Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Camera! #28

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
29 changes: 17 additions & 12 deletions chesterGL/block.js
Expand Up @@ -106,7 +106,8 @@ chesterGL.Block.TYPE = {
'SCENE': 2,
'TMXBLOCK': 3,
'PARTICLE': 4,
'PRIMITIVE': 5
'PRIMITIVE': 5,
'CAMERA': 6
};

/**
Expand Down Expand Up @@ -484,6 +485,18 @@ chesterGL.Block.prototype.removeChild = function (block) {
}
};

chesterGL.Block.prototype.updateTransform = function () {
this.mvMatrix = /** @type {Float32Array} */(goog.vec.Mat4.makeIdentity(this.mvMatrix));
goog.vec.Mat4.translate(this.mvMatrix, this.position[0], this.position[1], this.position[2]);
goog.vec.Mat4.rotate(this.mvMatrix, this.rotation * -1, 0, 0, 1);
goog.vec.Mat4.scale(this.mvMatrix, this.scale, this.scale, 1);
// concat with parent's transform
var ptransform = (this.parent ? this.parent.mvMatrix : null);
if (ptransform) {
goog.vec.Mat4.multMat(ptransform, this.mvMatrix, this.mvMatrix);
}
}

/**
* actually performs the transformation
* @ignore
Expand All @@ -492,19 +505,11 @@ chesterGL.Block.prototype.transform = function () {
var gl = chesterGL.gl;
var transformDirty = (this.isTransformDirty || (this.parent && this.parent.isTransformDirty));
if (transformDirty) {
this.mvMatrix = /** @type {Float32Array} */(goog.vec.Mat4.makeIdentity(this.mvMatrix));
goog.vec.Mat4.translate(this.mvMatrix, this.position[0], this.position[1], this.position[2]);
goog.vec.Mat4.rotate(this.mvMatrix, this.rotation * -1, 0, 0, 1);
goog.vec.Mat4.scale(this.mvMatrix, this.scale, this.scale, 1);
// concat with parent's transform
var ptransform = (this.parent ? this.parent.mvMatrix : null);
if (ptransform) {
goog.vec.Mat4.multMat(ptransform, this.mvMatrix, this.mvMatrix);
}
this.updateTransform();
}

// bail out if we're a block group or a primitive block
if (this.type == chesterGL.Block.TYPE['BLOCKGROUP'] || this.type == chesterGL.Block.TYPE['PRIMITIVE']) {
// bail out if we're a block group or a primitive block, or a camera
if (this.type == chesterGL.Block.TYPE['BLOCKGROUP'] || this.type == chesterGL.Block.TYPE['PRIMITIVE'] || this.type == chesterGL.Block.TYPE['CAMERA']) {
return;
}

Expand Down
46 changes: 46 additions & 0 deletions chesterGL/core.js
Expand Up @@ -810,6 +810,8 @@ chesterGL.setupPerspective = function () {
} else {
throw "Invalid projection: " + chesterGL.projection;
}

chesterGL.basePMatrix = chesterGL.pMatrix;
};

/**
Expand All @@ -822,11 +824,54 @@ chesterGL.setRunningScene = function (block) {
}
};

/**
* Sets the current camera. The scene will be rendered as if seen from a camera attached to the block.
* @param {chesterGL.Block} A Block of type Camera, created thusly: new chesterGL.Block(null, chesterGL.Block.TYPE.CAMERA)
*/
chesterGL.setCamera = function(block) {
if (block.type == chesterGL.Block.TYPE['CAMERA']) {
chesterGL.camera = block;
}
}

