Dynamic tilemap webgl rendering

This commit is contained in:
Felipe Alfonso 2017-06-21 22:19:03 -04:00
parent de336e6d35
commit 25977cfc4d
32 changed files with 250 additions and 45 deletions

View file

@ -1,4 +1,4 @@
var CHECKSUM = {
build: 'a534dad0-56ea-11e7-93ca-31a05bf83d09'
build: '0c19bd50-56f1-11e7-a796-01c1f26178a4'
};
module.exports = CHECKSUM;

View file

@ -0,0 +1,6 @@
var ScrollFactor = {
scrollFactorX: 1.0,
scrollFactorY: 1.0,
};
module.exports = ScrollFactor;

View file

@ -11,6 +11,7 @@ module.exports = {
Origin: require('./Origin'),
RenderTarget: require('./RenderTarget'),
ScaleMode: require('./ScaleMode'),
ScrollFactor: require('./ScrollFactor'),
Size: require('./Size'),
Texture: require('./Texture'),
ToJSON: require('./ToJSON'),

View file

@ -16,6 +16,7 @@ var DynamicBitmapText = new Class({
Components.Texture,
Components.Transform,
Components.Visible,
Components.ScrollFactor,
Render
],

View file

@ -12,8 +12,8 @@ var DynamicBitmapTextCanvasRenderer = function (renderer, src, interpolationPerc
var displayCallback = src.displayCallback;
var cameraScrollX = camera.scrollX;
var cameraScrollY = camera.scrollY;
var cameraScrollX = camera.scrollX * src.scrollFactorX;
var cameraScrollY = camera.scrollY * src.scrollFactorY;
var chars = src.fontData.chars;
var lineHeight = src.fontData.lineHeight;

View file

@ -11,8 +11,8 @@ var DynamicBitmapTextWebGLRenderer = function (renderer, gameObject, interpolati
var displayCallback = gameObject.displayCallback;
var textureFrame = gameObject.frame;
var cameraScrollX = camera.scrollX;
var cameraScrollY = camera.scrollY;
var cameraScrollX = camera.scrollX * gameObject.scrollFactorX;
var cameraScrollY = camera.scrollY * gameObject.scrollFactorY;
var text = gameObject.text;
var textLength = text.length;
var chars = gameObject.fontData.chars;

View file

@ -19,6 +19,7 @@ var BitmapText = new Class({
Components.Texture,
Components.Transform,
Components.Visible,
Components.ScrollFactor,
Render
],

View file

@ -10,8 +10,8 @@ var BitmapTextCanvasRenderer = function (renderer, src, interpolationPercentage,
var textureFrame = src.frame;
var cameraScrollX = camera.scrollX;
var cameraScrollY = camera.scrollY;
var cameraScrollX = camera.scrollX * src.scrollFactorX;
var cameraScrollY = camera.scrollY * src.scrollFactorY;
var chars = src.fontData.chars;
var lineHeight = src.fontData.lineHeight;

View file

@ -9,8 +9,8 @@ var BitmapTextWebGLRenderer = function (renderer, gameObject, interpolationPerce
}
var textureFrame = gameObject.frame;
var cameraScrollX = camera.scrollX;
var cameraScrollY = camera.scrollY;
var cameraScrollX = camera.scrollX * gameObject.scrollFactorX;
var cameraScrollY = camera.scrollY * gameObject.scrollFactorY;
var text = gameObject.text;
var textLength = text.length;
var chars = gameObject.fontData.chars;

View file

@ -36,6 +36,7 @@ var Blitter = new Class({
Components.Texture,
Components.Transform,
Components.Visible,
Components.ScrollFactor,
BlitterRender
],

View file

@ -14,8 +14,8 @@ var BlitterWebGLRenderer = function (renderer, src, interpolationPercentage, cam
var d = cameraMatrix[3];
var e = cameraMatrix[4];
var f = cameraMatrix[5];
var cameraScrollX = camera.scrollX;
var cameraScrollY = camera.scrollY;
var cameraScrollX = camera.scrollX * src.scrollFactorX;
var cameraScrollY = camera.scrollY * src.scrollFactorY;
var renderTarget = src.renderTarget;
// Render bobs

View file

@ -23,6 +23,7 @@ var EffectLayer = new Class({
Components.Size,
Components.Transform,
Components.Visible,
Components.ScrollFactor,
Render
],

View file

@ -18,6 +18,7 @@ var Graphics = new Class({
Components.Transform,
Components.RenderTarget,
Components.Visible,
Components.ScrollFactor,
Render
],

View file

@ -8,8 +8,8 @@ var GraphicsCanvasRenderer = function (renderer, src, interpolationPercentage, c
return;
}
var cameraScrollX = camera.scrollX;
var cameraScrollY = camera.scrollY;
var cameraScrollX = camera.scrollX * src.scrollFactorX;
var cameraScrollY = camera.scrollY * src.scrollFactorY;
var srcX = src.x;
var srcY = src.y;
var srcScaleX = src.scaleX;

View file

@ -38,8 +38,8 @@ var GraphicsWebGLRenderer = function (renderer, gameObject, interpolationPercent
var vertexBufferF32 = vertexDataBuffer.floatView;
var vertexBufferU32 = vertexDataBuffer.uintView;
var vertexOffset = 0;
var cameraScrollX = camera.scrollX;
var cameraScrollY = camera.scrollY;
var cameraScrollX = camera.scrollX * gameObject.scrollFactorX;
var cameraScrollY = camera.scrollY * gameObject.scrollFactorY;
const srcX = gameObject.x - cameraScrollX;
const srcY = gameObject.y - cameraScrollY;
const srcScaleX = gameObject.scaleX;

View file

@ -20,6 +20,7 @@ var Image = new Class({
Components.Texture,
Components.Transform,
Components.Visible,
Components.ScrollFactor,
ImageRender
],

View file

@ -20,6 +20,7 @@ var Mesh = new Class({
Components.Texture,
Components.Transform,
Components.Visible,
Components.ScrollFactor,
MeshRender
],

View file

@ -26,6 +26,7 @@ var RenderPass = new Class({
Components.Size,
Components.Transform,
Components.Visible,
Components.ScrollFactor,
Render
],

View file

@ -20,6 +20,7 @@ var Sprite = new Class({
Components.Texture,
Components.Transform,
Components.Visible,
Components.ScrollFactor,
SpriteRender
],

View file

@ -21,6 +21,7 @@ var Text = new Class({
Components.Transform,
Components.Visible,
Components.Flip,
Components.ScrollFactor,
TextRender
],

View file

@ -30,7 +30,7 @@ var TextCanvasRenderer = function (renderer, src, interpolationPercentage, camer
var canvas = src.canvas;
ctx.save();
ctx.translate(src.x - camera.scrollX, src.y - camera.scrollY);
ctx.translate(src.x - camera.scrollX * src.scrollFactorX, src.y - camera.scrollY * src.scrollFactorY);
ctx.rotate(src.rotation);
ctx.scale(src.scaleX, src.scaleY);
ctx.translate(canvas.width * (src.flipX ? 1 : 0), canvas.height * (src.flipY ? 1 : 0));

View file

@ -1,14 +1,36 @@
function Tile(properties)
{
this.index = properties.index;
this.id = properties.id;
this.x = properties.x;
this.y = properties.y;
this.width = properties.width;
this.height = properties.height;
this.frame = properties.frame;
this.alpha = 1.0;
this.frameX = properties.frameX;
this.frameY = properties.frameY;
this.frameWidth = properties.frameWidth;
this.frameHeight = properties.frameHeight;
this.alpha = 1.0;
this.tint = 0xFFFFFF;
this.visible = false;
this.visible = true;
this.textureWidth = properties.textureWidth;
this.textureHeight = properties.textureHeight;
}
Tile.prototype.setId = function (id)
{
var tileId = this.id = id;
var tileWidth = this.width;
var tileHeight = this.height;
var setWidth = this.textureWidth / tileWidth;
var halfTileWidth = (tileWidth) * 0.5;
var halfTileHeight = (tileHeight) * 0.5;
var rectx = (((tileId % setWidth)|0) * tileWidth) + halfTileWidth;
var recty = (((tileId / setWidth)|0) * tileHeight) + halfTileHeight;
this.frameX = rectx;
this.frameY = recty;
};
module.exports = Tile;

View file

@ -21,6 +21,7 @@ var Tilemap = new Class({
Components.Texture,
Components.Transform,
Components.Visible,
Components.ScrollFactor,
TilemapRender
],
@ -30,7 +31,7 @@ var Tilemap = new Class({
{
GameObject.call(this, state, 'Tilemap');
this.mapData = mapData;
this.mapData = mapData !== null ? new Uint32Array(mapData) : new Uint32Array(mapWidth * mapHeight);
this.tileWidth = tileWidth;
this.tileHeight = tileHeight;
this.mapWidth = mapWidth;
@ -45,6 +46,16 @@ var Tilemap = new Class({
this.buildTilemap();
},
getTotalTileCount: function ()
{
return this.tileArray.length;
},
getVisibleTileCount: function (camera)
{
return this.cull(camera).length;
},
buildTilemap: function ()
{
var tileArray = this.tileArray;
@ -65,26 +76,89 @@ var Tilemap = new Class({
for (var x = 0; x < mapWidth; ++x)
{
var tileId = mapData[y * mapWidth + x];
var rectx = ((tileId % setWidth)|0) * tileWidth;
var recty = ((tileId / setWidth)|0) * tileHeight;
var halfTileWidth = (tileWidth) * 0.5;
var halfTileHeight = (tileHeight) * 0.5;
var rectx = (((tileId % setWidth)|0) * tileWidth) + halfTileWidth;
var recty = (((tileId / setWidth)|0) * tileHeight) + halfTileHeight;
var tx = x * tileWidth;
var ty = y * tileHeight;
tileArray.push(new Tile({
index: x + y,
id: tileId,
x: tx,
y: ty,
width: tileWidth,
height: tileHeight,
frame: frame
frameX: rectx,
frameY: recty,
frameWidth: tileWidth,
frameHeight: tileHeight,
textureWidth: width,
textureHeight: height
}));
}
}
},
cull: function (rect)
cull: function (camera)
{
/* implement tilemap culling */
var culledTiles = this.culledTiles;
var tiles = this.tileArray;
var length = tiles.length;
var scrollX = camera.scrollX * this.scrollFactorX;
var scrollY = camera.scrollY * this.scrollFactorY;
var cameraW = camera.width;
var cameraH = camera.height;
culledTiles.length = 0;
for (var index = 0; index < length; ++index)
{
var tile = tiles[index];
var tileX = tile.x - scrollX;
var tileY = tile.y - scrollY;
var tileW = tile.width;
var tileH = tile.height;
var cullW = cameraW + tileW;
var cullH = cameraH + tileH;
if (tile.visible &&
tileX > -tileH && tileY > -tileW &&
tileX < cullW && tileY < cullH)
{
culledTiles.push(tile);
}
}
return culledTiles;
},
forEach: function (callback)
{
this.tileArray.forEach(callback);
},
getTileAt: function (x, y)
{
var ix = (x|0);
var iy = (y|0);
var tiles = this.tileArray;
var index = iy * this.mapWidth + ix;
if (index < tiles.length)
{
return tiles[index];
}
return null;
},
getTileAtIndex: function (index)
{
var tiles = this.tileArray;
if (index < tiles.length)
{
return tiles[index];
}
return null;
}
});

View file

@ -5,14 +5,34 @@ var TilemapWebGLRenderer = function (renderer, gameObject, interpolationPercenta
return;
}
var renderTiles = gameObject.tileArray;
this.cull(camera);
var renderTiles = gameObject.culledTiles;
var length = renderTiles.length;
var batch = renderer.spriteBatch;
var texture = gameObject.texture.source[0].glTexture;
var textureWidth = texture.width;
var textureHeight = texture.height;
var renderTarget = gameObject.renderTarget;
var scrollFactorX = gameObject.scrollFactorX;
var scrollFactorY = gameObject.scrollFactorY;
var alpha = gameObject.alpha;
var x = gameObject.x;
var y = gameObject.y;
for (var index = 0; index < length; ++index)
{
var tile = renderTiles[index];
batch.addTileTextureRect(
texture,
x + tile.x, y + tile.y, tile.width, tile.height, alpha * tile.alpha, tile.tint,
scrollFactorX, scrollFactorY,
textureWidth, textureHeight,
tile.frameX, tile.frameY, tile.frameWidth, tile.frameHeight,
camera,
renderTarget
);
}
};
module.exports = TilemapWebGLRenderer;

View file

@ -21,6 +21,7 @@ var StaticTilemap = new Class({
Components.Texture,
Components.Transform,
Components.Visible,
Components.ScrollFactor,
StaticTilemapRender
],
@ -42,8 +43,6 @@ var StaticTilemap = new Class({
this.mapHeight = mapHeight;
this.dirty = true;
this.vertexCount = 0;
this.scrollFactorX = 1.0;
this.scrollFactorY = 1.0;
this.setTexture(texture, frame);
this.setPosition(x, y);
this.setSizeToFrame();

View file

@ -11,7 +11,7 @@ var StaticTilemapWebGLRenderer = function (renderer, src, interpolationPercentag
renderer.setRenderer(gameObject.tilemapRenderer, frame.texture.source[frame.sourceIndex].glTexture, gameObject.renderTarget);
gameObject.tilemapRenderer.bind();
gameObject.upload(camera.scrollX, camera.scrollY);
gameObject.upload(camera.scrollX * src.scrollFactorX, camera.scrollY * src.scrollFactorY);
gameObject.vbo.bind();
gl.drawArrays(gl.TRIANGLES, 0, gameObject.vertexCount);
};

View file

@ -21,6 +21,7 @@ var TileSprite = new Class({
Components.Texture,
Components.Transform,
Components.Visible,
Components.ScrollFactor,
TileSpriteRender
],

View file

@ -37,7 +37,7 @@ var TileSpriteCanvasRenderer = function (renderer, src, interpolationPercentage,
ctx.save();
ctx.translate(dx, dy);
ctx.translate(src.x - camera.scrollX, src.y - camera.scrollY);
ctx.translate(src.x - camera.scrollX * src.scrollFactorX, src.y - camera.scrollY * src.scrollFactorY);
ctx.fillStyle = src.canvasPattern;
ctx.translate(-this.tilePositionX, -this.tilePositionY);
ctx.fillRect(this.tilePositionX, this.tilePositionY, src.width, src.height);

View file

@ -13,6 +13,7 @@ var Zone = new Class({
Components.ScaleMode,
Components.Size,
Components.Transform,
Components.ScrollFactor,
Components.Visible
],

View file

@ -174,8 +174,8 @@ EffectRenderer.prototype = {
var vertexOffset = 0;
var width = textureWidth * (gameObject.flipX ? -1 : 1);
var height = textureHeight * (gameObject.flipY ? -1 : 1);
var translateX = gameObject.x - camera.scrollX;
var translateY = gameObject.y - camera.scrollY;
var translateX = gameObject.x - camera.scrollX * gameObject.scrollFactorX;
var translateY = gameObject.y - camera.scrollY * gameObject.scrollFactorY;
var scaleX = gameObject.scaleX;
var scaleY = gameObject.scaleY;
var rotation = -gameObject.rotation;

View file

@ -101,7 +101,7 @@ SpriteBatch.prototype = {
shouldFlush: function ()
{
if (this.drawIndexed != this.lastDrawIndexed || this.lastDrawingMesh !== this.drawingMesh)
if (this.drawIndexed != this.lastDrawIndexed || this.lastDrawingMesh !== this.drawingMesh || this.isFull())
{
this.lastDrawIndexed = this.drawIndexed;
this.lastDrawingMesh = this.drawingMesh;
@ -215,8 +215,8 @@ SpriteBatch.prototype = {
var vertexBufferObjectF32 = vertexDataBuffer.floatView;
var vertexBufferObjectU32 = vertexDataBuffer.uintView;
var vertexOffset = 0;
var translateX = gameObject.x - camera.scrollX;
var translateY = gameObject.y - camera.scrollY;
var translateX = gameObject.x - camera.scrollX * gameObject.scrollFactorX;
var translateY = gameObject.y - camera.scrollY * gameObject.scrollFactorY;
var scaleX = gameObject.scaleX;
var scaleY = gameObject.scaleY;
var rotation = -gameObject.rotation;
@ -298,8 +298,8 @@ SpriteBatch.prototype = {
var vertexBufferObjectF32 = vertexDataBuffer.floatView;
var vertexBufferObjectU32 = vertexDataBuffer.uintView;
var vertexOffset = 0;
var translateX = gameObject.x - camera.scrollX;
var translateY = gameObject.y - camera.scrollY;
var translateX = gameObject.x - camera.scrollX * gameObject.scrollFactorX;
var translateY = gameObject.y - camera.scrollY * gameObject.scrollFactorY;
var scaleX = gameObject.scaleX;
var scaleY = gameObject.scaleY;
var rotation = -gameObject.rotation;
@ -361,6 +361,77 @@ SpriteBatch.prototype = {
}
},
addTileTextureRect: function (texture, x, y, width, height, alpha, tint, scrollFactorX, scrollFactorY, textureWidth, textureHeight, rectX, rectY, rectW, rectH, camera, renderTarget)
{
var vertexDataBuffer = this.vertexDataBuffer;
var vertexBufferObjectF32 = vertexDataBuffer.floatView;
var vertexBufferObjectU32 = vertexDataBuffer.uintView;
var vertexOffset = 0;
var xw = x + width;
var yh = y + height;
var cameraMatrix = camera.matrix.matrix;
var mva, mvb, mvc, mvd, mve, mvf, tx0, ty0, tx1, ty1, tx2, ty2, tx3, ty3;
var sra, srb, src, srd, sre, srf, cma, cmb, cmc, cmd, cme, cmf;
var halfTileWidth = (width) * 0.5;
var halfTileHeight = (height) * 0.5;
var u0 = (rectX - (halfTileWidth - 0.5)) / textureWidth;
var v0 = (rectY - (halfTileHeight - 0.5)) / textureHeight;
var u1 = (rectX + (halfTileWidth - 0.5)) / textureWidth;
var v1 = (rectY + (halfTileHeight - 0.5)) / textureHeight;
var scrollX = camera.scrollX * scrollFactorX;
var scrollY = camera.scrollY * scrollFactorY;
mva = cameraMatrix[0];
mvb = cameraMatrix[1];
mvc = cameraMatrix[2];
mvd = cameraMatrix[3];
mve = cameraMatrix[4];
mvf = cameraMatrix[5];
tx0 = (x * mva + y * mvc + mve) - scrollX;
ty0 = (x * mvb + y * mvd + mvf) - scrollY;
tx1 = (x * mva + yh * mvc + mve) - scrollX;
ty1 = (x * mvb + yh * mvd + mvf) - scrollY;
tx2 = (xw * mva + yh * mvc + mve) - scrollX;
ty2 = (xw * mvb + yh * mvd + mvf) - scrollY;
tx3 = (xw * mva + y * mvc + mve) - scrollX;
ty3 = (xw * mvb + y * mvd + mvf) - scrollY;
this.manager.setRenderer(this, texture, renderTarget);
this.drawIndexed = true;
this.drawingMesh = false;
this.elementCount += 6;
vertexOffset = vertexDataBuffer.allocate(24);
vertexBufferObjectF32[vertexOffset++] = tx0;
vertexBufferObjectF32[vertexOffset++] = ty0;
vertexBufferObjectF32[vertexOffset++] = u0;
vertexBufferObjectF32[vertexOffset++] = v0;
vertexBufferObjectU32[vertexOffset++] = tint;
vertexBufferObjectF32[vertexOffset++] = alpha;
vertexBufferObjectF32[vertexOffset++] = tx1;
vertexBufferObjectF32[vertexOffset++] = ty1;
vertexBufferObjectF32[vertexOffset++] = u0;
vertexBufferObjectF32[vertexOffset++] = v1;
vertexBufferObjectU32[vertexOffset++] = tint;
vertexBufferObjectF32[vertexOffset++] = alpha;
vertexBufferObjectF32[vertexOffset++] = tx2;
vertexBufferObjectF32[vertexOffset++] = ty2;
vertexBufferObjectF32[vertexOffset++] = u1;
vertexBufferObjectF32[vertexOffset++] = v1;
vertexBufferObjectU32[vertexOffset++] = tint;
vertexBufferObjectF32[vertexOffset++] = alpha;
vertexBufferObjectF32[vertexOffset++] = tx3;
vertexBufferObjectF32[vertexOffset++] = ty3;
vertexBufferObjectF32[vertexOffset++] = u1;
vertexBufferObjectF32[vertexOffset++] = v0;
vertexBufferObjectU32[vertexOffset++] = tint;
vertexBufferObjectF32[vertexOffset++] = alpha;
},
addSpriteTexture: function (gameObject, camera, texture, textureWidth, textureHeight)
{
var tempMatrix = this.tempMatrix;
@ -371,8 +442,8 @@ SpriteBatch.prototype = {
var vertexOffset = 0;
var width = textureWidth * (gameObject.flipX ? -1 : 1);
var height = textureHeight * (gameObject.flipY ? -1 : 1);
var translateX = gameObject.x - camera.scrollX;
var translateY = gameObject.y - camera.scrollY;
var translateX = gameObject.x - camera.scrollX * gameObject.scrollFactorX;
var translateY = gameObject.y - camera.scrollY * gameObject.scrollFactorY;
var scaleX = gameObject.scaleX;
var scaleY = gameObject.scaleY;
var rotation = -gameObject.rotation;
@ -468,8 +539,8 @@ SpriteBatch.prototype = {
var uvs = frame.uvs;
var width = frame.width * (flipX ? -1 : 1);
var height = frame.height * (flipY ? -1 : 1);
var translateX = gameObject.x - camera.scrollX;
var translateY = gameObject.y - camera.scrollY;
var translateX = gameObject.x - camera.scrollX * gameObject.scrollFactorX;
var translateY = gameObject.y - camera.scrollY * gameObject.scrollFactorY;
var scaleX = gameObject.scaleX;
var scaleY = gameObject.scaleY;
var rotation = -gameObject.rotation;

View file

@ -187,8 +187,8 @@ TileBatch.prototype = {
var vertexOffset = 0;
var width = gameObject.width * (gameObject.flipX ? -1 : 1);
var height = gameObject.height * (gameObject.flipY ? -1 : 1);
var translateX = gameObject.x - camera.scrollX;
var translateY = gameObject.y - camera.scrollY;
var translateX = gameObject.x - camera.scrollX * gameObject.scrollFactorX;
var translateY = gameObject.y - camera.scrollY * gameObject.scrollFactorY;
var scaleX = gameObject.scaleX;
var scaleY = gameObject.scaleY;
var rotation = -gameObject.rotation;