rename ObsoleteDemos back to Demos
fix some relative path issues for loading assets
This commit is contained in:
22
Demos/NativeClient/bin_html/bind.js
Normal file
22
Demos/NativeClient/bin_html/bind.js
Normal file
@@ -0,0 +1,22 @@
|
||||
// Copyright (c) 2011 The Native Client Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
/**
|
||||
* @fileoverview This class implements an extension to Function object that
|
||||
* lets you bind a scope for |this| to a function.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Bind a scope to a function. Used to bind an object to |this| for event
|
||||
* handlers.
|
||||
* @param {!Object} scope The scope in which the function executes. |scope|
|
||||
* becomes |this| during function execution.
|
||||
* @return {function} the bound version of the original function.
|
||||
*/
|
||||
Function.prototype.bind = function(scope) {
|
||||
var boundContext = this;
|
||||
return function() {
|
||||
return boundContext.apply(scope, arguments);
|
||||
}
|
||||
}
|
||||
134
Demos/NativeClient/bin_html/dragger.js
Normal file
134
Demos/NativeClient/bin_html/dragger.js
Normal file
@@ -0,0 +1,134 @@
|
||||
// Copyright (c) 2011 The Native Client Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
/**
|
||||
* @fileoverview This class implements a mouse-drag event. It registers for
|
||||
* mousedown events, and when it sees one, starts capturing mousemove events
|
||||
* until it gets a mousup event. It manufactures three drag events: the
|
||||
* DRAG_START, DRAG and DRAG_END.
|
||||
*/
|
||||
|
||||
// Requires bind
|
||||
|
||||
/**
|
||||
* Constructor for the Dragger. Register for mousedown events that happen on
|
||||
* |opt_target|. If |opt_target| is null or undefined, then this object
|
||||
* observes mousedown on the whole document.
|
||||
* @param {?Element} opt_target The event target. Defaults to the whole
|
||||
* document.
|
||||
* @constructor
|
||||
*/
|
||||
tumbler.Dragger = function(opt_target) {
|
||||
/**
|
||||
* The event target.
|
||||
* @type {Element}
|
||||
* @private
|
||||
*/
|
||||
this.target_ = opt_target || document;
|
||||
|
||||
/**
|
||||
* The array of objects that get notified of drag events. Each object in
|
||||
* this array get sent a handleStartDrag(), handleDrag() and handleEndDrag()
|
||||
* message.
|
||||
* @type {Array.<Object>}
|
||||
* @private
|
||||
*/
|
||||
this.listeners_ = [];
|
||||
|
||||
/**
|
||||
* Flag to indicate whether the object is in a drag sequence or not.
|
||||
* @type {boolean}
|
||||
* @private
|
||||
*/
|
||||
this.isDragging_ = false;
|
||||
|
||||
/**
|
||||
* The function objects that get attached as event handlers. These are
|
||||
* cached so that they can be removed on mouse up.
|
||||
* @type {function}
|
||||
* @private
|
||||
*/
|
||||
this.boundMouseMove_ = null;
|
||||
this.boundMouseUp_ = null;
|
||||
|
||||
this.target_.addEventListener('mousedown',
|
||||
this.onMouseDown.bind(this),
|
||||
false);
|
||||
}
|
||||
|
||||
/**
|
||||
* The ids used for drag event types.
|
||||
* @enum {string}
|
||||
*/
|
||||
tumbler.Dragger.DragEvents = {
|
||||
DRAG_START: 'dragstart', // Start a drag sequence
|
||||
DRAG: 'drag', // Mouse moved during a drag sequence.
|
||||
DRAG_END: 'dragend' // End a drag sewquence.
|
||||
};
|
||||
|
||||
/**
|
||||
* Add a drag listener. Each listener should respond to thhree methods:
|
||||
* handleStartDrag(), handleDrag() and handleEndDrag(). This method assumes
|
||||
* that |listener| does not already exist in the array of listeners.
|
||||
* @param {!Object} listener The object that will listen to drag events.
|
||||
*/
|
||||
tumbler.Dragger.prototype.addDragListener = function(listener) {
|
||||
this.listeners_.push(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle a mousedown event: register for mousemove and mouseup, then tell
|
||||
* the target that is has a DRAG_START event.
|
||||
* @param {Event} event The mousedown event that triggered this method.
|
||||
*/
|
||||
tumbler.Dragger.prototype.onMouseDown = function(event) {
|
||||
this.boundMouseMove_ = this.onMouseMove.bind(this);
|
||||
this.boundMouseUp_ = this.onMouseUp.bind(this);
|
||||
this.target_.addEventListener('mousemove', this.boundMouseMove_);
|
||||
this.target_.addEventListener('mouseup', this.boundMouseUp_);
|
||||
this.isDragging_ = true;
|
||||
var dragStartEvent = { type: tumbler.Dragger.DragEvents.DRAG_START,
|
||||
clientX: event.offsetX,
|
||||
clientY: event.offsetY };
|
||||
var i;
|
||||
for (i = 0; i < this.listeners_.length; ++i) {
|
||||
this.listeners_[i].handleStartDrag(this.target_, dragStartEvent);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle a mousemove event: tell the target that is has a DRAG event.
|
||||
* @param {Event} event The mousemove event that triggered this method.
|
||||
*/
|
||||
tumbler.Dragger.prototype.onMouseMove = function(event) {
|
||||
if (!this.isDragging_)
|
||||
return;
|
||||
var dragEvent = { type: tumbler.Dragger.DragEvents.DRAG,
|
||||
clientX: event.offsetX,
|
||||
clientY: event.offsetY};
|
||||
var i;
|
||||
for (i = 0; i < this.listeners_.length; ++i) {
|
||||
this.listeners_[i].handleDrag(this.target_, dragEvent);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle a mouseup event: un-register for mousemove and mouseup, then tell
|
||||
* the target that is has a DRAG_END event.
|
||||
* @param {Event} event The mouseup event that triggered this method.
|
||||
*/
|
||||
tumbler.Dragger.prototype.onMouseUp = function(event) {
|
||||
this.target_.removeEventListener('mouseup', this.boundMouseUp_, false);
|
||||
this.target_.removeEventListener('mousemove', this.boundMouseMove_, false);
|
||||
this.boundMouseUp_ = null;
|
||||
this.boundMouseMove_ = null;
|
||||
this.isDragging_ = false;
|
||||
var dragEndEvent = { type: tumbler.Dragger.DragEvents.DRAG_END,
|
||||
clientX: event.offsetX,
|
||||
clientY: event.offsetY};
|
||||
var i;
|
||||
for (i = 0; i < this.listeners_.length; ++i) {
|
||||
this.listeners_[i].handleEndDrag(this.target_, dragEndEvent);
|
||||
}
|
||||
}
|
||||
9
Demos/NativeClient/bin_html/httpd.cmd
Normal file
9
Demos/NativeClient/bin_html/httpd.cmd
Normal file
@@ -0,0 +1,9 @@
|
||||
@echo off
|
||||
setlocal
|
||||
|
||||
REM Relative path of CygWin
|
||||
set CYGWIN=%~dp0%..\third_party\cygwin\bin
|
||||
|
||||
PATH=%CYGWIN%;%PATH%
|
||||
|
||||
python httpd.py
|
||||
114
Demos/NativeClient/bin_html/httpd.py
Normal file
114
Demos/NativeClient/bin_html/httpd.py
Normal file
@@ -0,0 +1,114 @@
|
||||
#!/usr/bin/python
|
||||
#
|
||||
# Copyright (c) 2011, The Native Client Authors. All rights reserved.
|
||||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
||||
#
|
||||
|
||||
"""A tiny web server.
|
||||
|
||||
This is intended to be used for testing, and only run from within the examples
|
||||
directory.
|
||||
"""
|
||||
|
||||
import BaseHTTPServer
|
||||
import logging
|
||||
import os
|
||||
import SimpleHTTPServer
|
||||
import SocketServer
|
||||
import sys
|
||||
import urlparse
|
||||
|
||||
logging.getLogger().setLevel(logging.INFO)
|
||||
|
||||
# Using 'localhost' means that we only accept connections
|
||||
# via the loop back interface.
|
||||
SERVER_PORT = 5103
|
||||
SERVER_HOST = ''
|
||||
|
||||
# We only run from the examples directory (the one that contains scons-out), so
|
||||
# that not too much is exposed via this HTTP server. Everything in the
|
||||
# directory is served, so there should never be anything potentially sensitive
|
||||
# in the serving directory, especially if the machine might be a
|
||||
# multi-user machine and not all users are trusted. We only serve via
|
||||
# the loopback interface.
|
||||
|
||||
SAFE_DIR_COMPONENTS = ['bin_html']
|
||||
SAFE_DIR_SUFFIX = apply(os.path.join, SAFE_DIR_COMPONENTS)
|
||||
|
||||
def SanityCheckDirectory():
|
||||
if os.getcwd().endswith(SAFE_DIR_SUFFIX):
|
||||
return
|
||||
logging.error('httpd.py should only be run from the %s', SAFE_DIR_SUFFIX)
|
||||
logging.error('directory for testing purposes.')
|
||||
logging.error('We are currently in %s', os.getcwd())
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
# An HTTP server that will quit when |is_running| is set to False. We also use
|
||||
# SocketServer.ThreadingMixIn in order to handle requests asynchronously for
|
||||
# faster responses.
|
||||
class QuittableHTTPServer(SocketServer.ThreadingMixIn,
|
||||
BaseHTTPServer.HTTPServer):
|
||||
def serve_forever(self, timeout=0.5):
|
||||
self.is_running = True
|
||||
self.timeout = timeout
|
||||
while self.is_running:
|
||||
self.handle_request()
|
||||
|
||||
def shutdown(self):
|
||||
self.is_running = False
|
||||
return 1
|
||||
|
||||
|
||||
# "Safely" split a string at |sep| into a [key, value] pair. If |sep| does not
|
||||
# exist in |str|, then the entire |str| is the key and the value is set to an
|
||||
# empty string.
|
||||
def KeyValuePair(str, sep='='):
|
||||
if sep in str:
|
||||
return str.split(sep)
|
||||
else:
|
||||
return [str, '']
|
||||
|
||||
|
||||
# A small handler that looks for '?quit=1' query in the path and shuts itself
|
||||
# down if it finds that parameter.
|
||||
class QuittableHTTPHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
|
||||
def do_GET(self):
|
||||
(_, _, _, query, _) = urlparse.urlsplit(self.path)
|
||||
url_params = dict([KeyValuePair(key_value)
|
||||
for key_value in query.split('&')])
|
||||
if 'quit' in url_params and '1' in url_params['quit']:
|
||||
self.send_response(200, 'OK')
|
||||
self.send_header('Content-type', 'text/html')
|
||||
self.send_header('Content-length', '0')
|
||||
self.end_headers()
|
||||
self.server.shutdown()
|
||||
return
|
||||
|
||||
SimpleHTTPServer.SimpleHTTPRequestHandler.do_GET(self)
|
||||
|
||||
|
||||
def Run(server_address,
|
||||
server_class=QuittableHTTPServer,
|
||||
handler_class=QuittableHTTPHandler):
|
||||
httpd = server_class(server_address, handler_class)
|
||||
logging.info("Starting local server on port %d", server_address[1])
|
||||
logging.info("To shut down send http://localhost:%d?quit=1",
|
||||
server_address[1])
|
||||
try:
|
||||
httpd.serve_forever()
|
||||
except KeyboardInterrupt:
|
||||
logging.info("Received keyboard interrupt.")
|
||||
httpd.server_close()
|
||||
|
||||
logging.info("Shutting down local server on port %d", server_address[1])
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
SanityCheckDirectory()
|
||||
if len(sys.argv) > 1:
|
||||
Run((SERVER_HOST, int(sys.argv[1])))
|
||||
else:
|
||||
Run((SERVER_HOST, SERVER_PORT))
|
||||
sys.exit(0)
|
||||
33
Demos/NativeClient/bin_html/index.html
Normal file
33
Demos/NativeClient/bin_html/index.html
Normal file
@@ -0,0 +1,33 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
|
||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html>
|
||||
<!--
|
||||
Copyright (c) 2011 The Native Client Authors. All rights reserved.
|
||||
Use of this source code is governed by a BSD-style license that can be
|
||||
found in the LICENSE file.
|
||||
-->
|
||||
<head>
|
||||
<title>Interactive Cube Example</title>
|
||||
<script type="text/javascript">
|
||||
// Provide the tumbler namespace
|
||||
tumbler = {};
|
||||
</script>
|
||||
<script type="text/javascript" src="bind.js"></script>
|
||||
<script type="text/javascript" src="dragger.js"></script>
|
||||
<script type="text/javascript" src="tumbler.js"></script>
|
||||
<script type="text/javascript" src="vector3.js"></script>
|
||||
<script type="text/javascript" src="trackball.js"></script>
|
||||
</head>
|
||||
<body id="bodyId">
|
||||
<h1>Interactive Cube Example</h1>
|
||||
<p>
|
||||
The Native Client module executed in this page draws a 3D cube
|
||||
and allows you to rotate it using a virtual trackball method.
|
||||
</p>
|
||||
<div id="tumbler_view"></div>
|
||||
<script type="text/javascript">
|
||||
tumbler.application = new tumbler.Application();
|
||||
tumbler.application.run('tumbler_view');
|
||||
</script>
|
||||
</body>
|
||||
</HTML>
|
||||
296
Demos/NativeClient/bin_html/trackball.js
Normal file
296
Demos/NativeClient/bin_html/trackball.js
Normal file
@@ -0,0 +1,296 @@
|
||||
// Copyright (c) 2011 The Native Client Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
/**
|
||||
* @fileoverview Implement a virtual trackball in the tumbler.Trackball
|
||||
* class. This class maps 2D mouse events to 3D rotations by simulating a
|
||||
* trackball that you roll by dragging the mouse. There are two principle
|
||||
* methods in the class: startAtPointInFrame which you use to begin a trackball
|
||||
* simulation and rollToPoint, which you use while dragging the mouse. The
|
||||
* rollToPoint method returns a rotation expressed as a quaternion.
|
||||
*/
|
||||
|
||||
|
||||
// Requires tumbler.Application
|
||||
// Requires tumbler.DragEvent
|
||||
// Requires tumbler.Vector3
|
||||
|
||||
/**
|
||||
* Constructor for the Trackball object. This class maps 2D mouse drag events
|
||||
* into 3D rotations by simulating a trackball. The idea is to simulate
|
||||
* clicking on the trackball, and then rolling it as you drag the mouse.
|
||||
* The math behind the trackball is simple: start with a vector from the first
|
||||
* mouse-click on the ball to the center of the 3D view. At the same time, set
|
||||
* the radius of the ball to be the smaller dimension of the 3D view. As you
|
||||
* drag the mouse around in the 3D view, a second vector is computed from the
|
||||
* surface of the ball to the center. The axis of rotation is the cross
|
||||
* product of these two vectors, and the angle of rotation is the angle between
|
||||
* the two vectors.
|
||||
* @constructor
|
||||
*/
|
||||
tumbler.Trackball = function() {
|
||||
/**
|
||||
* The square of the trackball's radius. The math never looks at the radius,
|
||||
* but looks at the radius squared.
|
||||
* @type {number}
|
||||
* @private
|
||||
*/
|
||||
this.sqrRadius_ = 0;
|
||||
|
||||
/**
|
||||
* The 3D vector representing the point on the trackball where the mouse
|
||||
* was clicked. Default is pointing stright through the center of the ball.
|
||||
* @type {Object}
|
||||
* @private
|
||||
*/
|
||||
this.rollStart_ = new tumbler.Vector3(0, 0, 1);
|
||||
|
||||
/**
|
||||
* The 2D center of the frame that encloses the trackball.
|
||||
* @type {!Object}
|
||||
* @private
|
||||
*/
|
||||
this.center_ = { x: 0, y: 0 };
|
||||
|
||||
/**
|
||||
* Cached camera orientation. When a drag START event happens this is set to
|
||||
* the current orientation in the calling view's plugin. The default is the
|
||||
* identity quaternion.
|
||||
* @type {Array.<number>}
|
||||
* @private
|
||||
*/
|
||||
this.cameraOrientation_ = [0, 0, 0, 1];
|
||||
};
|
||||
|
||||
/**
|
||||
* Compute the dimensions of the virtual trackball to fit inside |frameSize|.
|
||||
* The radius of the trackball is set to be 1/2 of the smaller of the two frame
|
||||
* dimensions, the center point is at the midpoint of each side.
|
||||
* @param {!goog.math.Size} frameSize 2D-point representing the size of the
|
||||
* element that encloses the virtual trackball.
|
||||
* @private
|
||||
*/
|
||||
tumbler.Trackball.prototype.initInFrame_ = function(frameSize) {
|
||||
// Compute the radius of the virtual trackball. This is 1/2 of the smaller
|
||||
// of the frame's width and height.
|
||||
var halfFrameSize = 0.5 * Math.min(frameSize.width, frameSize.height);
|
||||
// Cache the square of the trackball's radius.
|
||||
this.sqrRadius_ = halfFrameSize * halfFrameSize;
|
||||
// Figure the center of the view.
|
||||
this.center_.x = frameSize.width * 0.5;
|
||||
this.center_.y = frameSize.height * 0.5;
|
||||
};
|
||||
|
||||
/**
|
||||
* Method to convert (by translation) a 2D client point from a coordinate space
|
||||
* with origin in the lower-left corner of the client view to a space with
|
||||
* origin in the center of the client view. Use this method before mapping the
|
||||
* 2D point to he 3D tackball point (see also the projectOnTrackball_() method).
|
||||
* Call the startAtPointInFrame before calling this method so that the
|
||||
* |center_| property is correctly initialized.
|
||||
* @param {!Object} clientPoint map this point to the coordinate space with
|
||||
* origin in thecenter of the client view.
|
||||
* @return {Object} the converted point.
|
||||
* @private
|
||||
*/
|
||||
tumbler.Trackball.prototype.convertClientPoint_ = function(clientPoint) {
|
||||
var difference = { x: clientPoint.x - this.center_.x,
|
||||
y: clientPoint.y - this.center_.y }
|
||||
return difference;
|
||||
};
|
||||
|
||||
/**
|
||||
* Method to map a 2D point to a 3D point on the virtual trackball that was set
|
||||
* up using the startAtPointInFrame method. If the point lies outside of the
|
||||
* radius of the virtual trackball, then the z-coordinate of the 3D point
|
||||
* is set to 0.
|
||||
* @param {!Object.<x, y>} point 2D-point in the coordinate space with origin
|
||||
* in the center of the client view.
|
||||
* @return {tumbler.Vector3} the 3D point on the virtual trackball.
|
||||
* @private
|
||||
*/
|
||||
tumbler.Trackball.prototype.projectOnTrackball_ = function(point) {
|
||||
var sqrRadius2D = point.x * point.x + point.y * point.y;
|
||||
var zValue;
|
||||
if (sqrRadius2D > this.sqrRadius_) {
|
||||
// |point| lies outside the virtual trackball's sphere, so use a virtual
|
||||
// z-value of 0. This is equivalent to clicking on the horizontal equator
|
||||
// of the trackball.
|
||||
zValue = 0;
|
||||
} else {
|
||||
// A sphere can be defined as: r^2 = x^2 + y^2 + z^2, so z =
|
||||
// sqrt(r^2 - (x^2 + y^2)).
|
||||
zValue = Math.sqrt(this.sqrRadius_ - sqrRadius2D);
|
||||
}
|
||||
var trackballPoint = new tumbler.Vector3(point.x, point.y, zValue);
|
||||
return trackballPoint;
|
||||
};
|
||||
|
||||
/**
|
||||
* Method to start up the trackball. The trackball works by pretending that a
|
||||
* ball encloses the 3D view. You roll this pretend ball with the mouse. For
|
||||
* example, if you click on the center of the ball and move the mouse straight
|
||||
* to the right, you roll the ball around its Y-axis. This produces a Y-axis
|
||||
* rotation. You can click on the "edge" of the ball and roll it around
|
||||
* in a circle to get a Z-axis rotation.
|
||||
* @param {!Object.<x, y>} startPoint 2D-point, usually the mouse-down
|
||||
* point.
|
||||
* @param {!Object.<width, height>} frameSize 2D-point representing the size of
|
||||
* the element that encloses the virtual trackball.
|
||||
*/
|
||||
tumbler.Trackball.prototype.startAtPointInFrame =
|
||||
function(startPoint, frameSize) {
|
||||
this.initInFrame_(frameSize);
|
||||
// Compute the starting vector from the surface of the ball to its center.
|
||||
this.rollStart_ = this.projectOnTrackball_(
|
||||
this.convertClientPoint_(startPoint));
|
||||
};
|
||||
|
||||
/**
|
||||
* Method to roll the virtual trackball; call this in response to a mouseDrag
|
||||
* event. Takes |dragPoint| and projects it from 2D mouse coordinates onto the
|
||||
* virtual track ball that was set up in startAtPointInFrame method.
|
||||
* Returns a quaternion that represents the rotation from |rollStart_| to
|
||||
* |rollEnd_|.
|
||||
* @param {!Object.<x, y>} dragPoint 2D-point representing the
|
||||
* destination mouse point.
|
||||
* @return {Array.<number>} a quaternion that represents the rotation from
|
||||
* the point wnere the mouse was clicked on the trackball to this point.
|
||||
* The quaternion looks like this: [[v], cos(angle/2)], where [v] is the
|
||||
* imaginary part of the quaternion and is computed as [x, y, z] *
|
||||
* sin(angle/2).
|
||||
*/
|
||||
tumbler.Trackball.prototype.rollToPoint = function(dragPoint) {
|
||||
var rollTo = this.convertClientPoint_(dragPoint);
|
||||
if ((Math.abs(this.rollStart_.x - rollTo.x) <
|
||||
tumbler.Trackball.DOUBLE_EPSILON) &&
|
||||
(Math.abs(this.rollStart_.y, rollTo.y) <
|
||||
tumbler.Trackball.DOUBLE_EPSILON)) {
|
||||
// Not enough change in the vectors to roll the ball, return the identity
|
||||
// quaternion.
|
||||
return [0, 0, 0, 1];
|
||||
}
|
||||
|
||||
// Compute the ending vector from the surface of the ball to its center.
|
||||
var rollEnd = this.projectOnTrackball_(rollTo);
|
||||
|
||||
// Take the cross product of the two vectors. r = s X e
|
||||
var rollVector = this.rollStart_.cross(rollEnd);
|
||||
var invStartMag = 1.0 / this.rollStart_.magnitude();
|
||||
var invEndMag = 1.0 / rollEnd.magnitude();
|
||||
|
||||
// cos(a) = (s . e) / (||s|| ||e||)
|
||||
var cosAng = this.rollStart_.dot(rollEnd) * invStartMag * invEndMag;
|
||||
// sin(a) = ||(s X e)|| / (||s|| ||e||)
|
||||
var sinAng = rollVector.magnitude() * invStartMag * invEndMag;
|
||||
// Build a quaternion that represents the rotation about |rollVector|.
|
||||
// Use atan2 for a better angle. If you use only cos or sin, you only get
|
||||
// half the possible angles, and you can end up with rotations that flip
|
||||
// around near the poles.
|
||||
var rollHalfAngle = Math.atan2(sinAng, cosAng) * 0.5;
|
||||
rollVector.normalize();
|
||||
// The quaternion looks like this: [[v], cos(angle/2)], where [v] is the
|
||||
// imaginary part of the quaternion and is computed as [x, y, z] *
|
||||
// sin(angle/2).
|
||||
rollVector.scale(Math.sin(rollHalfAngle));
|
||||
var ballQuaternion = [rollVector.x,
|
||||
rollVector.y,
|
||||
rollVector.z,
|
||||
Math.cos(rollHalfAngle)];
|
||||
return ballQuaternion;
|
||||
};
|
||||
|
||||
/**
|
||||
* Handle the drag START event: grab the current camera orientation from the
|
||||
* sending view and set up the virtual trackball.
|
||||
* @param {!tumbler.Application} view The view controller that called this
|
||||
* method.
|
||||
* @param {!tumbler.DragEvent} dragStartEvent The DRAG_START event that
|
||||
* triggered this handler.
|
||||
*/
|
||||
tumbler.Trackball.prototype.handleStartDrag =
|
||||
function(controller, dragStartEvent) {
|
||||
// Cache the camera orientation. The orientations from the trackball as it
|
||||
// rolls are concatenated to this orientation and pushed back into the
|
||||
// plugin on the other side of the JavaScript bridge.
|
||||
controller.setCameraOrientation(this.cameraOrientation_);
|
||||
// Invert the y-coordinate for the trackball computations.
|
||||
var frameSize = { width: controller.offsetWidth,
|
||||
height: controller.offsetHeight };
|
||||
var flippedY = { x: dragStartEvent.clientX,
|
||||
y: frameSize.height - dragStartEvent.clientY };
|
||||
this.startAtPointInFrame(flippedY, frameSize);
|
||||
};
|
||||
|
||||
/**
|
||||
* Handle the drag DRAG event: concatenate the current orientation to the
|
||||
* cached orientation. Send this final value through to the GSPlugin via the
|
||||
* setValueForKey() method.
|
||||
* @param {!tumbler.Application} view The view controller that called this
|
||||
* method.
|
||||
* @param {!tumbler.DragEvent} dragEvent The DRAG event that triggered this
|
||||
* handler.
|
||||
*/
|
||||
tumbler.Trackball.prototype.handleDrag =
|
||||
function(controller, dragEvent) {
|
||||
// Flip the y-coordinate so that the 2D origin is in the lower-left corner.
|
||||
var frameSize = { width: controller.offsetWidth,
|
||||
height: controller.offsetHeight };
|
||||
var flippedY = { x: dragEvent.clientX,
|
||||
y: frameSize.height - dragEvent.clientY };
|
||||
controller.setCameraOrientation(
|
||||
tumbler.multQuaternions(this.rollToPoint(flippedY),
|
||||
this.cameraOrientation_));
|
||||
};
|
||||
|
||||
/**
|
||||
* Handle the drag END event: get the final orientation and concatenate it to
|
||||
* the cached orientation.
|
||||
* @param {!tumbler.Application} view The view controller that called this
|
||||
* method.
|
||||
* @param {!tumbler.DragEvent} dragEndEvent The DRAG_END event that triggered
|
||||
* this handler.
|
||||
*/
|
||||
tumbler.Trackball.prototype.handleEndDrag =
|
||||
function(controller, dragEndEvent) {
|
||||
// Flip the y-coordinate so that the 2D origin is in the lower-left corner.
|
||||
var frameSize = { width: controller.offsetWidth,
|
||||
height: controller.offsetHeight };
|
||||
var flippedY = { x: dragEndEvent.clientX,
|
||||
y: frameSize.height - dragEndEvent.clientY };
|
||||
this.cameraOrientation_ = tumbler.multQuaternions(this.rollToPoint(flippedY),
|
||||
this.cameraOrientation_);
|
||||
controller.setCameraOrientation(this.cameraOrientation_);
|
||||
};
|
||||
|
||||
/**
|
||||
* A utility function to multiply two quaterions. Returns the product q0 * q1.
|
||||
* This is effectively the same thing as concatenating the two rotations
|
||||
* represented in each quaternion together. Note that quaternion multiplication
|
||||
* is NOT commutative: q0 * q1 != q1 * q0.
|
||||
* @param {!Array.<number>} q0 A 4-element array representing the first
|
||||
* quaternion.
|
||||
* @param {!Array.<number>} q1 A 4-element array representing the second
|
||||
* quaternion.
|
||||
* @return {Array.<number>} A 4-element array representing the product q0 * q1.
|
||||
*/
|
||||
tumbler.multQuaternions = function(q0, q1) {
|
||||
// Return q0 * q1 (note the order).
|
||||
var qMult = [
|
||||
q0[3] * q1[0] + q0[0] * q1[3] + q0[1] * q1[2] - q0[2] * q1[1],
|
||||
q0[3] * q1[1] - q0[0] * q1[2] + q0[1] * q1[3] + q0[2] * q1[0],
|
||||
q0[3] * q1[2] + q0[0] * q1[1] - q0[1] * q1[0] + q0[2] * q1[3],
|
||||
q0[3] * q1[3] - q0[0] * q1[0] - q0[1] * q1[1] - q0[2] * q1[2]
|
||||
];
|
||||
return qMult;
|
||||
};
|
||||
|
||||
/**
|
||||
* Real numbers that are less than this distance apart are considered
|
||||
* equivalent.
|
||||
* TODO(dspringer): It seems as though there should be a const like this
|
||||
* in Closure somewhere (goog.math?).
|
||||
* @type {number}
|
||||
*/
|
||||
tumbler.Trackball.DOUBLE_EPSILON = 1.0e-16;
|
||||
133
Demos/NativeClient/bin_html/tumbler.js
Normal file
133
Demos/NativeClient/bin_html/tumbler.js
Normal file
@@ -0,0 +1,133 @@
|
||||
// Copyright (c) 2011 The Native Client Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
/**
|
||||
* @fileoverview The tumbler Application object. This object instantiates a
|
||||
* Trackball object and connects it to the element named |tumbler_content|.
|
||||
* It also conditionally embeds a debuggable module or a release module into
|
||||
* the |tumbler_content| element.
|
||||
*/
|
||||
|
||||
// Requires tumbler
|
||||
// Requires tumbler.Dragger
|
||||
// Requires tumbler.Trackball
|
||||
|
||||
/**
|
||||
* Constructor for the Application class. Use the run() method to populate
|
||||
* the object with controllers and wire up the events.
|
||||
* @constructor
|
||||
*/
|
||||
tumbler.Application = function() {
|
||||
/**
|
||||
* The native module for the application. This refers to the module loaded
|
||||
* via the <embed> tag.
|
||||
* @type {Element}
|
||||
* @private
|
||||
*/
|
||||
this.module_ = null;
|
||||
|
||||
/**
|
||||
* The trackball object.
|
||||
* @type {tumbler.Trackball}
|
||||
* @private
|
||||
*/
|
||||
this.trackball_ = null;
|
||||
|
||||
/**
|
||||
* The mouse-drag event object.
|
||||
* @type {tumbler.Dragger}
|
||||
* @private
|
||||
*/
|
||||
this.dragger_ = null;
|
||||
|
||||
/**
|
||||
* The function objects that get attached as event handlers. These are
|
||||
* cached so that they can be removed when they are no longer needed.
|
||||
* @type {function}
|
||||
* @private
|
||||
*/
|
||||
this.boundModuleDidLoad_ = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* The ids used for elements in the DOM. The Tumlber Application expects these
|
||||
* elements to exist.
|
||||
* @enum {string}
|
||||
* @private
|
||||
*/
|
||||
tumbler.Application.DomIds_ = {
|
||||
MODULE: 'tumbler', // The <embed> element representing the NaCl module
|
||||
VIEW: 'tumbler_view' // The <div> containing the NaCl element.
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by the module loading function once the module has been loaded.
|
||||
* @param {?Element} nativeModule The instance of the native module.
|
||||
*/
|
||||
tumbler.Application.prototype.moduleDidLoad = function() {
|
||||
this.module_ = document.getElementById(tumbler.Application.DomIds_.MODULE);
|
||||
// Unbind the load function.
|
||||
this.boundModuleDidLoad_ = null;
|
||||
|
||||
/**
|
||||
* Set the camera orientation property on the NaCl module.
|
||||
* @param {Array.<number>} orientation A 4-element array representing the
|
||||
* camera orientation as a quaternion.
|
||||
*/
|
||||
this.module_.setCameraOrientation = function(orientation) {
|
||||
var methodString = 'setCameraOrientation ' +
|
||||
'orientation:' +
|
||||
JSON.stringify(orientation);
|
||||
this.postMessage(methodString);
|
||||
}
|
||||
|
||||
this.trackball_ = new tumbler.Trackball();
|
||||
this.dragger_ = new tumbler.Dragger(this.module_);
|
||||
this.dragger_.addDragListener(this.trackball_);
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that cond is true; issues an alert and throws an Error otherwise.
|
||||
* @param {bool} cond The condition.
|
||||
* @param {String} message The error message issued if cond is false.
|
||||
*/
|
||||
tumbler.Application.prototype.assert = function(cond, message) {
|
||||
if (!cond) {
|
||||
message = "Assertion failed: " + message;
|
||||
alert(message);
|
||||
throw new Error(message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The run() method starts and 'runs' the application. The trackball object
|
||||
* is allocated and all the events get wired up.
|
||||
* @param {?String} opt_contentDivName The id of a DOM element in which to
|
||||
* embed the Native Client module. If unspecified, defaults to
|
||||
* VIEW. The DOM element must exist.
|
||||
*/
|
||||
tumbler.Application.prototype.run = function(opt_contentDivName) {
|
||||
contentDivName = opt_contentDivName || tumbler.Application.DomIds_.VIEW;
|
||||
var contentDiv = document.getElementById(contentDivName);
|
||||
this.assert(contentDiv, "Missing DOM element '" + contentDivName + "'");
|
||||
|
||||
// Note that the <EMBED> element is wrapped inside a <DIV>, which has a 'load'
|
||||
// event listener attached. This method is used instead of attaching the
|
||||
// 'load' event listener directly to the <EMBED> element to ensure that the
|
||||
// listener is active before the NaCl module 'load' event fires.
|
||||
this.boundModuleDidLoad_ = this.moduleDidLoad.bind(this);
|
||||
contentDiv.addEventListener('load', this.boundModuleDidLoad_, true);
|
||||
|
||||
// Load the published .nexe. This includes the 'nacl' attribute which
|
||||
// shows how to load multi-architecture modules. Each entry in the "nexes"
|
||||
// object in the .nmf manifest file is a key-value pair: the key is the
|
||||
// runtime ('x86-32', 'x86-64', etc.); the value is a URL for the desired
|
||||
// NaCl module. To load the debug versions of your .nexes, set the 'nacl'
|
||||
// attribute to the _dbg.nmf version of the manifest file.
|
||||
contentDiv.innerHTML = '<embed id="'
|
||||
+ tumbler.Application.DomIds_.MODULE + '" '
|
||||
+ 'src=tumbler.nmf '
|
||||
+ 'type="application/x-nacl" '
|
||||
+ 'width="480" height="480" />'
|
||||
}
|
||||
6
Demos/NativeClient/bin_html/tumbler.nmf
Normal file
6
Demos/NativeClient/bin_html/tumbler.nmf
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"program": {
|
||||
"x86-64": {"url": "NativeClientTumbler_x64.exe"},
|
||||
"x86-32": {"url": "NativeClientTumbler.exe"}
|
||||
}
|
||||
}
|
||||
91
Demos/NativeClient/bin_html/vector3.js
Normal file
91
Demos/NativeClient/bin_html/vector3.js
Normal file
@@ -0,0 +1,91 @@
|
||||
// Copyright (c) 2011 The Native Client Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
/**
|
||||
* @fileoverview A 3D vector class. Proviudes some utility functions on
|
||||
* 3-dimentional vectors.
|
||||
*/
|
||||
|
||||
// Requires tumbler
|
||||
|
||||
/**
|
||||
* Constructor for the Vector3 object. This class contains a 3-tuple that
|
||||
* represents a vector in 3D space.
|
||||
* @param {?number} opt_x The x-coordinate for this vector. If null or
|
||||
* undefined, the x-coordinate value is set to 0.
|
||||
* @param {?number} opt_y The y-coordinate for this vector. If null or
|
||||
* undefined, the y-coordinate value is set to 0.
|
||||
* @param {?number} opt_z The z-coordinate for this vector. If null or
|
||||
* undefined, the z-coordinate value is set to 0.
|
||||
* @constructor
|
||||
*/
|
||||
tumbler.Vector3 = function(opt_x, opt_y, opt_z) {
|
||||
/**
|
||||
* The vector's 3-tuple.
|
||||
* @type {number}
|
||||
*/
|
||||
this.x = opt_x || 0;
|
||||
this.y = opt_y || 0;
|
||||
this.z = opt_z || 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to return the magnitude of a Vector3.
|
||||
* @return {number} the magnitude of the vector.
|
||||
*/
|
||||
tumbler.Vector3.prototype.magnitude = function() {
|
||||
return Math.sqrt(this.dot(this));
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalize the vector in-place.
|
||||
* @return {number} the magnitude of the vector.
|
||||
*/
|
||||
tumbler.Vector3.prototype.normalize = function() {
|
||||
var mag = this.magnitude();
|
||||
if (mag < tumbler.Vector3.DOUBLE_EPSILON)
|
||||
return 0.0; // |this| is equivalent to the 0-vector, don't normalize.
|
||||
this.scale(1.0 / mag);
|
||||
return mag;
|
||||
}
|
||||
|
||||
/**
|
||||
* Scale the vector in-place by |s|.
|
||||
* @param {!number} s The scale factor.
|
||||
*/
|
||||
tumbler.Vector3.prototype.scale = function(s) {
|
||||
this.x *= s;
|
||||
this.y *= s;
|
||||
this.z *= s;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the dot product: |this| . v.
|
||||
* @param {!tumbler.Vector3} v The vector to dot.
|
||||
* @return {number} the result of |this| . v.
|
||||
*/
|
||||
tumbler.Vector3.prototype.dot = function(v) {
|
||||
return this.x * v.x + this.y * v.y + this.z * v.z;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the cross product: |this| X v.
|
||||
* @param {!tumbler.Vector3} v The vector to cross with.
|
||||
* @return {tumbler.Vector3} the result of |this| X v.
|
||||
*/
|
||||
tumbler.Vector3.prototype.cross = function(v) {
|
||||
var vCross = new tumbler.Vector3(this.y * v.z - this.z * v.y,
|
||||
this.z * v.x - this.x * v.z,
|
||||
this.x * v.y - this.y * v.x);
|
||||
return vCross;
|
||||
}
|
||||
|
||||
/**
|
||||
* Real numbers that are less than this distance apart are considered
|
||||
* equivalent.
|
||||
* TODO(dspringer): It seems as though there should be a const like this
|
||||
* in generally available somewhere.
|
||||
* @type {number}
|
||||
*/
|
||||
tumbler.Vector3.DOUBLE_EPSILON = 1.0e-16;
|
||||
Reference in New Issue
Block a user