/**
* main draw function, will call the root block
* @ignore
*/
chesterGL.drawScene = function () {
//Setup camera transformation
var par = chesterGL.camera;
var parents = [];
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with you that this is somewhat inefficient, also creating new elements on every frame is not so good for GC.
One way we could avoid this (calculation of the camera transform) is with lazy evaluation... not sure how to achieve this yet, but seems like a good idea

// Work up the camera's chain of parents. This is somewhat inefficient, as they'll also get
// transformed as part of rendering the scene, but it's worth having the ability to just
// attach a camera to some block and have it follow the block, etc.
while(par) {
parents.push(par);
par = par.parent;
}

// We go backwards so that we start at the root and finish with the camera.
for(var i=parents.length-1; i >= 0; i--) {
parents[i].updateTransform();
}

// Invert and multiply onto the view transform.
// this looks a little wonky when using a camera that is a child of a normal block
// because we end up using the previous frame's transform for that block.
// TODO: refactor Block.visit into separate update and transform steps so we can
// use the current frame's transform here. This would also let us have multiple
// cameras each with their own viewport in the main port, picture in picture style.
chesterGL.pMatrix = goog.vec.Mat4.createFloat32();
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here. If you're doing this every frame, ideally you want to have a temp vector/matrix around just to reuse it and avoid creation every frame, that's more friendly with GC

var camTransform = goog.vec.Mat4.createFloat32();
if(goog.vec.Mat4.invert(chesterGL.camera.mvMatrix, camTransform)) {
goog.vec.Mat4.multMat(chesterGL.basePMatrix, camTransform, chesterGL.pMatrix);
}
else {
if(console) console.log("Inverse of camera transform is undefined!");
}

chesterGL.runningScene.isTransformDirty = true;

var gl = undefined;
if (chesterGL.webglMode) {
gl = chesterGL.gl;
Expand Down Expand Up @@ -1103,3 +1148,4 @@ goog.exportSymbol('chesterGL.togglePause', chesterGL.togglePause);
goog.exportSymbol('chesterGL.isPaused', chesterGL.isPaused);
goog.exportSymbol('chesterGL.addMouseHandler', chesterGL.addMouseHandler);
goog.exportSymbol('chesterGL.removeMouseHandler', chesterGL.removeMouseHandler);
goog.exportSymbol('chesterGL.setCamera', chesterGL.setCamera);
108 changes: 108 additions & 0 deletions html/test_camera.html
@@ -0,0 +1,108 @@
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" type="text/css" href="test.css"/>
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.5.2/jquery.min.js"></script>
<!-- <script type="text/javascript" src="externals/webgl-debug.js"></script> -->
<script type="text/javascript" src="chester.js"></script>
<!-- audio!! -->
<script type="text/javascript">

$(document).ready(function () {
setupGame();
function setupGame() {
chesterGL.settings['useGoogleAnalytics'] = true;
chesterGL.setup("demo-canvas");
var size = chesterGL.viewportSize();
var oneDeg = Math.PI / 180.0;

chesterGL.loadAsset("texture", "images/test.png");
chesterGL.loadAsset("texture", "images/star.png");
chesterGL.assetsLoaded("texture", function () {
// $("#loading").html("Test Single Block");
// finish with the setup and run the game
chesterGL.setupPerspective();

var sceneBlock = new chesterGL.Block(null, chesterGL.Block.TYPE['SCENE']);
sceneBlock.title = "Test::Single Block";
chesterGL.setRunningScene(sceneBlock);

// create a block
var someBlock = new chesterGL.Block();
someBlock.setTexture("images/test.png")
// someBlock.rotateBy(-45);
someBlock.setPosition([size.width/2, size.height/2, 0]);

var someBlock2 = new chesterGL.Block();
someBlock2.setTexture("images/star.png");
someBlock2.setPosition([60, 0, 0]);
someBlock.addChild(someBlock2);

sceneBlock.addChild(someBlock);


var someBlock3 = new chesterGL.Block();
someBlock3.setTexture("images/star.png");
someBlock3.setPosition([30, 60, 0]);

// === CAMERA EXAMPLE ===
// create a camera:
var camera = new chesterGL.Block(null, chesterGL.Block.TYPE.CAMERA);
// Misfeature: the camera's position is actually the location of the lower-left
// corner of the viewport. So, if you want the camera's parent in the center,
// you have to set the offset yourself. This should be fixed in a later update.
camera.setPosition([-200, -200, 220]);

// attach the camera to some block:
someBlock3.addChild(camera);

sceneBlock.addChild(someBlock3);

// VERY IMPORTANT: actually set the camera.
chesterGL.setCamera(camera);
// === END CAMERA CODE ===

// add some action
var bouncyFn = function () {
if(typeof this.dz === "undefined") this.dz = 10;
//this.setRotation(this.rotation + oneDeg);
this.setPosition([this.position[0], this.position[1], this.position[2] + this.dz]);
if (this.position[2] >= 200) { this.dz = -this.dz; }
if (this.position[2] <= -200) { this.dz = -this.dz; }
}

someBlock.setUpdate(bouncyFn);
someBlock2.setUpdate(bouncyFn);
someBlock3.setUpdate(function () {
this.setRotation(this.rotation - oneDeg/10);
});

chesterGL.run();
// draw a single frame (for debug purposes)
// chesterGL.drawScene();
});
} // setupGame()
});
</script>
<script type="text/javascript">
var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-77863-9']);
_gaq.push(['_trackPageview']);

(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();
</script>
</head>
<body>
<div id="loading" style="position: absolute; z-index: 100;"></div>
<div id="game-container">
<canvas id="demo-canvas" width="640" height="480"></canvas>
<div>
<span id="debug-info">00</span> ms per frame
</div>
</div>
</body>
</html>