From 92cbf531a9f0a4077f43a187f21418b1dd4df509 Mon Sep 17 00:00:00 2001 From: Shy Shalom Date: Fri, 18 Jan 2013 17:30:50 +0200 Subject: [PATCH] m --- build_release.py | 31 +- cycleblob.vcxproj | 2 + cycleblob.vcxproj.filters | 4 + page.html | 18 +- shaders.html | 106 ++++-- src/aiControl.js | 48 ++- src/background.js | 31 ++ src/build_number.js | 2 +- src/gameControl.js | 21 +- src/geomProcess.js | 29 +- src/loadManager.js | 33 -- src/main.js | 74 +++-- src/pack_footer.js | 5 +- src/player.js | 9 +- src/screens2d.js | 570 +++----------------------------- src/sfx.js | 3 +- src/shaders.js | 62 +++- src/userInput.js | 2 +- src/webgl-utils.js | 28 +- src/widgets2d.js | 662 ++++++++++++++++++++++++++++++++++++++ 20 files changed, 1065 insertions(+), 675 deletions(-) create mode 100644 src/background.js create mode 100644 src/widgets2d.js diff --git a/build_release.py b/build_release.py index d667b5e..9869903 100644 --- a/build_release.py +++ b/build_release.py @@ -3,6 +3,7 @@ from StringIO import StringIO import subprocess import tempfile +import time def incBuildNum(): with open('src/build_number.js', 'r') as f: @@ -38,6 +39,7 @@ def fileListStat(buf): 'src/aiControl.js', 'src/sfx.js', 'src/viewPoint.js', +'src/widgets2d.js', 'src/screens2d.js', 'src/build_number.js', 'src/gameControl.js', @@ -49,20 +51,35 @@ def fileListStat(buf): minjsout='../release/cycleblob.min.js' +def minWithUglify2(alljs): + with tempfile.TemporaryFile('w+') as tmp: + tmp.file.write(alljs) + tmp.file.flush() + p = subprocess.call(['node_modules\.bin\uglifyjs.cmd', tmp.name] + '-m -c -b beautify=false,max-line-len=600 -r "cb" -o'.split() + [minjsout] ) # --wrap cb + +def minWithClosure(alljs): + # NOT WORKING since it changes the names of fields from JSON + #subprocess.call(['java', '-jar', '../minify/closure/compiler.jar', '--js_output_file', minjsout, '--compilation_level', 'ADVANCED_OPTIMIZATIONS'] \ + # + sum((['--js',x] for x in jslist), [])) + + name = './tmp_%s.js' % time.time() + with open(name, 'w') as tmp: + tmp.write(alljs) + print 'tmp: ', name + subprocess.call(['java', '-jar', '../minify/closure/compiler.jar', '--third_party', '--js_output_file', minjsout, \ + '--compilation_level', 'ADVANCED_OPTIMIZATIONS', '--js', name, '--externs', '../minify/closure/jquery144_externs.js']) + + def main(): num = incBuildNum() print 'build number', num alljs = ''.join(open(name).read() for name in jslist) print 'before: %d lines, %d bytes' % fileListStat(alljs) - - with tempfile.TemporaryFile('w+') as tmp: - tmp.file.write(alljs) - tmp.file.flush() - p = subprocess.call(['node_modules\.bin\uglifyjs.cmd', tmp.name] + '-m -c -b beautify=false,max-line-len=600 -r "cb" -o'.split() + [minjsout] ) # --wrap cb - + minWithUglify2(alljs) + print 'after: %d lines, %d bytes' % fileStat(minjsout) if __name__ == '__main__': - main() \ No newline at end of file + main() diff --git a/cycleblob.vcxproj b/cycleblob.vcxproj index 99c5501..fb22a5b 100644 --- a/cycleblob.vcxproj +++ b/cycleblob.vcxproj @@ -61,6 +61,7 @@ + @@ -68,6 +69,7 @@ + diff --git a/cycleblob.vcxproj.filters b/cycleblob.vcxproj.filters index 06af7eb..8217e67 100644 --- a/cycleblob.vcxproj.filters +++ b/cycleblob.vcxproj.filters @@ -88,6 +88,10 @@ html + + + js + diff --git a/page.html b/page.html index f2c1a30..4597c0b 100644 --- a/page.html +++ b/page.html @@ -25,10 +25,12 @@ + + @@ -74,14 +76,18 @@ slideval3 = 0; acolor = Raphael.colorwheel($("#acolor"), 150); - acolor.onchange(function(c) { $("#acoltext").text(c.hex); if (acolor.onchange2) acolor.onchange2(); }); + acolor.onchange(function(c) { $("#acoltext").val(c.hex); if (acolor.onchange2) acolor.onchange2(); }); + $("#acoltext").change(function() { acolor.color($("#acoltext").val()); }) acolor.color("#Fff"); bcolor = Raphael.colorwheel($("#bcolor"), 150); - bcolor.onchange(function(c) { $("#bcoltext").text(c.hex); if (bcolor.onchange2) bcolor.onchange2(); }); + bcolor.onchange(function(c) { $("#bcoltext").val(c.hex); if (bcolor.onchange2) bcolor.onchange2(); }); + $("#bcoltext").change(function() { bcolor.color($("#bcoltext").val()); }) bcolor.color("#F00"); ccolor = Raphael.colorwheel($("#ccolor"), 150); - ccolor.onchange(function(c) { $("#ccoltext").text(c.hex); if (ccolor.onchange2) ccolor.onchange2(); }); + ccolor.onchange(function(c) { $("#ccoltext").val(c.hex); if (ccolor.onchange2) ccolor.onchange2(); }); + $("#ccoltext").change(function() { ccolor.color($("#ccoltext").val()); }) ccolor.color("#F00"); + // use with acolor.color().hex }); function writeModel(vtxBuf, normBuf, triBuf) { @@ -187,9 +193,9 @@

You have JavaScript disabled

