Permalink
Browse files

New JITed vtables - interpolation code still needed

  • Loading branch information...
1 parent 6f6023a commit a96d07ffb57c4744c3a953ff9bc250d4d7f54b92 @benvanik committed Aug 3, 2012
Showing with 507 additions and 422 deletions.
  1. +1 −1 anvil_rules/templates/simstate_js.mako
  2. +60 −0 src/gf/net/packetreader.js
  3. +65 −59 src/gf/sim/entitystate.js
  4. +204 −210 src/gf/sim/variable.js
  5. +150 −152 src/gf/sim/variabletable.js
  6. +27 −0 src/gf/vec/color.js
View
2 anvil_rules/templates/simstate_js.mako
@@ -23,7 +23,7 @@ goog.require('${state.super}');
*/
${state.name} = function(entity, opt_variableTable) {
var variableTable = opt_variableTable || gf.sim.EntityState.getVariableTable(
- ${state.name}.declareVariables);
+ ${state.name}.declareVariables, this);
goog.base(this, entity, variableTable);
% for i, var in enumerate(state.vars):
View
60 src/gf/net/packetreader.js
@@ -294,6 +294,21 @@ gf.net.PacketReader.prototype.readVec3 = function(value) {
/**
* Reads a value from the buffer.
+ * The result of this function will be reset on the next read operation and must
+ * only be used to copy the value to some other structure.
+ * @return {!goog.vec.Vec3.Float32} Value pointer.
+ */
+gf.net.PacketReader.prototype.readVec3Temp = function() {
+ goog.asserts.assert(this.offset + 3 * 4 <= this.buffer.length);
+ for (var n = 0; n < 3 * 4; n++) {
+ this.float32byte_[n] = this.buffer[this.offset++];
+ }
+ return this.float32_;
+};
+
+
+/**
+ * Reads a value from the buffer.
* @param {!goog.vec.Vec4.Float32} value Value to receive the contents.
*/
gf.net.PacketReader.prototype.readVec4 = function(value) {
@@ -307,6 +322,21 @@ gf.net.PacketReader.prototype.readVec4 = function(value) {
/**
* Reads a value from the buffer.
+ * The result of this function will be reset on the next read operation and must
+ * only be used to copy the value to some other structure.
+ * @return {!goog.vec.Vec3.Float32} Value pointer.
+ */
+gf.net.PacketReader.prototype.readVec4Temp = function() {
+ goog.asserts.assert(this.offset + 4 * 4 <= this.buffer.length);
+ for (var n = 0; n < 4 * 4; n++) {
+ this.float32byte_[n] = this.buffer[this.offset++];
+ }
+ return this.float32_;
+};
+
+
+/**
+ * Reads a value from the buffer.
* @param {!goog.vec.Mat3.Type} value Value to receive the contents.
*/
gf.net.PacketReader.prototype.readMat3 = function(value) {
@@ -320,6 +350,21 @@ gf.net.PacketReader.prototype.readMat3 = function(value) {
/**
* Reads a value from the buffer.
+ * The result of this function will be reset on the next read operation and must
+ * only be used to copy the value to some other structure.
+ * @return {!goog.vec.Vec3.Float32} Value pointer.
+ */
+gf.net.PacketReader.prototype.readMat3Temp = function() {
+ goog.asserts.assert(this.offset + 3 * 3 * 4 <= this.buffer.length);
+ for (var n = 0; n < 3 * 3 * 4; n++) {
+ this.float32byte_[n] = this.buffer[this.offset++];
+ }
+ return this.float32_;
+};
+
+
+/**
+ * Reads a value from the buffer.
* @param {!goog.vec.Mat4.Type} value Value to receive the contents.
*/
gf.net.PacketReader.prototype.readMat4 = function(value) {
@@ -333,6 +378,21 @@ gf.net.PacketReader.prototype.readMat4 = function(value) {
/**
* Reads a value from the buffer.
+ * The result of this function will be reset on the next read operation and must
+ * only be used to copy the value to some other structure.
+ * @return {!goog.vec.Vec3.Float32} Value pointer.
+ */
+gf.net.PacketReader.prototype.readMat4Temp = function() {
+ goog.asserts.assert(this.offset + 4 * 4 * 4 <= this.buffer.length);
+ for (var n = 0; n < 4 * 4 * 4; n++) {
+ this.float32byte_[n] = this.buffer[this.offset++];
+ }
+ return this.float32_;
+};
+
+
+/**
+ * Reads a value from the buffer.
* @param {Uint8Array=} opt_target Target value, used if the size matches.
* @return {!Uint8Array} Value read.
*/
View
124 src/gf/sim/entitystate.js
@@ -20,6 +20,7 @@
goog.provide('gf.sim.EntityState');
+goog.require('gf.sim.Variable');
goog.require('gf.sim.VariableTable');
goog.require('goog.asserts');
@@ -92,11 +93,12 @@ gf.sim.EntityState = function(entity, variableTable) {
* Entity state variable declaration function.
* @return {!gf.sim.VariableTable} A shared variable table.
*/
-gf.sim.EntityState.getVariableTable = function(declarationFunction) {
+gf.sim.EntityState.getVariableTable = function(declarationFunction, obj) {
if (!declarationFunction.variableTable_) {
var variableList = [];
declarationFunction(variableList);
- declarationFunction.variableTable_ = new gf.sim.VariableTable(variableList);
+ declarationFunction.variableTable_ = new gf.sim.VariableTable(
+ variableList, obj);
}
return declarationFunction.variableTable_;
};
@@ -155,37 +157,15 @@ gf.sim.EntityState.prototype.read = function(reader) {
*/
gf.sim.EntityState.prototype.readDelta = function(reader) {
// Read the first 32 variables
- this.readDeltaVariables_(reader, 0);
+ var presentBits00_31 = reader.readVarUint();
+ this.variableTable_.readPresentVariables(
+ 0, presentBits00_31, this, reader);
// Write the next 32, if present
if (this.variableTable_.getCount() > 31) {
- this.readDeltaVariables_(reader, 32);
- }
-};
-
-
-/**
- * Reads a range of delta variables.
- * This function is designed to be called on a subset of the variable range.
- * For example, the first 32 variables, second 32, etc.
- * @private
- * @param {!gf.net.PacketReader} reader Packet reader.
- * @param {number} startingOrdinal Ordinal this range starts at.
- */
-gf.sim.EntityState.prototype.readDeltaVariables_ = function(
- reader, startingOrdinal) {
- // Read bits indicating which variables are present
- var presentBits = reader.readVarUint();
-
- // For each bit that is present, read the value
- var ordinal = startingOrdinal;
- while (presentBits) {
- if (presentBits & 1) {
- // Variable at <ordinal> is present and needs reading
- this.variableTable_.readVariable(ordinal, this, reader);
- }
- presentBits >>= 1;
- ordinal++;
+ var presentBits32_63 = reader.readVarUint();
+ this.variableTable_.readPresentVariables(
+ 32, presentBits32_63, this, reader);
}
};
@@ -214,38 +194,15 @@ gf.sim.EntityState.prototype.writeDelta = function(writer) {
// delta
// Write the first 32 variables
- this.writeDeltaVariables_(writer, this.dirtyBits00_31_, 0);
+ writer.writeVarUint(this.dirtyBits00_31_);
+ this.variableTable_.writePresentVariables(
+ 0, this.dirtyBits00_31_, this, writer);
// Write the next 32, if present
if (this.dirtyBits32_63_ && this.variableTable_.getCount() > 31) {
- this.writeDeltaVariables_(writer, this.dirtyBits32_63_, 32);
- }
-};
-
-
-/**
- * Writes a range of delta variables.
- * This function is designed to be called on a subset of the variable range.
- * For example, the first 32 variables, second 32, etc.
- * @private
- * @param {!gf.net.PacketWriter} writer Packet writer.
- * @param {number} presentBits Bit field indicating which variables are present.
- * @param {number} startingOrdinal Ordinal this range starts at.
- */
-gf.sim.EntityState.prototype.writeDeltaVariables_ = function(
- writer, presentBits, startingOrdinal) {
- // Write dirty bits
- writer.writeVarUint(presentBits);
-
- // For each bit that is dirty, write the value
- var ordinal = startingOrdinal;
- while (presentBits) {
- if (presentBits & 1) {
- // Variable at <ordinal> is dirty and needs writing
- this.variableTable_.writeVariable(ordinal, this, writer);
- }
- presentBits >>= 1;
- ordinal++;
+ writer.writeVarUint(this.dirtyBits32_63_);
+ this.variableTable_.writePresentVariables(
+ 32, this.dirtyBits32_63_, this, writer);
}
};
@@ -300,3 +257,52 @@ gf.sim.EntityState.prototype.interpolate = function(
vtable.interpolateVariables(sourceState, targetState, t, this);
}
};
+
+
+// TODO(benvanik): find a way to remove these - point at an indirection table?
+/**
+ * Scratch Vec3 for math.
+ * This is currently used by the variable table system.
+ * @protected
+ * @type {!goog.vec.Vec3.Float32}
+ */
+gf.sim.EntityState.prototype.tmpVec3 = gf.sim.Variable.tmpVec3;
+
+
+/**
+ * Scratch Quaternion for math.
+ * This is currently used by the variable table system.
+ * @protected
+ * @type {!goog.vec.Quaternion.Float32}
+ */
+gf.sim.EntityState.prototype.tmpQuat = gf.sim.Variable.tmpQuat;
+
+
+/**
+ * Quaternion slerp.
+ * This is currently used by the variable table system.
+ * @protected
+ * @type {!Function}
+ */
+gf.sim.EntityState.prototype.qslerp = goog.vec.Quaternion.slerp;
+
+
+/**
+ * Color lerp.
+ * This is currently used by the variable table system.
+ * @protected
+ * @type {!Function}
+ */
+gf.sim.EntityState.prototype.colorLerp = gf.vec.Color.lerpUint32;
+
+// HACK: ensure things are included
+goog.scope(function() {
+ gf.sim.EntityState.prototype.tmpVec3[0] =
+ gf.sim.EntityState.prototype.tmpVec3[1];
+ gf.sim.EntityState.prototype.qslerp(
+ gf.sim.EntityState.prototype.tmpQuat,
+ gf.sim.EntityState.prototype.tmpQuat,
+ 0,
+ gf.sim.EntityState.prototype.tmpQuat);
+ gf.sim.EntityState.prototype.colorLerp(0, 0, 0);
+});
View
414 src/gf/sim/variable.js
@@ -21,6 +21,9 @@
goog.provide('gf.sim.Variable');
goog.provide('gf.sim.VariableFlag');
+goog.require('gf.net.PacketReader');
+goog.require('gf.net.PacketWriter');
+goog.require('gf.vec.Color');
goog.require('goog.vec.Quaternion');
goog.require('goog.vec.Vec3');
@@ -72,37 +75,47 @@ gf.sim.Variable.prototype.clone = goog.abstractMethod;
/**
- * Reads the variable.
- * @param {!Object} target Target object.
- * @param {!gf.net.PacketReader} reader Packet reader.
+ * Gets a source code statement for read.
+ * Used by the JIT system in the variable table.
+ * @param {!Object} obj Representative object.
+ * @return {string} Source statement.
*/
-gf.sim.Variable.prototype.read = goog.abstractMethod;
+gf.sim.Variable.prototype.getReadSource = goog.abstractMethod;
/**
- * Writes the variable.
- * @param {!Object} target Target object.
- * @param {!gf.net.PacketWriter} writer Packet writer.
+ * Gets a source code statement for write.
+ * Used by the JIT system in the variable table.
+ * @param {!Object} obj Representative object.
+ * @return {string} Source statement.
*/
-gf.sim.Variable.prototype.write = goog.abstractMethod;
+gf.sim.Variable.prototype.getWriteSource = goog.abstractMethod;
/**
- * Copies the value from one object to another.
- * @param {!Object} source Source object.
- * @param {!Object} target Target object.
+ * Gets a source code statement for copy.
+ * Used by the JIT system in the variable table.
+ * @param {!Object} obj Representative object.
+ * @return {string} Source statement.
*/
-gf.sim.Variable.prototype.copy = goog.abstractMethod;
+gf.sim.Variable.prototype.getCopySource = function(obj) {
+ var getter = gf.sim.Variable.getCompiledFunctionName_(obj, this.getter_);
+ var setter = gf.sim.Variable.getCompiledFunctionName_(obj, this.setter_);
+ return 'target.' + setter + '(source.' + getter + '());';
+};
/**
- * Interpolates the value between the given two states.
- * @param {!Object} source Interpolation source object.
- * @param {!Object} target Interpolation target object.
- * @param {number} t Interpolation coefficient, [0-1].
- * @param {!Object} result Storage object.
+ * Gets a source code statement for interpolate.
+ * Used by the JIT system in the variable table.
+ * @param {!Object} obj Representative object.
+ * @return {string} Source statement.
*/
-gf.sim.Variable.prototype.interpolate = goog.abstractMethod;
+gf.sim.Variable.prototype.getInterpolateSource = function(obj) {
+ var getter = gf.sim.Variable.getCompiledFunctionName_(obj, this.getter_);
+ var setter = gf.sim.Variable.getCompiledFunctionName_(obj, this.setter_);
+ return 'result.' + setter + '(target.' + getter + '());';
+};
/**
@@ -139,6 +152,25 @@ gf.sim.Variable.sortByPriority = function(a, b) {
/**
+ * Gets the compiled name of a member on an object.
+ * This looks up by member value, so only use with known-good values.
+ * @private
+ * @param {!Object} obj Representative object.
+ * @param {!Object} memberValue Member value.
+ * @return {string?} Member name, if found.
+ */
+gf.sim.Variable.getCompiledFunctionName_ = function(obj, memberValue) {
+ for (var name in obj) {
+ if (obj[name] === memberValue) {
+ return name;
+ }
+ }
+ goog.asserts.fail('member not found');
+ return null;
+};
+
+
+/**
* Bitmask values describing the behavior of variables.
* @enum {number}
*/
@@ -210,36 +242,47 @@ gf.sim.Variable.Integer.prototype.clone = function() {
/**
* @override
*/
-gf.sim.Variable.Integer.prototype.read = function(target, reader) {
- this.setter_.call(target, reader.readVarInt());
+gf.sim.Variable.Integer.prototype.getReadSource = function(obj) {
+ var setter = gf.sim.Variable.getCompiledFunctionName_(obj, this.setter_);
+ var reader = gf.net.PacketReader.getSharedReader();
+ var readFn = gf.sim.Variable.getCompiledFunctionName_(
+ reader, reader.readVarInt);
+ return 'target.' + setter + '(reader.' + readFn + '());';
};
/**
* @override
*/
-gf.sim.Variable.Integer.prototype.write = function(target, writer) {
- writer.writeVarInt(this.getter_.call(target) | 0);
+gf.sim.Variable.Integer.prototype.getWriteSource = function(obj) {
+ var getter = gf.sim.Variable.getCompiledFunctionName_(obj, this.getter_);
+ var writer = gf.net.PacketWriter.getSharedWriter();
+ var writeFn = gf.sim.Variable.getCompiledFunctionName_(
+ writer, writer.writeVarInt);
+ return 'writer.' + writeFn + '(target.' + getter + '() | 0);';
};
/**
* @override
*/
-gf.sim.Variable.Integer.prototype.copy = function(source, target) {
- this.setter_.call(target, this.getter_.call(source) | 0);
+gf.sim.Variable.Integer.prototype.getCopySource = function(obj) {
+ var getter = gf.sim.Variable.getCompiledFunctionName_(obj, this.getter_);
+ var setter = gf.sim.Variable.getCompiledFunctionName_(obj, this.setter_);
+ return 'target.' + setter + '(source.' + getter + '() | 0);';
};
/**
* @override
*/
-gf.sim.Variable.Integer.prototype.interpolate = function(source, target, t,
- result) {
- var sourceValue = this.getter_.call(source) | 0;
- var targetValue = this.getter_.call(target) | 0;
- this.setter_.call(result,
- (sourceValue + t * (targetValue - sourceValue)) | 0);
+gf.sim.Variable.Integer.prototype.getInterpolateSource = function(obj) {
+ var getter = gf.sim.Variable.getCompiledFunctionName_(obj, this.getter_);
+ var setter = gf.sim.Variable.getCompiledFunctionName_(obj, this.setter_);
+ return '' +
+ 'var _s = source.' + getter + '();' +
+ 'var _t = target.' + getter + '();' +
+ 'target.' + setter + '((_s + t * (_t - _s)) | 0);';
};
@@ -284,35 +327,37 @@ gf.sim.Variable.Float.prototype.clone = function() {
/**
* @override
*/
-gf.sim.Variable.Float.prototype.read = function(target, reader) {
- this.setter_.call(target, reader.readFloat32());
-};
-
-
-/**
- * @override
- */
-gf.sim.Variable.Float.prototype.write = function(target, writer) {
- writer.writeFloat32(this.getter_.call(target));
+gf.sim.Variable.Float.prototype.getReadSource = function(obj) {
+ var setter = gf.sim.Variable.getCompiledFunctionName_(obj, this.setter_);
+ var reader = gf.net.PacketReader.getSharedReader();
+ var readFn = gf.sim.Variable.getCompiledFunctionName_(
+ reader, reader.readFloat32);
+ return 'target.' + setter + '(reader.' + readFn + '());';
};
/**
* @override
*/
-gf.sim.Variable.Float.prototype.copy = function(source, target) {
- this.setter_.call(target, this.getter_.call(source));
+gf.sim.Variable.Float.prototype.getWriteSource = function(obj) {
+ var getter = gf.sim.Variable.getCompiledFunctionName_(obj, this.getter_);
+ var writer = gf.net.PacketWriter.getSharedWriter();
+ var writeFn = gf.sim.Variable.getCompiledFunctionName_(
+ writer, writer.writeFloat32);
+ return 'writer.' + writeFn + '(target.' + getter + '());';
};
/**
* @override
*/
-gf.sim.Variable.Float.prototype.interpolate = function(source, target, t,
- result) {
- var sourceValue = this.getter_.call(source);
- var targetValue = this.getter_.call(target);
- this.setter_.call(result, sourceValue + t * (targetValue - sourceValue));
+gf.sim.Variable.Float.prototype.getInterpolateSource = function(obj) {
+ var getter = gf.sim.Variable.getCompiledFunctionName_(obj, this.getter_);
+ var setter = gf.sim.Variable.getCompiledFunctionName_(obj, this.setter_);
+ return '' +
+ 'var _s = source.' + getter + '();' +
+ 'var _t = target.' + getter + '();' +
+ 'result.' + setter + '((_s + t * (_t - _s)));';
};
@@ -359,52 +404,46 @@ gf.sim.Variable.Vec3.prototype.clone = function() {
/**
* @override
*/
-gf.sim.Variable.Vec3.prototype.read = function(target, reader) {
- var v = gf.sim.Variable.Vec3.tmp_;
- reader.readVec3(v);
- this.setter_.call(target, v);
-};
-
-
-/**
- * @override
- */
-gf.sim.Variable.Vec3.prototype.write = function(target, writer) {
- writer.writeVec3(this.getter_.call(target));
+gf.sim.Variable.Vec3.prototype.getReadSource = function(obj) {
+ var setter = gf.sim.Variable.getCompiledFunctionName_(obj, this.setter_);
+ var reader = gf.net.PacketReader.getSharedReader();
+ var readFn = gf.sim.Variable.getCompiledFunctionName_(
+ reader, reader.readVec3Temp);
+ return 'target.' + setter + '(reader.' + readFn + '());';
};
/**
* @override
*/
-gf.sim.Variable.Vec3.prototype.copy = function(source, target) {
- this.setter_.call(target, this.getter_.call(source));
+gf.sim.Variable.Vec3.prototype.getWriteSource = function(obj) {
+ var getter = gf.sim.Variable.getCompiledFunctionName_(obj, this.getter_);
+ var writer = gf.net.PacketWriter.getSharedWriter();
+ var writeFn = gf.sim.Variable.getCompiledFunctionName_(
+ writer, writer.writeVec3);
+ return 'writer.' + writeFn + '(target.' + getter + '());';
};
/**
* @override
*/
-gf.sim.Variable.Vec3.prototype.interpolate = function(source, target, t,
- result) {
- var v = gf.sim.Variable.Vec3.tmp_;
- goog.vec.Vec3.lerp(
- this.getter_.call(source),
- this.getter_.call(target),
- t,
- v);
- this.setter_.call(result, v);
+gf.sim.Variable.Vec3.prototype.getInterpolateSource = function(obj) {
+ var getter = gf.sim.Variable.getCompiledFunctionName_(obj, this.getter_);
+ var setter = gf.sim.Variable.getCompiledFunctionName_(obj, this.setter_);
+ var tmpVec3 = gf.sim.Variable.getCompiledFunctionName_(obj,
+ gf.sim.Variable.tmpVec3);
+ return '' +
+ 'var _sv3 = source.' + getter + '();' +
+ 'var _tv3 = target.' + getter + '();' +
+ 'var _rv3 = source.' + tmpVec3 + ';' +
+ '_rv3[0] = (_tv3[0] - _sv3[0]) * t + _sv3[0];' +
+ '_rv3[1] = (_tv3[1] - _sv3[1]) * t + _sv3[1];' +
+ '_rv3[2] = (_tv3[2] - _sv3[2]) * t + _sv3[2];' +
+ 'result.' + setter + '(_rv3);';
};
-/**
- * Scratch Vec3 for math.
- * @private
- * @type {!goog.vec.Vec3.Float32}
- */
-gf.sim.Variable.Vec3.tmp_ = goog.vec.Vec3.createFloat32();
-
-
/**
* Variable containing a floating-point quaternion.
@@ -458,63 +497,45 @@ gf.sim.Variable.Quaternion.prototype.clone = function() {
/**
* @override
*/
-gf.sim.Variable.Quaternion.prototype.read = function(target, reader) {
- var q = gf.sim.Variable.Quaternion.tmp_;
- // if (this.normalized_) {
- // // Reconstruct w
- // reader.readVec3(q);
- // // Trick is from http://www.gamedev.net/topic/461253-compressed-quaternions/
- // // Known to have issues - may not be worth it
- // q[3] = Math.sqrt(1 - q[0] * q[0] + q[1] * q[1] + q[2] * q[2]);
- // } else {
- reader.readVec4(q);
- this.setter_.call(target, q);
-};
-
-
-/**
- * @override
- */
-gf.sim.Variable.Quaternion.prototype.write = function(target, writer) {
- // if (this.normalized_) {
- // // Just ignore w
- // writer.writeVec3(this.getter_.call(target));
- // } else {
- writer.writeVec4(this.getter_.call(target));
+gf.sim.Variable.Quaternion.prototype.getReadSource = function(obj) {
+ var setter = gf.sim.Variable.getCompiledFunctionName_(obj, this.setter_);
+ var reader = gf.net.PacketReader.getSharedReader();
+ var readFn = gf.sim.Variable.getCompiledFunctionName_(
+ reader, reader.readVec4Temp);
+ return 'target.' + setter + '(reader.' + readFn + '());';
};
/**
* @override
*/
-gf.sim.Variable.Quaternion.prototype.copy = function(source, target) {
- this.setter_.call(target, this.getter_.call(source));
+gf.sim.Variable.Quaternion.prototype.getWriteSource = function(obj) {
+ var getter = gf.sim.Variable.getCompiledFunctionName_(obj, this.getter_);
+ var writer = gf.net.PacketWriter.getSharedWriter();
+ var writeFn = gf.sim.Variable.getCompiledFunctionName_(
+ writer, writer.writeVec4);
+ return 'writer.' + writeFn + '(target.' + getter + '());';
};
/**
* @override
*/
-gf.sim.Variable.Quaternion.prototype.interpolate = function(source, target, t,
- result) {
- var q = gf.sim.Variable.Quaternion.tmp_;
- goog.vec.Quaternion.slerp(
- this.getter_.call(source),
- this.getter_.call(target),
- t,
- q);
- this.setter_.call(result, q);
+gf.sim.Variable.Quaternion.prototype.getInterpolateSource = function(obj) {
+ var getter = gf.sim.Variable.getCompiledFunctionName_(obj, this.getter_);
+ var setter = gf.sim.Variable.getCompiledFunctionName_(obj, this.setter_);
+ var tmpQuat = gf.sim.Variable.getCompiledFunctionName_(obj,
+ gf.sim.Variable.tmpQuat);
+ var slerp = gf.sim.Variable.getCompiledFunctionName_(obj,
+ goog.vec.Quaternion.slerp);
+ return '' +
+ 'var _rq = source.' + tmpQuat + ';' +
+ 'source.' + slerp +
+ '(source.' + getter + '(), target.' + getter + '(), t, _rq);' +
+ 'result.' + setter + '(_rq);';
};
-/**
- * Scratch Quaternion for math.
- * @private
- * @type {!goog.vec.Quaternion.Float32}
- */
-gf.sim.Variable.Quaternion.tmp_ = goog.vec.Quaternion.createFloat32();
-
-
/**
* Variable containing an ARGB color.
@@ -556,50 +577,38 @@ gf.sim.Variable.Color.prototype.clone = function() {
/**
* @override
*/
-gf.sim.Variable.Color.prototype.read = function(target, reader) {
- this.setter_.call(target, reader.readFloat32());
+gf.sim.Variable.Color.prototype.getReadSource = function(obj) {
+ var setter = gf.sim.Variable.getCompiledFunctionName_(obj, this.setter_);
+ var reader = gf.net.PacketReader.getSharedReader();
+ var readFn = gf.sim.Variable.getCompiledFunctionName_(
+ reader, reader.readUint32);
+ return 'target.' + setter + '(reader.' + readFn + '());';
};
/**
* @override
*/
-gf.sim.Variable.Color.prototype.write = function(target, writer) {
- writer.writeFloat32(this.getter_.call(target));
+gf.sim.Variable.Color.prototype.getWriteSource = function(obj) {
+ var getter = gf.sim.Variable.getCompiledFunctionName_(obj, this.getter_);
+ var writer = gf.net.PacketWriter.getSharedWriter();
+ var writeFn = gf.sim.Variable.getCompiledFunctionName_(
+ writer, writer.writeUint32);
+ return 'writer.' + writeFn + '(target.' + getter + '());';
};
/**
* @override
*/
-gf.sim.Variable.Color.prototype.copy = function(source, target) {
- this.setter_.call(target, this.getter_.call(source));
-};
-
-
-/**
- * @override
- */
-gf.sim.Variable.Color.prototype.interpolate = function(source, target, t,
- result) {
- // There has got to be a better way...
- // Knowing that t = [0,1], I'm sure it's possible to do this in two mults
- var sourceValue = this.getter_.call(source);
- var sourceA = (sourceValue >> 24) & 0xFF;
- var sourceB = (sourceValue >> 16) & 0xFF;
- var sourceG = (sourceValue >> 8) & 0xFF;
- var sourceR = sourceValue & 0xFF;
- var targetValue = this.getter_.call(target);
- var targetA = (sourceValue >> 24) & 0xFF;
- var targetB = (sourceValue >> 16) & 0xFF;
- var targetG = (sourceValue >> 8) & 0xFF;
- var targetR = sourceValue & 0xFF;
- var value =
- ((sourceA + t * (targetA - sourceA)) & 0xFF) << 24 |
- ((sourceB + t * (targetB - sourceB)) & 0xFF) << 16 |
- ((sourceG + t * (targetG - sourceG)) & 0xFF) << 8 |
- ((sourceR + t * (targetR - sourceR)) & 0xFF);
- this.setter_.call(result, value);
+gf.sim.Variable.Color.prototype.getInterpolateSource = function(obj) {
+ var getter = gf.sim.Variable.getCompiledFunctionName_(obj, this.getter_);
+ var setter = gf.sim.Variable.getCompiledFunctionName_(obj, this.setter_);
+ var lerp = gf.sim.Variable.getCompiledFunctionName_(obj,
+ gf.vec.Color.lerpUint32);
+ return '' +
+ 'result.' + setter + '(source.' + lerp + '(' +
+ 'source.' + getter + '(), target.' + getter + '(), t));';
};
@@ -644,34 +653,24 @@ gf.sim.Variable.String.prototype.clone = function() {
/**
* @override
*/
-gf.sim.Variable.String.prototype.read = function(target, reader) {
- this.setter_.call(target, reader.readString());
-};
-
-
-/**
- * @override
- */
-gf.sim.Variable.String.prototype.write = function(target, writer) {
- writer.writeString(this.getter_.call(target));
-};
-
-
-/**
- * @override
- */
-gf.sim.Variable.String.prototype.copy = function(source, target) {
- this.setter_.call(target, this.getter_.call(source));
+gf.sim.Variable.String.prototype.getReadSource = function(obj) {
+ var setter = gf.sim.Variable.getCompiledFunctionName_(obj, this.setter_);
+ var reader = gf.net.PacketReader.getSharedReader();
+ var readFn = gf.sim.Variable.getCompiledFunctionName_(
+ reader, reader.readString);
+ return 'target.' + setter + '(reader.' + readFn + '());';
};
/**
* @override
*/
-gf.sim.Variable.String.prototype.interpolate = function(source, target, t,
- result) {
- // Instantaneous to target
- this.setter_.call(result, this.getter_.call(target));
+gf.sim.Variable.String.prototype.getWriteSource = function(obj) {
+ var getter = gf.sim.Variable.getCompiledFunctionName_(obj, this.getter_);
+ var writer = gf.net.PacketWriter.getSharedWriter();
+ var writeFn = gf.sim.Variable.getCompiledFunctionName_(
+ writer, writer.writeString);
+ return 'writer.' + writeFn + '(target.' + getter + '());';
};
@@ -716,34 +715,24 @@ gf.sim.Variable.UserID.prototype.clone = function() {
/**
* @override
*/
-gf.sim.Variable.UserID.prototype.read = function(target, reader) {
- this.setter_.call(target, reader.readString());
+gf.sim.Variable.UserID.prototype.getReadSource = function(obj) {
+ var setter = gf.sim.Variable.getCompiledFunctionName_(obj, this.setter_);
+ var reader = gf.net.PacketReader.getSharedReader();
+ var readFn = gf.sim.Variable.getCompiledFunctionName_(
+ reader, reader.readString);
+ return 'target.' + setter + '(reader.' + readFn + '());';
};
/**
* @override
*/
-gf.sim.Variable.UserID.prototype.write = function(target, writer) {
- writer.writeString(this.getter_.call(target));
-};
-
-
-/**
- * @override
- */
-gf.sim.Variable.UserID.prototype.copy = function(source, target) {
- this.setter_.call(target, this.getter_.call(source));
-};
-
-
-/**
- * @override
- */
-gf.sim.Variable.UserID.prototype.interpolate = function(source, target, t,
- result) {
- // Instantaneous to target
- this.setter_.call(result, this.getter_.call(target));
+gf.sim.Variable.UserID.prototype.getWriteSource = function(obj) {
+ var getter = gf.sim.Variable.getCompiledFunctionName_(obj, this.getter_);
+ var writer = gf.net.PacketWriter.getSharedWriter();
+ var writeFn = gf.sim.Variable.getCompiledFunctionName_(
+ writer, writer.writeString);
+ return 'writer.' + writeFn + '(target.' + getter + '());';
};
@@ -788,32 +777,37 @@ gf.sim.Variable.EntityID.prototype.clone = function() {
/**
* @override
*/
-gf.sim.Variable.EntityID.prototype.read = function(target, reader) {
- this.setter_.call(target, reader.readVarUint());
+gf.sim.Variable.EntityID.prototype.getReadSource = function(obj) {
+ var setter = gf.sim.Variable.getCompiledFunctionName_(obj, this.setter_);
+ var reader = gf.net.PacketReader.getSharedReader();
+ var readFn = gf.sim.Variable.getCompiledFunctionName_(
+ reader, reader.readVarUint);
+ return 'target.' + setter + '(reader.' + readFn + '());';
};
/**
* @override
*/
-gf.sim.Variable.EntityID.prototype.write = function(target, writer) {
- writer.writeVarUint(this.getter_.call(target));
+gf.sim.Variable.EntityID.prototype.getWriteSource = function(obj) {
+ var getter = gf.sim.Variable.getCompiledFunctionName_(obj, this.getter_);
+ var writer = gf.net.PacketWriter.getSharedWriter();
+ var writeFn = gf.sim.Variable.getCompiledFunctionName_(
+ writer, writer.writeVarUint);
+ return 'writer.' + writeFn + '(target.' + getter + '());';
};
+
/**
- * @override
+ * Scratch Vec3 for math.
+ * @type {!goog.vec.Vec3.Float32}
*/
-gf.sim.Variable.EntityID.prototype.copy = function(source, target) {
- this.setter_.call(target, this.getter_.call(source));
-};
+gf.sim.Variable.tmpVec3 = goog.vec.Vec3.createFloat32();
/**
- * @override
+ * Scratch Quaternion for math.
+ * @type {!goog.vec.Quaternion.Float32}
*/
-gf.sim.Variable.EntityID.prototype.interpolate = function(source, target, t,
- result) {
- // Instantaneous to target
- this.setter_.call(result, this.getter_.call(target));
-};
+gf.sim.Variable.tmpQuat = goog.vec.Quaternion.createFloat32();
View
302 src/gf/sim/variabletable.js
@@ -37,8 +37,10 @@ goog.require('goog.asserts');
*
* @constructor
* @param {!Array.<!gf.sim.Variable>} variableList A list of all variables.
+ * @param {!Object} obj A representative object with an initialized prototype
+ * chain. Used for JITing.
*/
-gf.sim.VariableTable = function(variableList) {
+gf.sim.VariableTable = function(variableList, obj) {
// Sort by priority in a stable way
// We do this with a hack of using the ordinals if the two priorities are the
// same
@@ -57,34 +59,36 @@ gf.sim.VariableTable = function(variableList) {
this.ordinalLookup_ = {};
/**
- * Variables that are neither interpolated or predicted.
+ * A table of variable read functions.
+ * These are JITed functions that read variables into a value.
+ * Array order matches variable order.
* @private
- * @type {!Array.<!gf.sim.Variable>}
+ * @type {!Array.<!function(!Object, !gf.net.PacketReader)>}
*/
- this.immediateVariables_ = [];
+ this.readTable_ = new Array(variableList.length);
/**
- * Variables that have their {@see gf.sim.VariableFlag#PREDICTED} bit set.
+ * A table of variable write functions.
+ * These are JITed functions that write variables into a value.
+ * Array order matches variable order.
* @private
- * @type {!Array.<!gf.sim.Variable>}
+ * @type {!Array.<!function(!Object, !gf.net.PacketWriter)>}
*/
- this.predictedVariables_ = [];
-
- /**
- * Variables that have their {@see gf.sim.VariableFlag#INTERPOLATED} bit set.
- * @private
- * @type {!Array.<!gf.sim.Variable>}
- */
- this.interpolatedVariables_ = [];
-
- /**
- * Variables that have their {@see gf.sim.VariableFlag#INTERPOLATED} bit set
- * but not their {@see gf.sim.VariableFlag#PREDICTED} bit set. This is used
- * for interpolating variables on clients that have prediction enabled.
- * @private
- * @type {!Array.<!gf.sim.Variable>}
- */
- this.interpolatedNotPredictedVariables_ = [];
+ this.writeTable_ = new Array(variableList.length);
+
+ // Here lie black magic
+ // This code carefully constructs Functions while being mindful of the Closure
+ // Compiler renaming rules - it does this through some clever hacks that will
+ // likely break with ambiguation enabled - I hope that doesn't happen.
+ // This should be fairly efficient, and since vtables are shared across all
+ // entities of a given type this is a one-time per-entity type hit.
+ var readAllVariablesFn = '';
+ var writeAllVariablesFn = '';
+ var copyVariablesFn = '';
+ var copyImmediateVariablesFn = '';
+ var copyPredictedVariablesFn = '';
+ var interpolateVariablesFn = '';
+ var interpolateUnpredictedVariablesFn = '';
/**
* List, in sorted ordinal order, of all variables.
@@ -101,21 +105,104 @@ gf.sim.VariableTable = function(variableList) {
// Assign ordinal
v.ordinal = n;
- // Add to fast access arrays
+ // Read/write table
+ this.readTable_[n] = new Function(
+ 'target', 'reader', v.getReadSource(obj));
+ this.writeTable_[n] = new Function(
+ 'target', 'writer', v.getWriteSource(obj));
+
+ // Add function JIT per-variable statements
+ readAllVariablesFn += v.getReadSource(obj);
+ writeAllVariablesFn += v.getWriteSource(obj);
+ var copySource = v.getCopySource(obj);
+ copyVariablesFn += copySource;
if (!(v.flags & (
gf.sim.VariableFlag.PREDICTED | gf.sim.VariableFlag.INTERPOLATED))) {
- this.immediateVariables_.push(v);
+ copyImmediateVariablesFn += copySource;
}
if (v.flags & gf.sim.VariableFlag.PREDICTED) {
- this.predictedVariables_.push(v);
+ copyPredictedVariablesFn += copySource;
}
if (v.flags & gf.sim.VariableFlag.INTERPOLATED) {
- this.interpolatedVariables_.push(v);
+ var interpolateSource = v.getInterpolateSource(obj);
+ interpolateVariablesFn += interpolateSource;
if (!(v.flags & gf.sim.VariableFlag.PREDICTED)) {
- this.interpolatedNotPredictedVariables_.push(v);
+ interpolateUnpredictedVariablesFn += interpolateSource;
}
}
}
+
+ /**
+ * Reads all variables.
+ * @param {!Object} target Target object.
+ * @param {!gf.net.PacketReader} reader Packet reader.
+ */
+ this.readAllVariables = new Function(
+ 'target', 'reader', readAllVariablesFn);
+
+ /**
+ * Writes all variables.
+ * @param {!Object} target Target object.
+ * @param {!gf.net.PacketWriter} writer Packet writer.
+ */
+ this.writeAllVariables = new Function(
+ 'target', 'writer', writeAllVariablesFn);
+
+ /**
+ * Copies all variables from one object to another.
+ * @param {!Object} source Source object.
+ * @param {!Object} target Target object.
+ */
+ this.copyVariables = new Function(
+ 'source', 'target', copyVariablesFn);
+
+ /**
+ * Copies all immediate variables from one object to another (those variables
+ * that are not predicted/interpolated).
+ * @param {!Object} source Source object.
+ * @param {!Object} target Target object.
+ */
+ this.copyImmediateVariables = new Function(
+ 'source', 'target', copyImmediateVariablesFn);
+
+ /**
+ * Copies values of all predicted variables from one object to another.
+ * All values in the target with {@see gf.sim.VariableFlag#PREDICTED} set will
+ * get overwritten with the source values.
+ * @param {!Object} source Source object.
+ * @param {!Object} target Target object.
+ */
+ this.copyPredictedVariables = new Function(
+ 'source', 'target', copyPredictedVariablesFn);
+
+ /**
+ * Interpolates variables between two states.
+ * All values with {@see gf.sim.VariableFlag#INTERPOLATED} set will be
+ * interpolated between the source and target by the given time. The result
+ * will be stored on the given result object.
+ * @param {!Object} source Interpolation source object.
+ * @param {!Object} target Interpolation target object.
+ * @param {number} t Interpolation coefficient, [0-1].
+ * @param {!Object} result Storage object.
+ */
+ this.interpolateVariables = new Function(
+ 'source', 'target', 't', 'result', interpolateVariablesFn);
+
+ /**
+ * Interpolates unpredicted variables between two states.
+ * All values with {@see gf.sim.VariableFlag#INTERPOLATED} set will be
+ * interpolated between the source and target by the given time. The result
+ * will be stored on the given result object.
+ * This version will ignore variables that also have
+ * {@see gf.sim.VariableFlag#PREDICTED} set on them, preventing interpolation
+ * from messing with the prediction system.
+ * @param {!Object} source Interpolation source object.
+ * @param {!Object} target Interpolation target object.
+ * @param {number} t Interpolation coefficient, [0-1].
+ * @param {!Object} result Storage object.
+ */
+ this.interpolateUnpredictedVariables = new Function(
+ 'source', 'target', 't', 'result', interpolateUnpredictedVariablesFn);
};
@@ -141,140 +228,51 @@ gf.sim.VariableTable.prototype.getOrdinal = function(tag) {
/**
- * Reads the given variable.
- * @param {number} ordinal Variable ordinal.
- * @param {!Object} target Target object.
- * @param {!gf.net.PacketReader} reader Packet reader.
- */
-gf.sim.VariableTable.prototype.readVariable = function(
- ordinal, target, reader) {
- var v = this.variables_[ordinal];
- // NOTE: must validate here, as clients could send up bogus info
- if (v) {
- v.read(target, reader);
- }
-};
-
-
-/**
- * Reads all variables.
+ * Reads a range of delta variables.
+ * This function is designed to be called on a subset of the variable range.
+ * For example, the first 32 variables, second 32, etc.
+ * @param {number} startingOrdinal Ordinal this range starts at.
+ * @param {number} presentBits Bit field indicating which variables are present.
* @param {!Object} target Target object.
* @param {!gf.net.PacketReader} reader Packet reader.
*/
-gf.sim.VariableTable.prototype.readAllVariables = function(target, reader) {
- var vars = this.variables_;
- for (var n = 0; n < vars.length; n++) {
- vars[n].read(target, reader);
+gf.sim.VariableTable.prototype.readPresentVariables = function(
+ startingOrdinal, presentBits, target, reader) {
+ var readTable = this.readTable_;
+ var ordinal = startingOrdinal;
+ while (presentBits) {
+ if (presentBits & 1) {
+ // Variable at <ordinal> is present and needs reading
+ // NOTE: must validate here, as clients could send up bogus info
+ if (readTable[ordinal]) {
+ readTable[ordinal](target, reader);
+ }
+ }
+ presentBits >>= 1;
+ ordinal++;
}
};
/**
- * Writes the given variable.
- * @param {number} ordinal Variable ordinal.
+ * Writes a range of delta variables.
+ * This function is designed to be called on a subset of the variable range.
+ * For example, the first 32 variables, second 32, etc.
+ * @param {number} startingOrdinal Ordinal this range starts at.
+ * @param {number} presentBits Bit field indicating which variables are present.
* @param {!Object} target Target object.
* @param {!gf.net.PacketWriter} writer Packet writer.
*/
-gf.sim.VariableTable.prototype.writeVariable = function(
- ordinal, target, writer) {
- var v = this.variables_[ordinal];
- v.write(target, writer);
-};
-
-
-/**
- * Writes all variables.
- * @param {!Object} target Target object.
- * @param {!gf.net.PacketWriter} writer Packet writer.
- */
-gf.sim.VariableTable.prototype.writeAllVariables = function(target, writer) {
- var vars = this.variables_;
- for (var n = 0; n < vars.length; n++) {
- vars[n].write(target, writer);
- }
-};
-
-
-/**
- * Copies all variables from one object to another.
- * @param {!Object} source Source object.
- * @param {!Object} target Target object.
- */
-gf.sim.VariableTable.prototype.copyVariables = function(source, target) {
- var vars = this.variables_;
- for (var n = 0; n < vars.length; n++) {
- vars[n].copy(source, target);
- }
-};
-
-
-/**
- * Copies all immediate variables from one object to another (those variables
- * that are not predicted/interpolated).
- * @param {!Object} source Source object.
- * @param {!Object} target Target object.
- */
-gf.sim.VariableTable.prototype.copyImmediateVariables = function(
- source, target) {
- var vars = this.immediateVariables_;
- for (var n = 0; n < vars.length; n++) {
- vars[n].copy(source, target);
- }
-};
-
-
-/**
- * Copies values of all predicted variables from one object to another.
- * All values in the target with {@see gf.sim.VariableFlag#PREDICTED} set will
- * get overwritten with the source values.
- * @param {!Object} source Source object.
- * @param {!Object} target Target object.
- */
-gf.sim.VariableTable.prototype.copyPredictedVariables = function(
- source, target) {
- var vars = this.predictedVariables_;
- for (var n = 0; n < vars.length; n++) {
- vars[n].copy(source, target);
- }
-};
-
-
-/**
- * Interpolates variables between two states.
- * All values with {@see gf.sim.VariableFlag#INTERPOLATED} set will be
- * interpolated between the source and target by the given time. The result
- * will be stored on the given result object.
- * @param {!Object} source Interpolation source object.
- * @param {!Object} target Interpolation target object.
- * @param {number} t Interpolation coefficient, [0-1].
- * @param {!Object} result Storage object.
- */
-gf.sim.VariableTable.prototype.interpolateVariables = function(
- source, target, t, result) {
- var vars = this.interpolatedVariables_;
- for (var n = 0; n < vars.length; n++) {
- vars[n].interpolate(source, target, t, result);
- }
-};
-
-
-/**
- * Interpolates unpredicted variables between two states.
- * All values with {@see gf.sim.VariableFlag#INTERPOLATED} set will be
- * interpolated between the source and target by the given time. The result
- * will be stored on the given result object.
- * This version will ignore variables that also have
- * {@see gf.sim.VariableFlag#PREDICTED} set on them, preventing interpolation
- * from messing with the prediction system.
- * @param {!Object} source Interpolation source object.
- * @param {!Object} target Interpolation target object.
- * @param {number} t Interpolation coefficient, [0-1].
- * @param {!Object} result Storage object.
- */
-gf.sim.VariableTable.prototype.interpolateUnpredictedVariables = function(
- source, target, t, result) {
- var vars = this.interpolatedNotPredictedVariables_;
- for (var n = 0; n < vars.length; n++) {
- vars[n].interpolate(source, target, t, result);
+gf.sim.VariableTable.prototype.writePresentVariables = function(
+ startingOrdinal, presentBits, target, writer) {
+ var writeTable = this.writeTable_;
+ var ordinal = startingOrdinal;
+ while (presentBits) {
+ if (presentBits & 1) {
+ // Variable at <ordinal> is dirty and needs writing
+ writeTable[ordinal](target, writer);
+ }
+ presentBits >>= 1;
+ ordinal++;
}
};
View
27 src/gf/vec/color.js
@@ -35,3 +35,30 @@ gf.vec.Color.toUint32 = function(value) {
var a = Math.min(255, value[3] * 255);
return (a << 24) | (b << 16) | (g << 8) | r;
};
+
+
+/**
+ * Linear interpolation between two color values.
+ * @param {number} source Source Uint32 color as ABGR.
+ * @param {number} target Target Uint32 color as ABGR.
+ * @param {number} t Interpolation value, [0-1].
+ * @return {number} Result ABGR.
+ */
+gf.vec.Color.lerpUint32 = function(source, target, t) {
+ // There has got to be a better way...
+ // Knowing that t = [0,1], I'm sure it's possible to do this in two mults
+ var sourceA = (source >> 24) & 0xFF;
+ var sourceB = (source >> 16) & 0xFF;
+ var sourceG = (source >> 8) & 0xFF;
+ var sourceR = source & 0xFF;
+ var targetA = (target >> 24) & 0xFF;
+ var targetB = (target >> 16) & 0xFF;
+ var targetG = (target >> 8) & 0xFF;
+ var targetR = target & 0xFF;
+ var result =
+ ((sourceA + t * (targetA - sourceA)) & 0xFF) << 24 |
+ ((sourceB + t * (targetB - sourceB)) & 0xFF) << 16 |
+ ((sourceG + t * (targetG - sourceG)) & 0xFF) << 8 |
+ ((sourceR + t * (targetR - sourceR)) & 0xFF);
+ return result;
+};

0 comments on commit a96d07f

Please sign in to comment.