var Class = require('../../utils/Class'); var Components = require('../../gameobjects/components'); var GameEvents = require('../../core/events'); var GameObject = require('../../gameobjects/GameObject'); var ModelViewProjection = require('../../renderer/webgl/pipelines/components/ModelViewProjection'); var StaticTilemapLayerRender = require('./StaticTilemapLayerRender'); var TilemapComponents = require('../components'); var TransformMatrix = require('../../gameobjects/components/TransformMatrix'); var Utils = require('../../renderer/webgl/Utils'); var Vector2 = require('../../math/Vector2'); var StaticTilemapLayer = new Class({ Extends: GameObject, Mixins: [Components.Alpha, Components.BlendMode, Components.ComputedSize, Components.Depth, Components.Flip, Components.GetBounds, Components.Origin, Components.Pipeline, Components.Transform, Components.Visible, Components.ScrollFactor, StaticTilemapLayerRender, ModelViewProjection] , initialize: function StaticTilemapLayer(scene, tilemap, layerIndex, tileset, x, y){ GameObject.call(this, scene, 'StaticTilemapLayer'); this.isTilemap = true ; this.tilemap = tilemap; this.layerIndex = layerIndex; this.layer = tilemap.layers[layerIndex]; this.layer.tilemapLayer = this; this.tileset = [] ; this.culledTiles = [] ; this.skipCull = false ; this.isoCullDistances = new Vector2(1, 1); this.tilesDrawn = 0; this.tilesTotal = this.layer.width * this.layer.height; this.cullPaddingX = 1; this.cullPaddingY = 1; this.cullCallback = TilemapComponents.GetCullTilesFunction(this.layer.orientation); this.renderer = scene.sys.game.renderer; this.vertexBuffer = [] ; this.bufferData = [] ; this.vertexViewF32 = [] ; this.vertexViewU32 = [] ; this.dirty = [] ; this.vertexCount = [] ; this._renderOrder = 0; this._tempMatrix = new TransformMatrix(); this.gidMap = [] ; this.setTilesets(tileset); this.setAlpha(this.layer.alpha); this.setPosition(x, y); this.setOrigin(); this.setSize(tilemap.tileWidth * this.layer.width, tilemap.tileHeight * this.layer.height); this.updateVBOData(); this.initPipeline(); this.mvpInit(); scene.sys.game.events.on(GameEvents.CONTEXT_RESTORED, function (){ this.updateVBOData(); } , this); } , setTilesets: function (tilesets){ var gidMap = [] ; var setList = [] ; var map = this.tilemap; if (!Array.isArray(tilesets)) { tilesets = [tilesets] ; } for (var i = 0; i < (_AN_Read_length('length', tilesets)); i++ ){ var tileset = tilesets[i]; if (typeof tileset === 'string') { tileset = map.getTileset(tileset); } if (tileset) { setList.push(tileset); var s = tileset.firstgid; for (var t = 0; t < tileset.total; t++ ){ gidMap[s + t] = tileset; } } } this.gidMap = gidMap; this.tileset = setList; } , updateVBOData: function (){ for (var i = 0; i < (_AN_Read_length('length', this.tileset)); i++ ){ this.dirty[i] = true ; this.vertexCount[i] = 0; this.vertexBuffer[i] = null ; this.bufferData[i] = null ; this.vertexViewF32[i] = null ; this.vertexViewU32[i] = null ; } return this; } , upload: function (camera, tilesetIndex){ var pipeline = this.pipeline; var renderer = this.renderer; var gl = renderer.gl; var vertexBuffer = this.vertexBuffer[tilesetIndex]; var bufferData = this.bufferData[tilesetIndex]; if (!this.dirty[tilesetIndex] && vertexBuffer) { renderer.setVertexBuffer(vertexBuffer); pipeline.setAttribPointers(); gl.bufferSubData(gl.ARRAY_BUFFER, 0, bufferData); return this; } var layer = this.layer; var tileset = this.tileset[tilesetIndex]; var mapWidth = layer.width; var mapHeight = layer.height; var width = tileset.image.source[0].width; var height = tileset.image.source[0].height; var mapData = layer.data; var tile; var row; var col; var renderOrder = this._renderOrder; var minTileIndex = tileset.firstgid; var maxTileIndex = tileset.firstgid + tileset.total; var vOffset = -1; var bufferSize = (mapWidth * mapHeight) * pipeline.vertexSize * 6; this.vertexCount[tilesetIndex] = 0; if (bufferData === null ) { bufferData = new ArrayBuffer(bufferSize); this.bufferData[tilesetIndex] = bufferData; this.vertexViewF32[tilesetIndex] = new Float32Array(bufferData); this.vertexViewU32[tilesetIndex] = new Uint32Array(bufferData); } if (renderOrder === 0) { for (row = 0; row < mapHeight; row++ ){ for (col = 0; col < mapWidth; col++ ){ tile = mapData[row][col]; if (!tile || tile.index < minTileIndex || tile.index > maxTileIndex || !tile.visible) { continue ; } vOffset = this.batchTile(vOffset, tile, tileset, width, height, camera, tilesetIndex); } } } else if (renderOrder === 1) { for (row = 0; row < mapHeight; row++ ){ for (col = mapWidth - 1; col >= 0; col-- ){ tile = mapData[row][col]; if (!tile || tile.index < minTileIndex || tile.index > maxTileIndex || !tile.visible) { continue ; } vOffset = this.batchTile(vOffset, tile, tileset, width, height, camera, tilesetIndex); } } } else if (renderOrder === 2) { for (row = mapHeight - 1; row >= 0; row-- ){ for (col = 0; col < mapWidth; col++ ){ tile = mapData[row][col]; if (!tile || tile.index < minTileIndex || tile.index > maxTileIndex || !tile.visible) { continue ; } vOffset = this.batchTile(vOffset, tile, tileset, width, height, camera, tilesetIndex); } } } else if (renderOrder === 3) { for (row = mapHeight - 1; row >= 0; row-- ){ for (col = mapWidth - 1; col >= 0; col-- ){ tile = mapData[row][col]; if (!tile || tile.index < minTileIndex || tile.index > maxTileIndex || !tile.visible) { continue ; } vOffset = this.batchTile(vOffset, tile, tileset, width, height, camera, tilesetIndex); } } } this.dirty[tilesetIndex] = false ; if (vertexBuffer === null ) { vertexBuffer = renderer.createVertexBuffer(bufferData, gl.STATIC_DRAW); this.vertexBuffer[tilesetIndex] = vertexBuffer; } renderer.setVertexBuffer(vertexBuffer); pipeline.setAttribPointers(); gl.bufferSubData(gl.ARRAY_BUFFER, 0, bufferData); return this; } , batchTile: function (vOffset, tile, tileset, width, height, camera, tilesetIndex){ var texCoords = tileset.getTileTextureCoordinates(tile.index); if (!texCoords) { return vOffset; } var tileWidth = tileset.tileWidth; var tileHeight = tileset.tileHeight; var halfTileWidth = tileWidth / 2; var halfTileHeight = tileHeight / 2; var u0 = texCoords.x / width; var v0 = texCoords.y / height; var u1 = (texCoords.x + tileWidth) / width; var v1 = (texCoords.y + tileHeight) / height; var matrix = this._tempMatrix; var x = - halfTileWidth; var y = - halfTileHeight; if (tile.flipX) { tileWidth *= -1; x += tileset.tileWidth; } if (tile.flipY) { tileHeight *= -1; y += tileset.tileHeight; } var xw = x + tileWidth; var yh = y + tileHeight; matrix.applyITRS(halfTileWidth + tile.pixelX, halfTileHeight + tile.pixelY, tile.rotation, 1, 1); var tint = Utils.getTintAppendFloatAlpha(16777215, camera.alpha * this.alpha * tile.alpha); var tx0 = matrix.getX(x, y); var ty0 = matrix.getY(x, y); var tx1 = matrix.getX(x, yh); var ty1 = matrix.getY(x, yh); var tx2 = matrix.getX(xw, yh); var ty2 = matrix.getY(xw, yh); var tx3 = matrix.getX(xw, y); var ty3 = matrix.getY(xw, y); if (camera.roundPixels) { tx0 = Math.round(tx0); ty0 = Math.round(ty0); tx1 = Math.round(tx1); ty1 = Math.round(ty1); tx2 = Math.round(tx2); ty2 = Math.round(ty2); tx3 = Math.round(tx3); ty3 = Math.round(ty3); } var vertexViewF32 = this.vertexViewF32[tilesetIndex]; var vertexViewU32 = this.vertexViewU32[tilesetIndex]; vertexViewF32[++vOffset] = tx0; vertexViewF32[++vOffset] = ty0; vertexViewF32[++vOffset] = u0; vertexViewF32[++vOffset] = v0; vertexViewF32[++vOffset] = 0; vertexViewF32[++vOffset] = 0; vertexViewU32[++vOffset] = tint; vertexViewF32[++vOffset] = tx1; vertexViewF32[++vOffset] = ty1; vertexViewF32[++vOffset] = u0; vertexViewF32[++vOffset] = v1; vertexViewF32[++vOffset] = 0; vertexViewF32[++vOffset] = 0; vertexViewU32[++vOffset] = tint; vertexViewF32[++vOffset] = tx2; vertexViewF32[++vOffset] = ty2; vertexViewF32[++vOffset] = u1; vertexViewF32[++vOffset] = v1; vertexViewF32[++vOffset] = 0; vertexViewF32[++vOffset] = 0; vertexViewU32[++vOffset] = tint; vertexViewF32[++vOffset] = tx0; vertexViewF32[++vOffset] = ty0; vertexViewF32[++vOffset] = u0; vertexViewF32[++vOffset] = v0; vertexViewF32[++vOffset] = 0; vertexViewF32[++vOffset] = 0; vertexViewU32[++vOffset] = tint; vertexViewF32[++vOffset] = tx2; vertexViewF32[++vOffset] = ty2; vertexViewF32[++vOffset] = u1; vertexViewF32[++vOffset] = v1; vertexViewF32[++vOffset] = 0; vertexViewF32[++vOffset] = 0; vertexViewU32[++vOffset] = tint; vertexViewF32[++vOffset] = tx3; vertexViewF32[++vOffset] = ty3; vertexViewF32[++vOffset] = u1; vertexViewF32[++vOffset] = v0; vertexViewF32[++vOffset] = 0; vertexViewF32[++vOffset] = 0; vertexViewU32[++vOffset] = tint; this.vertexCount[tilesetIndex] += 6; return vOffset; } , setRenderOrder: function (renderOrder){ var orders = ['right-down', 'left-down', 'right-up', 'left-up'] ; if (typeof renderOrder === 'string') { renderOrder = orders.indexOf(renderOrder); } if (renderOrder >= 0 && renderOrder < 4) { this._renderOrder = renderOrder; for (var i = 0; i < (_AN_Read_length('length', this.tileset)); i++ ){ this.dirty[i] = true ; } } return this; } , calculateFacesAt: function (tileX, tileY){ TilemapComponents.CalculateFacesAt(tileX, tileY, this.layer); return this; } , calculateFacesWithin: function (tileX, tileY, width, height){ TilemapComponents.CalculateFacesWithin(tileX, tileY, width, height, this.layer); return this; } , createFromTiles: function (indexes, replacements, spriteConfig, scene, camera){ return TilemapComponents.CreateFromTiles(indexes, replacements, spriteConfig, scene, camera, this.layer); } , cull: function (camera){ return this.cullCallback(this.layer, camera, this.culledTiles); } , setSkipCull: function (value){ if (value === undefined) { value = true ; } this.skipCull = value; return this; } , setCullPadding: function (paddingX, paddingY){ if (paddingX === undefined) { paddingX = 1; } if (paddingY === undefined) { paddingY = 1; } this.cullPaddingX = paddingX; this.cullPaddingY = paddingY; return this; } , findByIndex: function (findIndex, skip, reverse){ return TilemapComponents.FindByIndex(findIndex, skip, reverse, this.layer); } , findTile: function (callback, context, tileX, tileY, width, height, filteringOptions){ return TilemapComponents.FindTile(callback, context, tileX, tileY, width, height, filteringOptions, this.layer); } , filterTiles: function (callback, context, tileX, tileY, width, height, filteringOptions){ return TilemapComponents.FilterTiles(callback, context, tileX, tileY, width, height, filteringOptions, this.layer); } , forEachTile: function (callback, context, tileX, tileY, width, height, filteringOptions){ TilemapComponents.ForEachTile(callback, context, tileX, tileY, width, height, filteringOptions, this.layer); return this; } , getTileAt: function (tileX, tileY, nonNull){ return TilemapComponents.GetTileAt(tileX, tileY, nonNull, this.layer); } , getTileAtWorldXY: function (worldX, worldY, nonNull, camera){ return TilemapComponents.GetTileAtWorldXY(worldX, worldY, nonNull, camera, this.layer); } , getTilesWithin: function (tileX, tileY, width, height, filteringOptions){ return TilemapComponents.GetTilesWithin(tileX, tileY, width, height, filteringOptions, this.layer); } , getTilesWithinWorldXY: function (worldX, worldY, width, height, filteringOptions, camera){ return TilemapComponents.GetTilesWithinWorldXY(worldX, worldY, width, height, filteringOptions, camera, this.layer); } , getTilesWithinShape: function (shape, filteringOptions, camera){ return TilemapComponents.GetTilesWithinShape(shape, filteringOptions, camera, this.layer); } , hasTileAt: function (tileX, tileY){ return TilemapComponents.HasTileAt(tileX, tileY, this.layer); } , hasTileAtWorldXY: function (worldX, worldY, camera){ return TilemapComponents.HasTileAtWorldXY(worldX, worldY, camera, this.layer); } , renderDebug: function (graphics, styleConfig){ TilemapComponents.RenderDebug(graphics, styleConfig, this.layer); return this; } , setCollision: function (indexes, collides, recalculateFaces, updateLayer){ TilemapComponents.SetCollision(indexes, collides, recalculateFaces, this.layer, updateLayer); return this; } , setCollisionBetween: function (start, stop, collides, recalculateFaces){ TilemapComponents.SetCollisionBetween(start, stop, collides, recalculateFaces, this.layer); return this; } , setCollisionByProperty: function (properties, collides, recalculateFaces){ TilemapComponents.SetCollisionByProperty(properties, collides, recalculateFaces, this.layer); return this; } , setCollisionByExclusion: function (indexes, collides, recalculateFaces){ TilemapComponents.SetCollisionByExclusion(indexes, collides, recalculateFaces, this.layer); return this; } , setTileIndexCallback: function (indexes, callback, callbackContext){ TilemapComponents.SetTileIndexCallback(indexes, callback, callbackContext, this.layer); return this; } , setCollisionFromCollisionGroup: function (collides, recalculateFaces){ TilemapComponents.SetCollisionFromCollisionGroup(collides, recalculateFaces, this.layer); return this; } , setTileLocationCallback: function (tileX, tileY, width, height, callback, callbackContext){ TilemapComponents.SetTileLocationCallback(tileX, tileY, width, height, callback, callbackContext, this.layer); return this; } , tileToWorldX: function (tileX, camera){ return this.tilemap.tileToWorldX(tileX, camera, this.layer); } , tileToWorldY: function (tileY, camera){ return this.tilemap.tileToWorldY(tileY, camera, this.layer); } , tileToWorldXY: function (tileX, tileY, point, camera){ return this.tilemap.tileToWorldXY(tileX, tileY, point, camera, this.layer); } , worldToTileX: function (worldX, snapToFloor, camera){ return this.tilemap.worldToTileX(worldX, snapToFloor, camera, this.layer); } , worldToTileY: function (worldY, snapToFloor, camera){ return this.tilemap.worldToTileY(worldY, snapToFloor, camera, this.layer); } , worldToTileXY: function (worldX, worldY, snapToFloor, point, camera){ return this.tilemap.worldToTileXY(worldX, worldY, snapToFloor, point, camera, this.layer); } , destroy: function (removeFromTilemap){ if (removeFromTilemap === undefined) { removeFromTilemap = true ; } if (!this.tilemap) { return ; } if (this.layer.tilemapLayer === this) { this.layer.tilemapLayer = undefined; } if (removeFromTilemap) { this.tilemap.removeLayer(this); } this.tilemap = undefined; this.layer = undefined; this.culledTiles.length = 0; this.cullCallback = null ; for (var i = 0; i < (_AN_Read_length('length', this.tileset)); i++ ){ this.dirty[i] = true ; this.vertexCount[i] = 0; this.vertexBuffer[i] = null ; this.bufferData[i] = null ; this.vertexViewF32[i] = null ; this.vertexViewU32[i] = null ; } this.gidMap = [] ; this.tileset = [] ; GameObject.prototype.destroy.call(this); } } ); module.exports = StaticTilemapLayer;