- - - + + + diff --git a/shaders.html b/shaders.html index 61404c4..2b8a27d 100644 --- a/shaders.html +++ b/shaders.html @@ -1,13 +1,41 @@ + + + + + - + + \ No newline at end of file diff --git a/src/aiControl.js b/src/aiControl.js index 7a2281f..0d94f19 100644 --- a/src/aiControl.js +++ b/src/aiControl.js @@ -11,7 +11,7 @@ var AiLevels = [ // created in startLife function Ai(player, level) { - this.player = player; + this.player = player; // player object var ailevel = AiLevels[level]; this.stepsAhead = ailevel.stepsAhead; @@ -36,7 +36,9 @@ function isOccupied(point) { return (w !== undefined && w >= 0) // (occupied) can be equal to 0.. for player 0 } -Ai.prototype.turnToAvailableSide = function(nei) + + +Ai.prototype.turnToAvailableSide = function(nei, fwdBlocked) { this.occRight = isOccupied(nei.toRight); this.occLeft = isOccupied(nei.toLeft); @@ -45,7 +47,8 @@ Ai.prototype.turnToAvailableSide = function(nei) return; // we're screwed, nothing to do but die. if (!this.occRight && !this.occLeft) { // both are clear, choose one - + if (fwdBlocked && this.checkWallHeading(nei)) // returns true if made a decision + return; if (this.checkFarBlocks()) // returns true if made a decision return; if (randomChoise(0.5)) @@ -99,6 +102,41 @@ function countFree(vw, togo, went) { return went; } +function pieceIsPlayer(piece, playerId) { + return piece >= 100 && piece < 200 && (piece - 100 == playerId); +} + +Ai.prototype.checkWallHeading = function (nei) { + var thisPlayerId = this.player.id; + var fwdVal = world.map.get(nei.toFwd); + var fwdPiece = PieceMap.piece(fwdVal); + if (!pieceIsPlayer(fwdPiece, thisPlayerId)) { + return false; // only consider my wall + } + var fwdWc = PieceMap.meta(fwdVal); // wall-count + + var p = this.player.point, l = this.player.last.point; + this.look.init(p, l).goLeft(); + this.look.goRight(); + var leftPnt = this.look.point; + this.look.init(p, l).goRight(); + this.look.goLeft(); + var rightPnt = this.look.point; + + var leftVal = world.map.get(leftPnt), rightVal = world.map.get(rightPnt); + var leftPiece = PieceMap.piece(leftVal), rightPiece = PieceMap.piece(rightVal); + var leftWc = PieceMap.meta(leftVal), rightWc = PieceMap.meta(rightVal); + writeDebug("wall-h " + leftPiece + ":" + leftWc + " - " + rightPiece + ":" + rightWc); + if (!pieceIsPlayer(leftPiece, thisPlayerId) || !pieceIsPlayer(rightPiece, thisPlayerId)) + return false; + + if (leftWc < fwdWc) + this.turnLeft(); + else + this.turnRight(); + return true; +} + // advance several steps forward, right and left to see if there is something blocking Ai.prototype.checkFarBlocks = function() @@ -129,13 +167,13 @@ Ai.prototype.moveControl = function(world) var occFwd = isOccupied(nei.toFwd); if (occFwd) // the point up ahead is occupied { - this.turnToAvailableSide(nei); + this.turnToAvailableSide(nei, true); return; } // random turning for no reason (2% chance) if (randomChoise(2)) { - this.turnToAvailableSide(nei); + this.turnToAvailableSide(nei, false); return; } diff --git a/src/background.js b/src/background.js new file mode 100644 index 0000000..f0bce48 --- /dev/null +++ b/src/background.js @@ -0,0 +1,31 @@ + + +function Background(model, scale) { + this.model = model; + this.scale = scale; + this.time = 0; +} + +Background.prototype.draw = function () { + mv.pushMatrix(); + mv.scale(this.scale); + mv.rotate(this.time*4, [1, 1, 0]); + bkgProg.setTime(this.time); + renderModel(this.model); + + mv.popMatrix(); +} + +Background.prototype.advance = function (elapsed) { + var sec = elapsed / 1000.0 + this.time += sec; +} + + +function makeBackground(model) { + var vtx = [-5.28, -1.72, -2.78, 0.00, 0.00, -6.21, 0.00, -5.55, -2.78, 5.28, -1.72, -2.78, 3.26, -4.49, 2.78, 0.00, 0.00, 6.21, -3.26, -4.49, 2.78, 5.28, 1.72, 2.78, -5.28, 1.72, 2.78, -3.26, 4.49, -2.78, 3.26, 4.49, -2.78, 0.00, 5.55, 2.78]; + var triangles = [0, 1, 2, 2, 3, 4, 4, 5, 6, 7, 5, 4, 2, 1, 3, 7, 4, 3, 0, 8, 9, 2, 6, 0, 3, 1, 10, 5, 8, 6, 9, 1, 0, 1, 9, 10, 10, 9, 11, 8, 11, 9, 11, 7, 10, 4, 6, 2, 8, 0, 6, 7, 11, 5, 10, 7, 3, 5, 11, 8]; + + model.vertexBuffer = GLBuffer.Data(gl.ARRAY_BUFFER, new Float32Array(vtx), gl.STATIC_DRAW, 3); + model.triangles = GLBuffer.Data(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(triangles), gl.STATIC_DRAW, 1); +} \ No newline at end of file diff --git a/src/build_number.js b/src/build_number.js index ef2db0e..0f65c1e 100644 --- a/src/build_number.js +++ b/src/build_number.js @@ -1,2 +1,2 @@ // this file is created by the build script -var BUILD_NUMBER=153 \ No newline at end of file +var BUILD_NUMBER=166 \ No newline at end of file diff --git a/src/gameControl.js b/src/gameControl.js index eff7a2b..3cb5ef3 100644 --- a/src/gameControl.js +++ b/src/gameControl.js @@ -82,6 +82,7 @@ function startLife(lvlsel) { lives: new LifesRenderable(userPlayer) }; world.bonuses = []; + world.background = new Background(resources.background, world.model.bbox.size * 0.28); world.ready = true; enable3d(true) @@ -92,16 +93,16 @@ function startLife(lvlsel) { worldModels={ // cube: { file: "models/cube3.json", eyeDist:3.3 }, - cube: { file: "modelsz/cube5quads.jsonz", eyeDist:3.3 }, - triCorner: { file: "modelsz/triCorner4.jsonz", eyeDist: 7 }, - plus: { file: "modelsz/plus4q.jsonz", eyeDist: 7 }, - dblsofa: { file: "modelsz/dbl_sofa_soft_4q.jsonz", eyeDist: 3.3 }, - softsofa: { file: "modelsz/sofa4q_soft.jsonz", eyeDist: 3.54 }, // nice - dDiamond: { file: "modelsz/distortDiamond5q.jsonz", eyeDist: 4 }, // nice - torus: { file: "modelsz/torus_100_50s.jsonz", eyeDist: 3.66 }, // fun - tetra: { file: "modelsz/tetra1_4q.jsonz", eyeDist: 3.4 }, - mobius: { file: "modelsz/mobius_10r_3q.jsonz", eyeDist: 1.0 }, - rotDounut: { file: "models/rot_dounut2.json", eyeDist: 4 } + "cube": { file: "modelsz/cube5quads.jsonz", eyeDist:3.3 }, + "triCorner": { file: "modelsz/triCorner4.jsonz", eyeDist: 7 }, + "plus": { file: "modelsz/plus4q.jsonz", eyeDist: 7 }, + "dblsofa": { file: "modelsz/dbl_sofa_soft_4q.jsonz", eyeDist: 3.3 }, + "softsofa": { file: "modelsz/sofa4q_soft.jsonz", eyeDist: 3.54 }, // nice + "dDiamond": { file: "modelsz/distortDiamond5q.jsonz", eyeDist: 4 }, // nice + "torus": { file: "modelsz/torus_100_50s.jsonz", eyeDist: 3.66 }, // fun + "tetra": { file: "modelsz/tetra1_4q.jsonz", eyeDist: 3.4 }, + "mobius": { file: "modelsz/mobius_10r_3q.jsonz", eyeDist: 1.0 }, + "rotDounut": { file: "models/rot_dounut2.json", eyeDist: 4 } //sofa: { file: "modelsz/sofa4q.jsonz", eyeDist: 4 }, //triCornerOut: { file: "modelsz/triCornerOut4.jsonz", eyeDist: 6.95 }, // squashSofa: { file: "models/squashSofa5q.json", eyeDist: 2.78 }, // confusing, sickening diff --git a/src/geomProcess.js b/src/geomProcess.js index f6febb6..0af4321 100644 --- a/src/geomProcess.js +++ b/src/geomProcess.js @@ -154,7 +154,7 @@ function createGridMeshBuffers(model, async, ondone, onprogress) // put a vertex between every two neighbots var basei = baseStarting[i] = addedVtx; // ne - current neighbor. nene - next neighbor - var ne = model.nei[i].t[myNeiList[0]], nene; + var ne = model.nei[i].t[myNeiList[0]]; for (var c = 0; c < neiCount; ++c) { var nene = model.nei[i].t[ne]; // next neighbor @@ -281,18 +281,37 @@ function createGridMeshBuffers(model, async, ondone, onprogress) -function indexDist(model, a, b) -{ +function indexDist(model, a, b) { return vec3.distance(model.vtx[a], model.vtx[b]); } +vec3.minwith = function(a, b) { + if (b[0] < a[0]) a[0] = b[0]; + if (b[1] < a[1]) a[1] = b[1]; + if (b[2] < a[2]) a[2] = b[2]; +} +vec3.maxwith = function(a, b) { + if (b[0] > a[0]) a[0] = b[0]; + if (b[1] > a[1]) a[1] = b[1]; + if (b[2] > a[2]) a[2] = b[2]; +} +vec3.distance = function(a, b) { + return Math.sqrt((a[0]-b[0])*(a[0]-b[0]) + (a[1]-b[1])*(a[1]-b[1]) + (a[2]-b[2])*(a[2]-b[2])); +} + // read the data into the a proper mesh data and generate neighbor information function createMeshData(input, model) { model.vtx = []; + model.bbox = { min: vec3.create([99, 99, 99]), max: vec3.create([-99, -99, -99]) }; for (var i = 0; i < input.vertexPositions.length; i += 3) { - model.vtx.push(vec3.create([input.vertexPositions[i], input.vertexPositions[i + 1], input.vertexPositions[i + 2]])); + p = vec3.create([input.vertexPositions[i], input.vertexPositions[i + 1], input.vertexPositions[i + 2]]); + model.vtx.push(p); + vec3.minwith(model.bbox.min, p); + vec3.maxwith(model.bbox.max, p); } - writeDebug(model.vtx.length + " vertices in world"); + + model.bbox.size = vec3.distance(model.bbox.min, model.bbox.max); + writeDebug(model.vtx.length + " vertices in world bbox=" + model.bbox.size); model.normals = []; if (input.vertexNormals) { for (var i = 0; i < input.vertexNormals.length; i += 3) { diff --git a/src/loadManager.js b/src/loadManager.js index c5db06c..0e70b48 100644 --- a/src/loadManager.js +++ b/src/loadManager.js @@ -70,39 +70,6 @@ function processWorldModel(loadedName, async) { ); } -/* -function processWorldModel2(loadedName, async) { - updateProgress(loadedName, "processing"); - var rec = resources[loadedName]; - var model = {}; - - var _start = new Date().getTime(); - writeDebug("start " + loadedName); - - doWork( {func: "makeWorldSync", input:rec.input}, function(data) { - if (!(data.vertexBuffer instanceof Float32Array)) { // chrome bug doesn't preserve typed arrays - data.vertexBuffer = new Float32Array(data.vertexBuffer); - data.vNormalBuffer = new Float32Array(data.vNormalBuffer); - data.triangles = new Uint16Array(data.triangles); - } - - data.vertexBuffer = GLBuffer.Data(gl.ARRAY_BUFFER, data.vertexBuffer, gl.STATIC_DRAW, 3); - data.vNormalBuffer = GLBuffer.Data(gl.ARRAY_BUFFER, data.vNormalBuffer, gl.STATIC_DRAW, 3); - data.triangles = GLBuffer.Data(gl.ELEMENT_ARRAY_BUFFER, data.triangles, gl.STATIC_DRAW, 1); - - rec.model = data; - writeDebug("done " + loadedName + " " + (new Date().getTime() - _start)); - - updateProgress(loadedName, null); // may call workProgress.ondone which may lead to startLife - }, - workProgress.onprogress - ); - - -}*/ - -//processWorldModel = processWorldModel2; // process with worker thread. Chrome crashes due to copies of data - function deleteModel(name) { if (!resources[name] || !resources[name].model) diff --git a/src/main.js b/src/main.js index 0ee3920..91bb0d0 100644 --- a/src/main.js +++ b/src/main.js @@ -4,7 +4,7 @@ if (!writeDebug) {// did not include debug.js var clearDebug = function() {} } -function renderFaces(model, defaultColor) { +function renderFaces(model, defaultColor, prog) { if (model.triangles) { model.triangles.bind(); @@ -23,14 +23,14 @@ function renderFaces(model, defaultColor) { if (model.trianglesInline) { if (model.diffuseColor) - shaderProg.setColor(model.diffuseColor[0], model.diffuseColor[1], model.diffuseColor[2]); + prog.setColor(model.diffuseColor[0], model.diffuseColor[1], model.diffuseColor[2]); else if (defaultColor) - shaderProg.setColorv(defaultColor); + prog.setColorv(defaultColor); model.vertexBuffer.bind(); - gl.vertexAttribPointer(shaderProg.vertexPositionAttribute, model.vertexBuffer.itemSize, gl.FLOAT, false, 0, 0); + gl.vertexAttribPointer(prog.vertexPositionAttribute, model.vertexBuffer.itemSize, gl.FLOAT, false, 0, 0); model.vNormalBuffer.bind(); - gl.vertexAttribPointer(shaderProg.vertexNormalAttribute, model.vNormalBuffer.itemSize, gl.FLOAT, false, 0, 0); + gl.vertexAttribPointer(prog.vertexNormalAttribute, model.vNormalBuffer.itemSize, gl.FLOAT, false, 0, 0); gl.drawArrays(gl.TRIANGLES, 0, model.vertexBuffer.numItems); } @@ -38,24 +38,25 @@ function renderFaces(model, defaultColor) { } function renderModel(model, defaultColor) { + var prog = Program.current; if (model.vertexBuffer) { model.vertexBuffer.bind(); - gl.vertexAttribPointer(shaderProg.vertexPositionAttribute, model.vertexBuffer.itemSize, gl.FLOAT, false, 0, 0); + gl.vertexAttribPointer(prog.vertexPositionAttribute, model.vertexBuffer.itemSize, gl.FLOAT, false, 0, 0); } // model.vTexCoord.bind(); // gl.vertexAttribPointer(shaderProg.textureCoordAttribute, model.vTexCoord.itemSize, gl.FLOAT, false, 0, 0); - + if (model.vNormalBuffer) { model.vNormalBuffer.bind(); - gl.vertexAttribPointer(shaderProg.vertexNormalAttribute, model.vNormalBuffer.itemSize, gl.FLOAT, false, 0, 0); + gl.vertexAttribPointer(prog.vertexNormalAttribute, model.vNormalBuffer.itemSize, gl.FLOAT, false, 0, 0); } - - shaderProg.setMatrixUniforms(); - renderFaces(model); + prog.setMatrixUniforms(); + + renderFaces(model, undefined, prog); if (model.groups) { for(var gname in model.groups) { - renderFaces(model.groups[gname], defaultColor); + renderFaces(model.groups[gname], defaultColor, prog); } } } @@ -104,8 +105,8 @@ function setupLighting() { } } -function drawScene() { - +function drawScene() +{ gl.viewport(0, 0, gl.viewportWidth, gl.viewportHeight); gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); @@ -117,6 +118,8 @@ function drawScene() { setupLighting(); mv.loadIdentity(); + Program.use(shaderProg); + // objects that are static in the scene for(var ri in world.staticDraw) { @@ -132,6 +135,7 @@ function drawScene() { mv.multMatrix(userInput.rotationMatrix); } + shaderProg.setColor(1.0, 1.0, 1.0); shaderProg.setTwoSided(camera.twoSided); renderModel(world.model); @@ -213,7 +217,11 @@ function drawScene() { for(var bi in world.bonuses) { world.bonuses[bi].draw(); } - + + Program.use(bkgProg); + world.background.draw(); + + Program.use(shaderProg); // checkGLErrors("draw"); // huge performance hit apparently. } @@ -236,11 +244,12 @@ function movePlayer(player) removePlayer(player, collide); } } - + + ++player.stepCount; // update map after everything? - world.map.set(lastPoint, player.id + 100, 0); // put wall in the previous point + world.map.set(lastPoint, player.id + 100, player.stepCount); // put wall in the previous point if (collide === undefined) - world.map.set(player.point, player.id, 0); // put bike in the current point + world.map.set(player.point, player.id, player.stepCount); // put bike in the current point return { dist:dist, collide:collide }; } @@ -316,7 +325,8 @@ function animate(elapsed) { for(var bi in world.bonuses) { world.bonuses[bi].advance(elapsed); } - + + world.background.advance(elapsed); return doDraw; @@ -333,8 +343,6 @@ var dispFps = function() { sum = 0; count = 0; } - - } }(); @@ -468,7 +476,9 @@ PieceMap.prototype.unset = function (index) { var shaderProg = new Program(); +var bkgProg = new Program(); +// re-initialized in startLife() var world = { map: new PieceMap(), @@ -509,7 +519,10 @@ function containterResize(event, bforce) { var WIDTH_MULT = 20; // changing the width in multiples of this drawDiv = document.getElementById("canvas-container"); - var newWidth = Math.round(drawDiv.offsetWidth/WIDTH_MULT)*WIDTH_MULT; + // writeDebug("RESIZE " + drawDiv.offsetWidth + "," + drawDiv.offsetHeight + "|" + window.innerWidth + "," + window.innerHeight); + var wbyHeight = Math.round(window.innerHeight *0.94 / 0.7 / WIDTH_MULT) * WIDTH_MULT; + var wbyWidth = Math.round(window.innerWidth *0.94 / WIDTH_MULT) * WIDTH_MULT; + var newWidth = Math.min(wbyHeight, wbyWidth); if (newWidth === canvas.width && !bforce) return; @@ -526,8 +539,13 @@ function containterResize(event, bforce) { writeDebug("canvas resized: " + canvas.width + " x " + canvas.height); } +function hack() { + game.userLivesCount=10 +} function webGLStart() { + document.getElementById('shadersFrame').src = "shaders.html" + canvas = document.getElementById("game-canvas"); if (!initGL(canvas)) @@ -539,7 +557,13 @@ function webGLStart() { containterResize(null, true); c2d.showStartScreen(ctx2d); // sets up the screen and returns immediately - shaderProg.init($('#shadersFrame').contents().find('#phong-fs'), $('#shadersFrame').contents().find('#phong-vs')) + + shaderFrame = $('#shadersFrame').contents(); + shaderProg.init(shaderFrame.find('#phong-fs'), shaderFrame.find('#phong-vs')); + shaderProg.initNormParams(); + bkgProg.init(shaderFrame.find('#bkg-fs'), shaderFrame.find('#bkg-vs')); + bkgProg.initBkgParams(); + Program.use(shaderProg); window.onresize = containterResize; @@ -554,9 +578,11 @@ function webGLStart() { loadModel("models/bikePlayer2.json", "inlined", "bike", loadedResource); loadModel("models/lifeWheel.json", "indexed", "life", loadedResource); - resources.explode = { ring:{} }; makeExplosionGeom(resources.explode); + resources.background = {}; + makeBackground(resources.background); + initSounds(); // for(var i = 0; i < 100; ++i) diff --git a/src/pack_footer.js b/src/pack_footer.js index ef9519d..d098faf 100644 --- a/src/pack_footer.js +++ b/src/pack_footer.js @@ -1,2 +1,3 @@ -return { webGLStart: webGLStart}; -}()); \ No newline at end of file +return { webGLStart: webGLStart, hack=hack}; +}()); +window["webGLStart"] = cb.webGLStart \ No newline at end of file diff --git a/src/player.js b/src/player.js index 83afdc1..0580e46 100644 --- a/src/player.js +++ b/src/player.js @@ -159,6 +159,8 @@ var PlayerColors = [ ]; function Wall() { + // the queue of points is needed because the point the bike is on is not the point where we start to draw wall + // the wall is started POINT_DELAY steps after the bike this.queue = []; this.pntRecord = []; // a record of the indexes of the world points the wall passes on this.standing = true; @@ -190,7 +192,7 @@ function Player(id, inmodel, startPoint) { this.selDir = Directions.Up; // direction the user selects he wants to go next this.wall = new Wall(); - this.ai = null; // computer controlled or user controlled (inited in startLife + this.ai = null; // computer controlled or user controlled (inited in startLife) this.sfx = { explode:null, wall_decent:null }; // if not null, these is the instances of the ongoing special effects this.lastMadeMoves = 0; // how many moves I did in the last ai check @@ -205,8 +207,9 @@ function Player(id, inmodel, startPoint) { // the wall building uses this to interpolate between two points behind the bike. this.lastMvDist = 1; - - this.turnCallback = null; // if not null, called when a turn is made + + this.turnCallback = null; // if not null, called when a turn is made (for sound) + this.stepCount = 0; // how many steps we did. (for wall count used by AI) // needs to be last this.selDir.move.call(this); // align to surface (set the normal, right and up) diff --git a/src/screens2d.js b/src/screens2d.js index 1723f63..a483d96 100644 --- a/src/screens2d.js +++ b/src/screens2d.js @@ -1,511 +1,4 @@ -var $MR = Math.round; - -function Box(x, y, width, height) { - this.x = $MR(x); this.y = $MR(y); this.height = $MR(height); this.width = $MR(width); -} -Box.prototype.inside = function(coord) { - return (coord.x >= this.x && coord.y >= this.y && coord.x <= this.x+this.width && coord.y <= this.y+this.height); -} -Box.prototype.expand = function(px) { - this.x -= px; - this.y -= px; - this.height += 2*px; - this.width += 2*px; - return this; -} -// returns a new copy -Box.prototype.expanded = function(px) { - return new Box(this.x - px, this.y - px, this.width + 2*px, this.height + 2*px); -} -Box.prototype.down = function(px) { - this.y += px; - return this; -} -Box.prototype.xmid = function() { - return this.x + $MR(this.width/2); -} -Box.prototype.widen = function(px) { - this.x -= $MR(px); - this.width += $MR(2*px); - return this; -} - - -function callWidget(e, w, ename) { - var c = c2d.getCanvasCoord(e); - w.base.callback.call(w, (w.box?{ x:c.x-w.box.x, y:c.y-w.box.y, name:ename}:undefined) ); -} - -function menuMouseMove(e) { - - if (c2d.curPage.mouseCaptureWidget) { - callWidget(e, c2d.curPage.mouseCaptureWidget, Widget.EVENT_MOVE); - return; - } - var w = c2d.getWidget(e) - if (w !== null && w.base.index !== c2d.curPage.sel) { - - //var snd = $("#turnSound")[0]; - //snd.currentTime = 0; - //snd.play(); - - c2d.curPage.sel = w.base.index; - c2d.drawWidgets(); - } -} - -function menuMouseDown(e) { - // var coord = getCanvasCoord(e); - // writeDebug(coord.x + " " + coord.y); - var w = c2d.getWidget(e) - if (w !== null) { - callWidget(e, w, Widget.EVENT_PRESS); - } - else if (c2d.curPage.mouseHandler !== null) - c2d.curPage.mouseHandler(); -} - -function menuMouseUp(e) { - if (c2d.curPage.mouseCaptureWidget) { - callWidget(e, c2d.curPage.mouseCaptureWidget, Widget.EVENT_RELEASE); - c2d.curPage.mouseCaptureWidget = null; - } -} - - -function menuKeyDown(e) { - var ret; - if (c2d.curPage.widgets.length > 0) { - ret = false; - if (e.keyCode === KeyEvent.DOM_VK_DOWN || e.keyCode === KeyEvent.DOM_VK_RIGHT) - c2d.curPage.sel = (c2d.curPage.sel + 1) % c2d.curPage.widgets.length; - else if (e.keyCode === KeyEvent.DOM_VK_UP || e.keyCode === KeyEvent.DOM_VK_LEFT) - c2d.curPage.sel = (c2d.curPage.sel - 1 + c2d.curPage.widgets.length) % c2d.curPage.widgets.length; - else if (e.keyCode === KeyEvent.DOM_VK_RETURN || - e.keyCode === KeyEvent.DOM_VK_ENTER || - e.keyCode === KeyEvent.DOM_VK_SPACE) - { - var w = c2d.curPage.widgets[c2d.curPage.sel]; - w.base.callback.call(w); // engage a button - } - else - ret = true; // not processes - - if (ret === false) { - c2d.drawWidgets(); - return ret; - } - } - if (c2d.curPage.keyHandler !== null) { - // keyHandler return value has the same sematrics as this handler. - // it returns false if the key is consumed - return c2d.curPage.keyHandler(e.keyCode); - } - - return true; -} - -function menuKeyUp(e) {} - - -//////////////////////////////////////////////// screens and widgets ///////////////////////// - -// control 2d constructore -function C2d() { - this.curPage = null; - this.msgQueue = []; - this.curMenuDraw = null; - this.curMenuRemake = null; - this.texth = 42; // changes with resize - - this.has3dContent = false; - this.render3d = []; // 3d renderables - this.mainMenu = null; // points to the function which draw the menu from which we came. either the start menu or the custom level menu - - window.setInterval(function() { c2d.checkMessageQueue(); }, 200); -} - -C2d.prototype.setup2dInputs = function() -{ - // disable scrolling in the page using keyboard - document.onkeydown = menuKeyDown; - document.onkeyup = menuKeyUp; - - canvas2d.onmousedown = menuMouseDown; - canvas.onmousedown = menuMouseDown; - document.onmouseup = menuMouseUp; - document.onmousemove = menuMouseMove; - - userInput.handlersSet = userInput.HANDLERS_MENU; -} - - -C2d.prototype.getCanvasCoord = function(e) { - return { x:e.layerX, y:e.layerY }; // ignoring any borders and padding -} - - -C2d.prototype.getWidget = function(e) { - var coord = this.getCanvasCoord(e); - for(var i = 0; i < this.curPage.widgets.length; ++i) { - var widget = this.curPage.widgets[i]; - if (widget.box.inside(coord)) - return widget; - } - return null; -} - - -C2d.prototype.roundedBoxPath = function(x, y, w, h, r) { - ctx2d.beginPath(); - ctx2d.moveTo(x+r, y); - ctx2d.arcTo(x+w, y, x+w, y+r, r); - ctx2d.arcTo(x+w, y+h, x+w-r, y+h, r); - ctx2d.arcTo(x, y+h, x, y+h-r, r); - ctx2d.arcTo(x, y, x+r, y, r) -} - -C2d.prototype.backgroundRect = function(box) { - // clear it anyway becuase the color has alpha - // erase a bit more not to leave traces behind - ctx2d.clearRect(box.x, box.y, box.width, box.height); - if (this.widgetsBackground !== undefined) { - ctx2d.fillStyle = this.widgetsBackground; - ctx2d.fillRect(box.x, box.y, box.width, box.height); - } -} - - -C2d.prototype.drawSelect = function(box, isSelected) { - if (isSelected) { - var size = Math.max(box.width, box.height); // want 45 degrees - var grad = ctx2d.createLinearGradient(box.x, box.y, box.x+size/2, box.y+size/2); - grad.addColorStop(0, 'rgba(136,255,19,1.0)'); - grad.addColorStop(1, 'rgba(255,255,0,1.0)'); - ctx2d.fillStyle = grad; - - c2d.roundedBoxPath(box.x, box.y, box.width, box.height, 10); - - ctx2d.fillStyle = "black"; - ctx2d.fill(); // workround for chrome 9 transparency bug - ctx2d.fillStyle = grad; - ctx2d.fill(); - - } - else { - this.backgroundRect(box); - } -} - - -function Widget(callback, index) { - this.callback = callback; - this.index = index; -} - -Widget.EVENT_PRESS = 100; -Widget.EVENT_MOVE = 101; -Widget.EVENT_RELEASE = 102; - -/////////////////////////////////////// TextButton /////////////////////////////////////////////// - -function TextButton(text, box, w, groupItem) { - this.base = w; // base widget - this.text = text; - this.tx = box.x; - this.ty = box.y + box.height; - - this.box = box.expanded($MR(c2d.em/4)).down($MR(c2d.em/7)); - - this.group = groupItem; - if (this.group) - this.group.setBox(box.expanded($MR(c2d.em/8)).down($MR(c2d.em/7))); -} - -var MMENU_FILL = "#ff8464"; -var MMENU_STROKE = "#c90034"; - -TextButton.prototype.draw = function(isSelected) { - c2d.drawSelect(this.box, isSelected); - if (this.group) - this.group.testndraw(); - ctx2d.fillStyle = MMENU_FILL; // orange "#ff3c00" - var tx = (ctx2d.textAlign == "center")?(this.box.x + $MR(0.5*this.box.width)):this.tx; - - ctx2d.fillText(this.text, tx, this.ty); - ctx2d.lineWidth = 2; - ctx2d.strokeStyle = MMENU_STROKE; //"#500000" - ctx2d.strokeText(this.text, tx, this.ty); - -} - -/////////////////////////////////// ImgToggleButton - check box with two images ///////////////// - -function ImgToggleButton(imgOn, imgOff, text, initState, box, w) { - this.base = w; - this.imgOn = imgOn; - this.imgOff = imgOff; - this.text = text; - this.boxImg = box; - this.box = box.expanded($MR(c2d.em/4)); - this.isOn = initState; - this.toggleCallback = this.base.callback; - this.base.callback = function() { - this.isOn = !this.isOn; - this.toggleCallback(this.isOn); - this.draw(true); - } -} - -ImgToggleButton.prototype.draw = function(isSelected) { - c2d.drawSelect(this.box, isSelected); - - var img = (this.isOn)?this.imgOn:this.imgOff; - ctx2d.drawImage(img, this.boxImg.x, this.boxImg.y, this.boxImg.width, this.boxImg.height); -} - -///////////////////////////////////// ImgButton - button with a single image //////////////////// - -function ImgButton(img, text, box, w, groupItem) { - this.base = w; - this.img = img; - this.text = text; - this.boxImg = box; - this.box = box.expanded($MR(c2d.em/4)); - - this.group = groupItem; - if (this.group) - this.group.setBox(box.expanded($MR(c2d.em/8))); -} - -ImgButton.prototype.draw = function(isSelected) { - c2d.drawSelect(this.box, isSelected); - if (this.group) - this.group.testndraw(); - if (this.img === null) - return; - ctx2d.drawImage(this.img, this.boxImg.x, this.boxImg.y, this.boxImg.width, this.boxImg.height); -} - -//////////////////////////////////// Slider ///////////////////////////////////////////////// - -function Slider(vmin, vmax, step, value, box, w) { - this.base = w; w.box = box; - this.vmin = vmin; this.vmax = vmax; this.step = step; - this.value = value; - this.box = box; - this.valueChanged = w.callback; - this.base.callback = this.onevent; - this.clearBox = box.expanded(2).widen(c2d.en*0.5); - this.valueChanged(this.value); -} - -Slider.prototype.draw = function(isSelected) { - c2d.backgroundRect(this.clearBox); - - var wf = $MR(this.box.height*0.22); - c2d.roundedBoxPath(this.box.x, this.box.y+$MR((this.box.height-wf)*0.5), this.box.width, wf, $MR(wf*0.5)); - ctx2d.fillStyle = MMENU_FILL; - ctx2d.fill(); - ctx2d.strokeStyle = MMENU_STROKE; - ctx2d.lineWidth = 2; - ctx2d.stroke(); - - // x center of the selector - var selx = this.box.x + this.box.width / (this.vmax - this.vmin) * (this.value - this.vmin); - var selhw = $MR(c2d.en*0.35); - c2d.roundedBoxPath(selx-selhw, this.box.y, 2*selhw, this.box.height, $MR(selhw*0.4)); - ctx2d.fill(); - ctx2d.stroke(); - -} - - -Slider.prototype.onevent = function(e) { - var newvalue = this.vmin + e.x/this.box.width*(this.vmax - this.vmin) - newvalue = Math.min(this.vmax, Math.max(this.vmin, newvalue)); // clamp to min-max - newvalue = $MR(newvalue/this.step)*this.step; // clamp to steps - if (newvalue !== this.value) { - this.value = newvalue; - this.draw(true); - this.valueChanged(newvalue); - } - - if (e.name === Widget.EVENT_PRESS) - c2d.curPage.mouseCaptureWidget = this; -} - - -////////////////////////////////////////////////////////////////////////////////////////////////// - -C2d.prototype.blankScr = function(background) { - if (!background) - ctx2d.clearRect(0, 0, ctx2d.canvas.width, ctx2d.canvas.height); - else { - ctx2d.fillStyle = background; - ctx2d.fillRect(0, 0, ctx2d.canvas.width, ctx2d.canvas.height); - } -} - -function GroupCommon(selected) { - this.sel = selected; -} - -// common: an instance of GroupCommon -function GroupItem(common, id) { - this.id = id; - this.com = common; -} - -GroupItem.prototype.setBox = function(box) { - this.box = box -} - -GroupItem.prototype.testndraw = function() { - if (this.com.sel === this.id) { // it is selected - c2d.roundedBoxPath(this.box.x, this.box.y, this.box.width, this.box.height, 10); - ctx2d.lineWidth = 2; - ctx2d.fillStyle = "rgba(0,0,255,0.2)"; - ctx2d.fill(); - ctx2d.strokeStyle = "#0000FF"; - ctx2d.stroke(); - } -} - - - -C2d.prototype.clearScr = function() { - this.curPage = {}; - this.curPage.widgets = []; - this.curPage.sel = 0; // selected widget - this.curPage.background = undefined; - this.curPage.keyHandler = null; // keyboard actions specific to a page - this.curPage.mouseHandler = null; // mouse actions specific to a page, for clicks outside the widgets - this.curPage.selTextBox = null; // a box where the text of the current selection can appearl, - this.curPage.mouseCaptureWidget = null; // if one widget captures the mouse, it gets exclusive messages from it - - this.blankScr(); - this.curMenuDraw = null; - this.curMenuRemake = null; // the function to recreate the menu (after a resize); -} - - -C2d.prototype.setSelectionTextBox = function(box) { - var th = box.height; - this.curPage.selTextBox = box.expanded($MR(box.height/4)); // need to be bigger than the text due to the bottom of the 'g' - this.curPage.selTextBox.th = th; -} - -////////////////////////////// widgets creation shortcuts ///////////////////////////////////////////////////////// - -C2d.prototype.makeTextButton = function(text, x, y, height, width, callback, groupId) { - var m = ctx2d.measureText(text); - var r; - this.curPage.widgets.push( - r = new TextButton(text, - new Box(x, y, width, height), - new Widget(callback, this.curPage.widgets.length), - groupId - ) - ); - return r; -} - -C2d.prototype.makeImgToggleButton = function(imgOn, imgOff, text, initState, x, y, height, width, callback) { - var r; - this.curPage.widgets.push( - r = new ImgToggleButton(imgOn, imgOff, text, initState, - new Box(x, y, width, height), - new Widget(callback, this.curPage.widgets.length) - ) - ); - return r; - -} - -// groupId is an object with sel: index of currently selected item, id: this widget's id -C2d.prototype.makeImgButton = function(img, text, x, y, height, width, callback, groupId) { - var r; - this.curPage.widgets.push( - r = new ImgButton(img, text, new Box(x, y, width, height), - new Widget(callback, this.curPage.widgets.length), - groupId) - ); - return r; -} - -C2d.prototype.makeSlider = function(vmin, vmax, step, value, x, y, width, height, callback) { - var r; - return this.curPage.widgets.push( - r = new Slider(vmin, vmax, step, value, new Box(x, y, width, height), - new Widget(callback, this.curPage.widgets.length))); - return r; -} - - - -C2d.prototype.drawWidgets = function() { - if (this.curPage.widgets.length === 0) - return; - - for(var i = 0; i < this.curPage.widgets.length; ++i) { - var w = this.curPage.widgets[i]; - w.draw(i === this.curPage.sel); - } - - var text = this.curPage.widgets[this.curPage.sel].text; - if (this.curPage.selTextBox && text) { - this.backgroundRect(this.curPage.selTextBox); - - ctx2d.fillStyle = "#ff3c00"; - ctx2d.textAlign = "center" - // $MR(this.texth / 2) - this.setMenuFont(this.curPage.selTextBox.th); - ctx2d.fillText(text, this.curPage.selTextBox.xmid(), this.curPage.selTextBox.y + this.curPage.selTextBox.th); - ctx2d.textAlign = "start" - } -} - -//const MENU_TEXTH = 42; -//var INMENU_BACKGROUND = "rgba(0, 0, 128, 0.7)"; -//var INMENU_STROKE = "rgba(0, 0, 255, 0.7)" - -var INMENU_BACKGROUND = "rgba(0, 0, 0, 0.8)"; -var INMENU_STROKE = "rgba(128, 128, 128, 0.7)" - - -// background - the color of unselected menu items -C2d.prototype.preMenu = function(background) { - this.setup2dInputs(); - this.clearScr(); - this.widgetsBackground = background; - - var caller = arguments.callee.caller; - var args = caller.arguments; - this.curMenuRemake = function() { caller.apply(this, args) }; -} - -C2d.prototype.setMenuFont = function(th) { - if (!th) th = this.texth; - ctx2d.font = "bold " + $MR(th) + "px sans-serif" -} - - -C2d.prototype.resizeAdjust = function(w, h) { - this.texth = $MR(42*(w/900)); - this.setMenuFont(); - this.em = ctx2d.measureText("m").width; - this.en = ctx2d.measureText("n").width; - writeDebug("text height: " + this.texth + " em: " + this.em + " " + this.en); - - this.drawGameState(true); // don't draw the menus again - if (this.curMenuRemake) - this.curMenuRemake(); -} - - -//************************************************ actual screens ********************************************************** C2d.prototype.showStartScreen = function() @@ -521,7 +14,7 @@ C2d.prototype.showStartScreen = function() var textWidth = 8*em; - var newGameBot = this.makeTextButton("New game", 20, ch - 6*th, th, textWidth, function() { + var newGameBot = this.wnd.makeTextButton("New game", 20, ch - 6*th, th, textWidth, function() { writeDebug("NewNew!") c2d.clearScr(); c2d.mainMenu = C2d.prototype.showStartScreen; // and not the custom screen @@ -529,14 +22,14 @@ C2d.prototype.showStartScreen = function() startGame(); // calls startLife }); }); - this.makeTextButton("How to play", 20, ch - 4.3*th, th, textWidth, function() { + this.wnd.makeTextButton("How to play", 20, ch - 4.3*th, th, textWidth, function() { c2d.instructionsScreen() }); - this.makeTextButton("Custom level", 20, ch - 2.6*th, th, textWidth, function() { + this.wnd.makeTextButton("Custom level", 20, ch - 2.6*th, th, textWidth, function() { c2d.customLevelScreen(); }); - this.makeImgToggleButton($("#soundOnImg")[0], $("#soundOffImg")[0], "Sound", game.soundEnabled, cw-50-2*em, ch-50-2*em, + this.wnd.makeImgToggleButton($("#soundOnImg")[0], $("#soundOffImg")[0], "Sound", game.soundEnabled, cw-50-2*em, ch-50-2*em, 2.5*em, 2.5*em, function(isOn) { writeDebug("SetSnd " + isOn); game.enableSound(isOn); @@ -617,16 +110,16 @@ C2d.prototype.levelComplete = function(compLvlNum, compLvl) var cx = $MR(ctx2d.canvas.width / 2), cy = $MR(ctx2d.canvas.height / 2); var en = this.en, th = this.texth, hth = $MR(th/2); - this.makeImgButton($("#againImg")[0], "This one again", cx-7*en, cy, 4*en, 4*en, function() { + this.wnd.makeImgButton($("#againImg")[0], "This one again", cx-7*en, cy, 4*en, 4*en, function() { c2d.clearScr(); startLife(compLvl); // level is loaded becaue we just played this level }); - this.makeImgButton($("#menuImg")[0], "Exit game", cx-2*en, cy, 4*en, 4*en, function() { + this.wnd.makeImgButton($("#menuImg")[0], "Exit game", cx-2*en, cy, 4*en, 4*en, function() { c2d.showStartScreen(); }); - var nextBot = this.makeImgButton($("#nextImg")[0], "Next level", cx+3*en, cy, 4*en, 4*en, function() { + var nextBot = this.wnd.makeImgButton($("#nextImg")[0], "Next level", cx+3*en, cy, 4*en, 4*en, function() { c2d.clearScr(); if (compLvl === levels.length - 1) {// last level this.showStartScreen(); @@ -671,13 +164,13 @@ C2d.prototype.lifeEndScreen = function(inLvl, inLvlNum) var cx = $MR(ctx2d.canvas.width / 2), cy = $MR(ctx2d.canvas.height / 2); var th = this.texth, en = this.en; - var againBot = this.makeImgButton($("#againImg")[0], "Try again", cx-5*en, cy, 4*en, 4*en, function() { + var againBot = this.wnd.makeImgButton($("#againImg")[0], "Try again", cx-5*en, cy, 4*en, 4*en, function() { c2d.clearScr(); if (inLvlNum !== -1) inLvl = inLvlNum; startLife(inLvl); // level is loaded becaue we just played this level }); - this.makeImgButton($("#menuImg")[0], "Exit Game", cx+1*en, cy, 4*en, 4*en, function() { + this.wnd.makeImgButton($("#menuImg")[0], "Exit Game", cx+1*en, cy, 4*en, 4*en, function() { c2d.mainMenu(); }); @@ -706,7 +199,7 @@ C2d.prototype.gameOverScreen = function(inLvl, inLvlNum) var cx = $MR(ctx2d.canvas.width / 2), cy = $MR(ctx2d.canvas.height / 2); var th = this.texth, en = this.en; - var menuBot = this.makeImgButton($("#menuImg")[0], "Back to menu", cx-2*en, cy, 4*en, 4*en, function() { + var menuBot = this.wnd.makeImgButton($("#menuImg")[0], "Back to menu", cx-2*en, cy, 4*en, 4*en, function() { c2d.mainMenu(); }); @@ -743,14 +236,14 @@ C2d.prototype.verbosePauseScreen = function() game.setPaused(false); } - this.makeImgButton($("#resumeImg")[0], "Resume", cx-7*en, cy, 4*en, 4*en, function() { + this.wnd.makeImgButton($("#resumeImg")[0], "Resume", cx-7*en, cy, 4*en, 4*en, function() { resume(); }); - this.makeImgButton($("#menuImg")[0], "End game", cx-2*en, cy, 4*en, 4*en, function() { + this.wnd.makeImgButton($("#menuImg")[0], "End game", cx-2*en, cy, 4*en, 4*en, function() { game.isDemo = false; c2d.mainMenu(); }); - this.makeImgToggleButton($("#soundOnImg")[0], $("#soundOffImg")[0], "Sound", game.soundEnabled, cx+3*en, cy, 4*en, 4*en, function(isOn) { + this.wnd.makeImgToggleButton($("#soundOnImg")[0], $("#soundOffImg")[0], "Sound", game.soundEnabled, cx+3*en, cy, 4*en, 4*en, function(isOn) { writeDebug("SetSnd " + isOn); game.enableSound(isOn); }); @@ -847,11 +340,15 @@ C2d.prototype.customLevelScreen = function() var cw = ctx2d.canvas.width, ch = ctx2d.canvas.height; var cx = $MR(cw / 2), cy = $MR(ch / 2), th = this.texth, em = this.em, en = this.en; - var iis = $MR(ch/4.2); - var iiw = $MR(iis*0.8); + var iis = $MR(ch/4.2); // image space + var iiw = $MR(iis*0.8); // image width (and height) + var isp = $MR(c2d.em/4) // image outer space var scrSel = customSelect; + var modelsCont = this.wnd.makeContainer($MR(em-isp), $MR(0.08*ch), $MR(iis*4.8+ 2*isp), $MR(0.48*ch)); + modelsCont.translateY = 0; + for(var i = 0 ; i < levels.length; ++i) { var img = null; if (levels[i].icon !== null) { @@ -859,7 +356,7 @@ C2d.prototype.customLevelScreen = function() img.src = levels[i].icon; img.onload = function() { c2d.drawWidgets(); } } - this.makeImgButton(img, "", em+iis*(i%5), th*1.2+iis*Math.floor(i/5), iiw, iiw, function(value) { return function() { + modelsCont.makeImgButton(img, "", iis*(i%5)+isp, iis*Math.floor(i/5)+isp, iiw, iiw, function(value) { return function() { // scrSel = { iconSel:index, numEnemySel: levels[index].numPlayers, aiSel: levels[index].ai }; scrSel.worldSel.sel = value; c2d.drawWidgets(); @@ -871,37 +368,37 @@ C2d.prototype.customLevelScreen = function() ctx2d.fillStyle = "#ff3c00" c2d.setMenuFont(th*0.7); ctx2d.fillText("Select World:", en, $MR(th*0.7)); - var y2 = $MR(0.56*ch); + var y2 = $MR(0.68*ch); ctx2d.fillText("Number of Players:", en, y2); - var y3 = $MR(0.74*ch); + var y3 = $MR(0.81*ch); ctx2d.fillText("Difficulty:", en, y3); - var y4 = $MR(0.89*ch); + var y4 = $MR(0.94*ch); ctx2d.fillText("Speed:", en, y4); c2d.setMenuFont(th); ctx2d.textAlign = "center"; for(var i = 1; i <= 6; ++i) { - this.makeTextButton(i, i*em*2, y2+0.3*th, th, en, function(value) { return function() { + this.wnd.makeTextButton(i, 11*en + i*em*1.5, y2-0.9*th, th, en, function(value) { return function() { scrSel.numPlayersSel.sel = value; c2d.drawWidgets(); }}(i), new GroupItem(scrSel.numPlayersSel, i)); } var aidiff = [ {txt:"easy", d:1}, {txt:"medium", d:3}, {txt:"hard", d:5}]; - var sx = 2*em; + var sx = 7*en; for(var i = 0; i < aidiff.length; ++i) { var df = aidiff[i]; var ln = en*(df.txt.length+1); - this.makeTextButton(df.txt, sx, y3+0.3*th, th, ln, function(value) { return function() { + this.wnd.makeTextButton(df.txt, sx, y3-0.9*th, th, ln, function(value) { return function() { scrSel.aiSel.sel = value; c2d.drawWidgets(); }}(i), new GroupItem(scrSel.aiSel, i) ); sx += ln+en; } - var percentBox = new Box(cw*0.64, 0.9*ch, 4.5*en, th); - var slider = this.makeSlider(50, 300, 5, customSelect.speedSel, 2*em, 0.9*ch, cw*0.5, th*1.3, function(v) { + var percentBox = new Box(cw*0.69, 0.88*ch, 4.5*en, th); + var slider = this.wnd.makeSlider(50, 300, 5, customSelect.speedSel, 6*en, 0.89*ch, cw*0.5, th*1.1, function(v) { //writeDebug(v); c2d.backgroundRect(percentBox); ctx2d.fillStyle = "#ff3c00" @@ -910,13 +407,18 @@ C2d.prototype.customLevelScreen = function() ctx2d.textAlign = "center" customSelect.speedSel = v; }); - + + var scroll = this.wnd.makeScroll(400, 200, 0, modelsCont.drawScroll.x, modelsCont.drawScroll.y, 30, modelsCont.drawScroll.height, function(v) { + modelsCont.translateY = v; + c2d.drawWidgets(); + }); + c2d.curPage.wheelHandlers = [ {box:modelsCont.box, handler: function(e) { scroll.onWheelEvent(e) } } ]; - this.makeImgButton($("#menuImg")[0], "Exit game", cw-5*en, ch-10*en, 4*en, 4*en, function() { + this.wnd.makeImgButton($("#menuImg")[0], "Exit game", cw-5*en, ch-10*en, 4*en, 4*en, function() { c2d.showStartScreen(); }); - this.makeImgButton($("#nextImg")[0], "Next level", cw-5*en, ch-5*en, 4*en, 4*en, function() { + this.wnd.makeImgButton($("#nextImg")[0], "Next level", cw-5*en, ch-5*en, 4*en, 4*en, function() { c2d.clearScr(); worldLvl = scrSel.worldSel.sel; diff --git a/src/sfx.js b/src/sfx.js index 006b1e9..108aa42 100644 --- a/src/sfx.js +++ b/src/sfx.js @@ -181,7 +181,7 @@ function LifeBonus(index) { this.index = index; this.occupy = nei; for(var ni in this.occupy) - world.map.set(this.occupy[ni], 1000 + index) + world.map.set(this.occupy[ni], 1000 + index, 0) this.normal = world.model.normals[this.point]; this.forward = vec3.normalize(vec3.nsubtract(world.model.vtx[this.point], world.model.vtx[nei[1]])); // an estimate, nor really perpendicular @@ -200,6 +200,7 @@ LifeBonus.prototype.getColor = function(angle) { return hslToRgb(angle/360, 1, 0.5); } + LifeBonus.prototype.draw = function() { mv.pushMatrix(); diff --git a/src/shaders.js b/src/shaders.js index b12c1b0..5e82716 100644 --- a/src/shaders.js +++ b/src/shaders.js @@ -31,7 +31,7 @@ function getShader(gl, elem) { gl.compileShader(shader); if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) { - alert(gl.getShaderInfoLog(shader)); + alert(gl.getShaderInfoLog(shader) + "\n" + innerElem.id); return null; } @@ -43,7 +43,7 @@ function Program() { } -Program.prototype.init = function(fragElem, vtxElem) { +Program.prototype.init = function (fragElem, vtxElem) { var fragmentShader = getShader(gl, fragElem); var vertexShader = getShader(gl, vtxElem); @@ -56,14 +56,43 @@ Program.prototype.init = function(fragElem, vtxElem) { alert("Could not initialise shaders"); return null; } +} + +Program.prototype.enableArrs = function (en) { + if (en) { + gl.enableVertexAttribArray(this.vertexPositionAttribute); + if (this.vertexNormalAttribute !== undefined) + gl.enableVertexAttribArray(this.vertexNormalAttribute); + } + else { + gl.disableVertexAttribArray(this.vertexPositionAttribute); + if (this.vertexNormalAttribute !== undefined) + gl.disableVertexAttribArray(this.vertexNormalAttribute); + } +} + +Program.prototype.initBkgParams = function () { + gl.useProgram(this.prog); + this.vertexPositionAttribute = gl.getAttribLocation(this.prog, "aVertexPosition"); + //gl.enableVertexAttribArray(this.vertexPositionAttribute); + + this.pMatrixUniform = gl.getUniformLocation(this.prog, "uPMatrix"); + this.mvMatrixUniform = gl.getUniformLocation(this.prog, "uMVMatrix"); + this.timeUniform = gl.getUniformLocation(this.prog, "time"); + + //writeDebug(this.pMatrixUniform + "," + this.mvMatrixUniform + "," + this.vertexPositionAttribute); +} + +// parameters for the normal shader used for most of the scene except the background +Program.prototype.initNormParams = function() { gl.useProgram(this.prog); this.vertexPositionAttribute = gl.getAttribLocation(this.prog, "aVertexPosition"); - gl.enableVertexAttribArray(this.vertexPositionAttribute); + //gl.enableVertexAttribArray(this.vertexPositionAttribute); this.vertexNormalAttribute = gl.getAttribLocation(this.prog, "aVertexNormal"); - gl.enableVertexAttribArray(this.vertexNormalAttribute); + //gl.enableVertexAttribArray(this.vertexNormalAttribute); // this.textureCoordAttribute = gl.getAttribLocation(this.prog, "aTextureCoord"); // gl.enableVertexAttribArray(this.textureCoordAttribute); @@ -84,6 +113,27 @@ Program.prototype.init = function(fragElem, vtxElem) { this.globColorUniform = gl.getUniformLocation(this.prog, "uGlobColor"); this.twoSidedUniform = gl.getUniformLocation(this.prog, "uTwoSided"); + //writeDebug(this.pMatrixUniform + "," + this.mvMatrixUniform + "," + this.vertexPositionAttribute); +} + + +Program.current = null + +Program.use = function (prog) { + if (Program.current === prog) + return; + if (Program.current !== null) + Program.current.enableArrs(false) + if (prog === null || prog === undefined) { + gl.useProgram(null); + Program.current = null; + } + else { + gl.useProgram(prog.prog); + Program.current = prog; + if (Program.current !== null) + Program.current.enableArrs(true) + } } @@ -98,6 +148,7 @@ Program.prototype.setMatrixUniforms = function() { mat4.transpose(normMat); gl.uniformMatrix4fv(this.nMatrixUniform, false, normMat);*/ + } Program.prototype.setColor = function(r, g, b) { @@ -133,3 +184,6 @@ Program.prototype.enableNormals = function(b) { } +Program.prototype.setTime = function (v) { + gl.uniform1f(this.timeUniform, v); +} diff --git a/src/userInput.js b/src/userInput.js index 87ec34e..2725100 100644 --- a/src/userInput.js +++ b/src/userInput.js @@ -184,7 +184,7 @@ function handleKeyDown(event) { if (gameConf.debug) { if (event.keyCode === KeyEvent.DOM_VK_E) { - startExplosion(userPlayer); + startExplosion(userPlayer, 1); } else if (event.keyCode === KeyEvent.DOM_VK_U) { ++game.userLivesCount; diff --git a/src/webgl-utils.js b/src/webgl-utils.js index 3751b6c..f676dfb 100644 --- a/src/webgl-utils.js +++ b/src/webgl-utils.js @@ -109,18 +109,18 @@ var VIDEO_EMBED = '
a: b: c:
a: b: c: