Comparing version 0.0.2 to 0.2.0
var cubeSize = 32; | ||
// occlusion | ||
Template.occlusion.onRendered(function () { | ||
@@ -36,2 +37,3 @@ var start = +new Date; | ||
// reverse | ||
Template.reverse.onRendered(function () { | ||
@@ -93,2 +95,3 @@ var start = +new Date; | ||
// model | ||
Template.model.onRendered(function () { | ||
@@ -127,1 +130,83 @@ var model = JSON.parse(this.data.model); | ||
}); | ||
// click | ||
Template.click.onRendered(function () { | ||
var clickCube = 32; | ||
var start = +new Date; | ||
var cubes = this.cubes = new Cubes(this.find('canvas'), { | ||
x: clickCube, | ||
y: clickCube, | ||
z: clickCube, | ||
clickDetection: true | ||
}); | ||
for (var z = 0, zz = clickCube; z < zz; z++) { | ||
for (var y = 0, yy = clickCube; y < yy; y++) { | ||
for (var x = 0, xx = clickCube; x < xx; x++) { | ||
this.cubes.insert({ | ||
x: x, | ||
y: y, | ||
z: z, | ||
color: this.cubes.randomColor().toHex() | ||
}); | ||
} | ||
} | ||
} | ||
var count = this.cubes.renderScene() | ||
// Values based on 32x32x32 cube at 800x800. | ||
Tinytest.add('click - top', function (test) { | ||
var cube = cubes.click(400, 6); | ||
test.equal(cube.x, 31); | ||
test.equal(cube.y, 31); | ||
test.equal(cube.z, 31); | ||
}); | ||
Tinytest.add('click - bottom', function (test) { | ||
var cube = cubes.click(400, 635); | ||
test.equal(cube.x, 0); | ||
test.equal(cube.y, 0); | ||
test.equal(cube.z, 0); | ||
}); | ||
Tinytest.add('click - upper left', function (test) { | ||
var cube = cubes.click(128, 165); | ||
test.equal(cube.x, 0); | ||
test.equal(cube.y, 31); | ||
test.equal(cube.z, 31); | ||
}); | ||
Tinytest.add('click - upper right', function (test) { | ||
var cube = cubes.click(675, 165); | ||
test.equal(cube.x, 31); | ||
test.equal(cube.y, 0); | ||
test.equal(cube.z, 31); | ||
}); | ||
Tinytest.add('click - lower left', function (test) { | ||
var cube = cubes.click(128, 480); | ||
test.equal(cube.x, 0); | ||
test.equal(cube.y, 31); | ||
test.equal(cube.z, 0); | ||
}); | ||
Tinytest.add('click - lower right', function (test) { | ||
var cube = cubes.click(675, 480); | ||
test.equal(cube.x, 31); | ||
test.equal(cube.y, 0); | ||
test.equal(cube.z, 0); | ||
}); | ||
var end = +new Date; | ||
console.log(count, 'cubes rendered in', end - start, 'ms'); | ||
}); | ||
Template.click.events({ | ||
'click canvas': function (evt, tpl) { | ||
console.log(evt.offsetX, evt.offsetY); | ||
var cube = tpl.cubes.click(evt.offsetX, evt.offsetY); | ||
console.log(cube.x, cube.y, cube.z); | ||
} | ||
}) |
148
cubes.js
@@ -33,2 +33,3 @@ Cubes = function (canvasNode, config) { | ||
scale: (config.scale || 10.0), | ||
originX: (config.originX || null), | ||
originY: (config.originY || this.gridSizeZ * 2 * 10), | ||
@@ -42,2 +43,9 @@ lightPosition: new this.Isomer.Vector( | ||
this.clickDetection = config.clickDetection || false; | ||
if (this.clickDetection) { | ||
// this.clickBuffer = new Int16Array(this.iso.canvas.width * this.iso.canvas.height); | ||
this.clickBuffer = {}; | ||
} | ||
this.iso.colorDifference = config.colorDifference || 0.10; | ||
@@ -114,3 +122,8 @@ | ||
else { | ||
this.render(renderQueue); | ||
if (this.clickDetection) { | ||
this.render(renderQueue, this._renderClickBuffer); | ||
} | ||
else { | ||
this.render(renderQueue); | ||
} | ||
} | ||
@@ -135,16 +148,121 @@ | ||
Cubes.prototype.render = function (rq) { | ||
setTimeout(function (that, rq) { | ||
Cubes.prototype._renderClickBuffer = function (that, shapeQueue) { | ||
var width = that.iso.canvas.width; | ||
var height = that.iso.canvas.height; | ||
var shape = null; | ||
var quad = null; | ||
var point = null; | ||
var id = null; | ||
var points = null; | ||
for (var sh = 0, shh = shapeQueue.length; sh < shh; sh += 2) { | ||
shape = shapeQueue[sh]; | ||
id = shapeQueue[sh + 1]; | ||
for (var q = 0, qq = shape.length; q < qq; q++) { | ||
quad = shape[q]; | ||
var points = []; | ||
for (var p = 0, pp = quad.length; p < pp; p++) { | ||
point = quad[p]; | ||
points.push(point.x, point.y); | ||
} | ||
that._fillQuad(that, points, id); | ||
} | ||
} | ||
} | ||
Cubes.prototype._fillQuad = function (that, points, id) { | ||
that._rasterTri(that, { | ||
x: points[0], | ||
y: points[1] | ||
}, { | ||
x: points[2], | ||
y: points[3] | ||
}, { | ||
x: points[4], | ||
y: points[5] | ||
}, id); | ||
that._rasterTri(that, { | ||
x: points[4], | ||
y: points[5] | ||
}, { | ||
x: points[6], | ||
y: points[7] | ||
}, { | ||
x: points[0], | ||
y: points[1] | ||
}, id); | ||
} | ||
// http://www.sunshine2k.de/coding/java/TriangleRasterization/TriangleRasterization.html | ||
Cubes.prototype._rasterTri = function (that, vt1, vt2, vt3, id) { | ||
var maxX = Math.max(vt1.x, Math.max(vt2.x, vt3.x)); | ||
var minX = Math.min(vt1.x, Math.min(vt2.x, vt3.x)); | ||
var maxY = Math.max(vt1.y, Math.max(vt2.y, vt3.y)); | ||
var minY = Math.min(vt1.y, Math.min(vt2.y, vt3.y)); | ||
var vs1 = { | ||
x: vt2.x - vt1.x, | ||
y: vt2.y - vt1.y | ||
}; | ||
var vs2 = { | ||
x: vt3.x - vt1.x, | ||
y: vt3.y - vt1.y | ||
}; | ||
for (var x = minX; x <= maxX; x++) { | ||
for (var y = minY; y <= maxY; y++) { | ||
var q = { | ||
x: x - vt1.x, | ||
y: y - vt1.y | ||
}; | ||
var s = that._crossProduct(q, vs2) / that._crossProduct(vs1, vs2); | ||
var t = that._crossProduct(vs1, q) / that._crossProduct(vs1, vs2); | ||
if ((s >= 0) && (t >= 0) && (s + t <= 1)) { | ||
that._drawPixel(that, x, y, id); | ||
} | ||
} | ||
} | ||
} | ||
Cubes.prototype._crossProduct = function (a, b) { | ||
return a.x * b.y - a.y * b.x; | ||
} | ||
Cubes.prototype._drawPixel = function (that, x, y, id) { | ||
var index = that._indexCanvas(Math.floor(x), Math.floor(y), that); | ||
that.clickBuffer[index] = id; | ||
} | ||
Cubes.prototype.render = function (rq, cb) { | ||
setTimeout(function (that, rq, cb) { | ||
var cube = null; | ||
var shape = null; | ||
var result = null; | ||
if (cb) var shapeQueue = []; | ||
for (var j = 0, jj = rq.length; j < jj; j++) { | ||
cube = rq[j]; | ||
that.iso.add( | ||
that.Shape.Prism( | ||
new that.Point(cube.x, cube.y, cube.z) | ||
), | ||
shape = that.Shape.Prism( | ||
new that.Point(cube.x, cube.y, cube.z) | ||
); | ||
result = that.iso.add( | ||
shape, | ||
cube.color ? that.isoColor(cube.color) : null | ||
// , true | ||
); | ||
if (cb) shapeQueue.push(result, cube.index); | ||
} | ||
}, 0, this, rq); | ||
if (cb) { | ||
cb(that, shapeQueue); | ||
}; | ||
}, 0, this, rq, cb); | ||
} | ||
@@ -175,2 +293,3 @@ | ||
var index = this._index(cube.x, cube.y, cube.z); | ||
var faceIndex = this._index(fx, fy, fz); | ||
@@ -188,4 +307,2 @@ | ||
var index = this._index(cube.x, cube.y, cube.z); | ||
if (dist <= this.faceDistances[faceIndex]) { | ||
@@ -202,2 +319,8 @@ this.faceIndices[faceIndex] = index; | ||
Cubes.prototype.click = function (x, y) { | ||
var canvasIndex = this._indexCanvas(x, y); | ||
var index = this.clickBuffer[canvasIndex]; | ||
return this.sceneData[index]; | ||
} | ||
Cubes.prototype._index = function (x, y, z) { | ||
@@ -207,4 +330,9 @@ return this.gridSizeZ * this.gridSizeZ * z + this.gridSizeY * y + x + 1; | ||
Cubes.prototype._indexCanvas = function (x, y, that) { | ||
that = this || that; | ||
return that.iso.canvas.height * y + x; | ||
} | ||
if (Cubes.commonJS) { | ||
module.exports = Cubes; | ||
} |
Package.describe({ | ||
name: 'cryptoquick:cubes', | ||
version: '0.0.2', | ||
version: '0.2.0', | ||
summary: 'An isometric graphics-rendering library.', | ||
@@ -10,7 +10,8 @@ git: 'https://github.com/cryptoquick/cubes', | ||
Package.onUse(function(api) { | ||
api.use('cryptoquick:isomer@0.2.5'); | ||
// api.use('cryptoquick:isomer@0.2.5'); | ||
api.versionsFrom('1.1.0.2'); | ||
api.addFiles('isomer.js'); | ||
api.addFiles('cubes.js'); | ||
api.export('Cubes'); | ||
api.imply('cryptoquick:isomer@0.2.5'); | ||
// api.imply('cryptoquick:isomer@0.2.5'); | ||
}); | ||
@@ -17,0 +18,0 @@ |
{ | ||
"name": "cubes", | ||
"version": "0.0.2", | ||
"version": "0.2.0", | ||
"description": "An isometric graphics management library.", | ||
@@ -5,0 +5,0 @@ "main": "cubes.js", |
117
README.md
@@ -5,27 +5,124 @@ # Cubes | ||
It's used primarily for Meteor, but it's also designed as a standalone NPM package. | ||
## Current Support | ||
- Meteor | ||
## Planned Support | ||
- Browserify | ||
- Full source | ||
- Minified distribution with sourcemap | ||
- Pull requests for other package managers are welcomed | ||
## Roadmap | ||
- 0.0 - Current | ||
- 0.0 - _Finished_ | ||
- Experimental status | ||
- 0.1 - Future | ||
- 0.1 - _Finished_ | ||
- Scene management | ||
- Depth sorting | ||
- Occlusion culling | ||
- 0.2 | ||
- 0.2 - _Finished_ | ||
- Click detection | ||
- Scene editing API | ||
- Basic editor partial | ||
- 0.3 | ||
- Isometric color picker partial | ||
- 0.3 - __Future__ | ||
- 3-axis slicing | ||
- 4-angle rotation | ||
- 0.4 | ||
- Isometric color picker partial | ||
- Basic editor partial | ||
- 0.5 | ||
- Backend rendering | ||
## Usage | ||
## Configuration | ||
This package is still under heavy development. Contributions welcome. | ||
An example configuration, taken from the defaults: | ||
If used without Meteor or Browserify, be sure to include Isomer, as a dependency. | ||
```javascript | ||
var canvas = document.getElementById('myCanvas'); | ||
var cubes = new Cubes(canvas, { | ||
// This defines how much area is given to cube rendering and editing | ||
x: 32, | ||
y: 32, | ||
z: 32, | ||
// Slow mode provides a visual example of how models are rendered. The value provided indicates milliseconds between each successive render. | ||
slow: 10, | ||
// This determines how large the cubes and grid area are. | ||
scale: 10.0, | ||
// This determines the center from which all graphics are drawn. This should be set to a sensible value, but if it isn't, it can be overridden. It is measured in pixels. | ||
originX: null, | ||
// Also available is originY. It should also be set to a sensible default, but in case it isn't... | ||
originY: null, | ||
// Toggles click detection for this instance of Cubes. | ||
clickDetection: false, | ||
// Determines how different the sides of each cube of the same color are in lightness. | ||
colorDifference: 0.10, | ||
// This is the position of the light source for lighting the scene. It's a directional light, so a larger number indicates the light is further away, but it is not a point light. | ||
lightX: 3, lightY: -5, lightZ: 1, | ||
// Do you want a base plan upon which to build upon? No? Set it to false, then. | ||
planeXY: true | ||
}); | ||
``` | ||
## Scene Management | ||
Current methods: | ||
- insert() | ||
This will return a special scene ID that's used internally by Cubes to keep track of cubes in a quickly accessible format. This will change if a different size cube area is specified. Please use x, y, & z format for storing and retrieving cube information. | ||
Planned methods: | ||
- remove() | ||
- find() | ||
- edit() | ||
- export() | ||
- load() | ||
### Insert | ||
A simple insert method in addition to color data. | ||
```javascript | ||
cubes.insert({ | ||
x: x, | ||
y: y, | ||
z: z, | ||
color: '#ff00ff' | ||
}); | ||
``` | ||
## Click Detection | ||
Click detection must be enabled, using the `clickDetection` configuration property, as shown above. | ||
`cubes.click(x, y);` | ||
### Example | ||
```javascript | ||
$('#myCanvas').on('click', function (evt) { | ||
cubes.click(evt.offsetX, evt.offsetY); | ||
}); | ||
``` | ||
## Utility Methods | ||
Some additional useful utility methods are available. | ||
### Random Colors | ||
`cubes.randomColor().toHex()` | ||
## Testing | ||
Be sure to see what's being done in the `cubes-tests.js` file. Tests can be run with Meteor installed and running the `meteor test-packages ./` command. |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
74273
10
1391
128
1