2013-09-01 14:27:21 +00:00
|
|
|
/*
|
|
|
|
** tilemap.cpp
|
|
|
|
**
|
|
|
|
** This file is part of mkxp.
|
|
|
|
**
|
|
|
|
** Copyright (C) 2013 Jonas Kulla <Nyocurio@gmail.com>
|
|
|
|
**
|
|
|
|
** mkxp is free software: you can redistribute it and/or modify
|
|
|
|
** it under the terms of the GNU General Public License as published by
|
|
|
|
** the Free Software Foundation, either version 2 of the License, or
|
|
|
|
** (at your option) any later version.
|
|
|
|
**
|
|
|
|
** mkxp is distributed in the hope that it will be useful,
|
|
|
|
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
** GNU General Public License for more details.
|
|
|
|
**
|
|
|
|
** You should have received a copy of the GNU General Public License
|
|
|
|
** along with mkxp. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "tilemap.h"
|
|
|
|
|
|
|
|
#include "viewport.h"
|
|
|
|
#include "bitmap.h"
|
|
|
|
#include "table.h"
|
|
|
|
|
2013-10-09 10:30:33 +00:00
|
|
|
#include "sharedstate.h"
|
2013-09-01 14:27:21 +00:00
|
|
|
#include "glstate.h"
|
|
|
|
#include "gl-util.h"
|
2014-07-11 06:31:12 +00:00
|
|
|
#include "gl-meta.h"
|
2014-07-11 00:09:53 +00:00
|
|
|
#include "global-ibo.h"
|
2013-09-01 14:27:21 +00:00
|
|
|
#include "etc-internal.h"
|
|
|
|
#include "quadarray.h"
|
|
|
|
#include "texpool.h"
|
|
|
|
#include "quad.h"
|
2014-07-13 12:03:18 +00:00
|
|
|
#include "vertex.h"
|
Implement a new tileset atlas layout to allow for bigger tilesets
The atlas packing algorithm has been reworked to pack autotiles
and tileset very efficiently into a texture, splitting the tileset
in multiple ways and eliminating the previous duplication of image
data in the atlas across "frames". Animation, which these frames
were designed for, is now done via duplicated buffer frames,
ie. each animation frame has its own VBO and IBO data. This was
not done to save on VRAM (hardly less memory is used), but to
make place for the new atlas layout.
Thanks to this new layout, even with a max texture size of 2048,
one can use tilesets with up to 15000 height. Of course, such
a tileset couldn't be stored in a regular Bitmap to begin with,
which is why I also introduced a hack called "mega surfaces":
software surfaces stored in RAM and wrapped inside a Bitmap,
whose sole purpose is to be passed to a Tilemap as tilesets.
Various other minor changes and fixes are included.
2013-09-23 20:21:58 +00:00
|
|
|
#include "tileatlas.h"
|
2013-09-01 14:27:21 +00:00
|
|
|
|
2013-12-04 16:48:37 +00:00
|
|
|
#include <sigc++/connection.h>
|
2013-09-01 14:27:21 +00:00
|
|
|
|
|
|
|
#include <string.h>
|
|
|
|
#include <stdint.h>
|
2013-12-08 12:19:22 +00:00
|
|
|
#include <algorithm>
|
2013-12-26 19:18:33 +00:00
|
|
|
#include <vector>
|
2013-09-01 14:27:21 +00:00
|
|
|
|
2013-12-04 16:48:37 +00:00
|
|
|
#include <SDL_surface.h>
|
Implement a new tileset atlas layout to allow for bigger tilesets
The atlas packing algorithm has been reworked to pack autotiles
and tileset very efficiently into a texture, splitting the tileset
in multiple ways and eliminating the previous duplication of image
data in the atlas across "frames". Animation, which these frames
were designed for, is now done via duplicated buffer frames,
ie. each animation frame has its own VBO and IBO data. This was
not done to save on VRAM (hardly less memory is used), but to
make place for the new atlas layout.
Thanks to this new layout, even with a max texture size of 2048,
one can use tilesets with up to 15000 height. Of course, such
a tileset couldn't be stored in a regular Bitmap to begin with,
which is why I also introduced a hack called "mega surfaces":
software surfaces stored in RAM and wrapped inside a Bitmap,
whose sole purpose is to be passed to a Tilemap as tilesets.
Various other minor changes and fixes are included.
2013-09-23 20:21:58 +00:00
|
|
|
|
2013-09-01 14:27:21 +00:00
|
|
|
extern const StaticRect autotileRects[];
|
|
|
|
|
2013-12-26 19:18:33 +00:00
|
|
|
typedef std::vector<SVertex> SVVector;
|
2013-09-01 14:27:21 +00:00
|
|
|
|
|
|
|
static const int tilesetW = 8 * 32;
|
|
|
|
static const int autotileW = 3 * 32;
|
|
|
|
static const int autotileH = 4 * 32;
|
Implement a new tileset atlas layout to allow for bigger tilesets
The atlas packing algorithm has been reworked to pack autotiles
and tileset very efficiently into a texture, splitting the tileset
in multiple ways and eliminating the previous duplication of image
data in the atlas across "frames". Animation, which these frames
were designed for, is now done via duplicated buffer frames,
ie. each animation frame has its own VBO and IBO data. This was
not done to save on VRAM (hardly less memory is used), but to
make place for the new atlas layout.
Thanks to this new layout, even with a max texture size of 2048,
one can use tilesets with up to 15000 height. Of course, such
a tileset couldn't be stored in a regular Bitmap to begin with,
which is why I also introduced a hack called "mega surfaces":
software surfaces stored in RAM and wrapped inside a Bitmap,
whose sole purpose is to be passed to a Tilemap as tilesets.
Various other minor changes and fixes are included.
2013-09-23 20:21:58 +00:00
|
|
|
|
|
|
|
static const int autotileCount = 7;
|
|
|
|
|
|
|
|
static const int atAreaW = autotileW * 4;
|
|
|
|
static const int atAreaH = autotileH * autotileCount;
|
|
|
|
|
|
|
|
static const int tsLaneW = tilesetW / 2;
|
2013-09-01 14:27:21 +00:00
|
|
|
|
2014-07-10 23:07:18 +00:00
|
|
|
/* Map viewport size */
|
|
|
|
static const int viewpW = 21;
|
|
|
|
static const int viewpH = 16;
|
|
|
|
|
|
|
|
static const size_t scanrowsMax = viewpH + 5;
|
|
|
|
|
2013-09-01 14:27:21 +00:00
|
|
|
/* Vocabulary:
|
|
|
|
*
|
|
|
|
* Atlas: A texture containing both the tileset and all
|
|
|
|
* autotile images. This is so the entire tilemap can
|
|
|
|
* be drawn from one texture (for performance reasons).
|
|
|
|
* This means that we have to watch the 'modified' signals
|
|
|
|
* of all Bitmaps that make up the atlas, and update it
|
|
|
|
* as required during runtime.
|
Implement a new tileset atlas layout to allow for bigger tilesets
The atlas packing algorithm has been reworked to pack autotiles
and tileset very efficiently into a texture, splitting the tileset
in multiple ways and eliminating the previous duplication of image
data in the atlas across "frames". Animation, which these frames
were designed for, is now done via duplicated buffer frames,
ie. each animation frame has its own VBO and IBO data. This was
not done to save on VRAM (hardly less memory is used), but to
make place for the new atlas layout.
Thanks to this new layout, even with a max texture size of 2048,
one can use tilesets with up to 15000 height. Of course, such
a tileset couldn't be stored in a regular Bitmap to begin with,
which is why I also introduced a hack called "mega surfaces":
software surfaces stored in RAM and wrapped inside a Bitmap,
whose sole purpose is to be passed to a Tilemap as tilesets.
Various other minor changes and fixes are included.
2013-09-23 20:21:58 +00:00
|
|
|
* The atlas is tightly packed, with the autotiles located
|
|
|
|
* in the top left corener and the tileset image filing the
|
|
|
|
* remaining open space (below the autotiles as well as
|
|
|
|
* besides it). The tileset is vertically cut in half, where
|
|
|
|
* the first half fills available texture space, and then the
|
|
|
|
* other half (as if the right half was cut and pasted below
|
|
|
|
* the left half before fitting it all into the atlas).
|
|
|
|
* Internally these halves are called "tileset lanes".
|
Tilemap: Use vertex shader based autotile animation strategy
Previously, we would just stuff the entire tilemap vertex data
four times into the buffers, with only the autotile vertices
offset according to the animation frame. This meant we could
prepare the buffers once, and then just bind a different offset
for each animation frame without any shader changes, but it also
lead to a huge amount of data being duplicated (and blowing up
the buffer sizes).
The new method only requires one buffer, and instead animates by
recognizing vertices belonging to autotiles in a custom vertex
shader, which offsets them on the fly according to the animation
index.
With giant tilemaps, this method would turn out to be a little
less efficient, but considering the Tilemap is planned to be
rewritten to only hold the range of tiles visible on the screen
in its buffers, the on the fly offsetting will become neglient,
while at the same time the amount of data we have to send to the
GPU everytime the tilemap is updated is greatly reduced; so a
net win in the end.
2014-07-06 17:44:19 +00:00
|
|
|
* There is a 32 pixel wide empty buffer below the autotile
|
|
|
|
* area so the vertex shader can safely differentiate between
|
|
|
|
* autotile and tileset vertices (relevant for autotile animation).
|
Implement a new tileset atlas layout to allow for bigger tilesets
The atlas packing algorithm has been reworked to pack autotiles
and tileset very efficiently into a texture, splitting the tileset
in multiple ways and eliminating the previous duplication of image
data in the atlas across "frames". Animation, which these frames
were designed for, is now done via duplicated buffer frames,
ie. each animation frame has its own VBO and IBO data. This was
not done to save on VRAM (hardly less memory is used), but to
make place for the new atlas layout.
Thanks to this new layout, even with a max texture size of 2048,
one can use tilesets with up to 15000 height. Of course, such
a tileset couldn't be stored in a regular Bitmap to begin with,
which is why I also introduced a hack called "mega surfaces":
software surfaces stored in RAM and wrapped inside a Bitmap,
whose sole purpose is to be passed to a Tilemap as tilesets.
Various other minor changes and fixes are included.
2013-09-23 20:21:58 +00:00
|
|
|
*
|
|
|
|
* Tile atlas
|
|
|
|
* *-----------------------*--------------*
|
|
|
|
* | | | | | ¦ |
|
|
|
|
* | AT1 | AT1 | AT1 | AT1 | ¦ |
|
|
|
|
* | FR0 | FR1 | FR2 | FR3 | | ¦ | |
|
|
|
|
* |-----|-----|-----|-----| v ¦ v |
|
|
|
|
* | | | | | ¦ |
|
|
|
|
* | AT1 | | | | ¦ |
|
|
|
|
* | | | | | ¦ |
|
|
|
|
* |-----|-----|-----|-----| ¦ |
|
|
|
|
* |[...]| | | | ¦ |
|
|
|
|
* |-----|-----|-----|-----| ¦ |
|
|
|
|
* | | | | | | ¦ | |
|
|
|
|
* | AT7 | | | | v ¦ v |
|
|
|
|
* | | | | | ¦ |
|
|
|
|
* |-----|-----|-----|-----| ¦ |
|
Tilemap: Use vertex shader based autotile animation strategy
Previously, we would just stuff the entire tilemap vertex data
four times into the buffers, with only the autotile vertices
offset according to the animation frame. This meant we could
prepare the buffers once, and then just bind a different offset
for each animation frame without any shader changes, but it also
lead to a huge amount of data being duplicated (and blowing up
the buffer sizes).
The new method only requires one buffer, and instead animates by
recognizing vertices belonging to autotiles in a custom vertex
shader, which offsets them on the fly according to the animation
index.
With giant tilemaps, this method would turn out to be a little
less efficient, but considering the Tilemap is planned to be
rewritten to only hold the range of tiles visible on the screen
in its buffers, the on the fly offsetting will become neglient,
while at the same time the amount of data we have to send to the
GPU everytime the tilemap is updated is greatly reduced; so a
net win in the end.
2014-07-06 17:44:19 +00:00
|
|
|
* | Empty space | | |
|
|
|
|
* |-----------------------| | |
|
Implement a new tileset atlas layout to allow for bigger tilesets
The atlas packing algorithm has been reworked to pack autotiles
and tileset very efficiently into a texture, splitting the tileset
in multiple ways and eliminating the previous duplication of image
data in the atlas across "frames". Animation, which these frames
were designed for, is now done via duplicated buffer frames,
ie. each animation frame has its own VBO and IBO data. This was
not done to save on VRAM (hardly less memory is used), but to
make place for the new atlas layout.
Thanks to this new layout, even with a max texture size of 2048,
one can use tilesets with up to 15000 height. Of course, such
a tileset couldn't be stored in a regular Bitmap to begin with,
which is why I also introduced a hack called "mega surfaces":
software surfaces stored in RAM and wrapped inside a Bitmap,
whose sole purpose is to be passed to a Tilemap as tilesets.
Various other minor changes and fixes are included.
2013-09-23 20:21:58 +00:00
|
|
|
* | ¦ ¦ ¦ ¦ |
|
|
|
|
* | Tile- ¦ | ¦ | ¦ ¦ |
|
|
|
|
* | set ¦ v ¦ v ¦ ¦ |
|
|
|
|
* | ¦ ¦ ¦ | ¦ | |
|
|
|
|
* | | ¦ ¦ ¦ v ¦ v |
|
|
|
|
* | v ¦ | ¦ | ¦ ¦ |
|
|
|
|
* | ¦ v ¦ v ¦ ¦ |
|
|
|
|
* | ¦ ¦ ¦ ¦ |
|
|
|
|
* *---------------------------------------*
|
2013-09-01 14:27:21 +00:00
|
|
|
*
|
Implement a new tileset atlas layout to allow for bigger tilesets
The atlas packing algorithm has been reworked to pack autotiles
and tileset very efficiently into a texture, splitting the tileset
in multiple ways and eliminating the previous duplication of image
data in the atlas across "frames". Animation, which these frames
were designed for, is now done via duplicated buffer frames,
ie. each animation frame has its own VBO and IBO data. This was
not done to save on VRAM (hardly less memory is used), but to
make place for the new atlas layout.
Thanks to this new layout, even with a max texture size of 2048,
one can use tilesets with up to 15000 height. Of course, such
a tileset couldn't be stored in a regular Bitmap to begin with,
which is why I also introduced a hack called "mega surfaces":
software surfaces stored in RAM and wrapped inside a Bitmap,
whose sole purpose is to be passed to a Tilemap as tilesets.
Various other minor changes and fixes are included.
2013-09-23 20:21:58 +00:00
|
|
|
* When allocating the atlas size, we first expand vertically
|
|
|
|
* until all the space immediately below the autotile area
|
|
|
|
* is used up, and then, when the max texture size
|
|
|
|
* is reached, horizontally.
|
2013-09-01 14:27:21 +00:00
|
|
|
*
|
Tilemap: Use vertex shader based autotile animation strategy
Previously, we would just stuff the entire tilemap vertex data
four times into the buffers, with only the autotile vertices
offset according to the animation frame. This meant we could
prepare the buffers once, and then just bind a different offset
for each animation frame without any shader changes, but it also
lead to a huge amount of data being duplicated (and blowing up
the buffer sizes).
The new method only requires one buffer, and instead animates by
recognizing vertices belonging to autotiles in a custom vertex
shader, which offsets them on the fly according to the animation
index.
With giant tilemaps, this method would turn out to be a little
less efficient, but considering the Tilemap is planned to be
rewritten to only hold the range of tiles visible on the screen
in its buffers, the on the fly offsetting will become neglient,
while at the same time the amount of data we have to send to the
GPU everytime the tilemap is updated is greatly reduced; so a
net win in the end.
2014-07-06 17:44:19 +00:00
|
|
|
* To animate the autotiles, we catch any autotile vertices in
|
|
|
|
* the tilemap shader based on their texcoord, and offset them
|
|
|
|
* horizontally by (animation index) * (autotile frame width = 96).
|
2013-09-01 14:27:21 +00:00
|
|
|
*
|
|
|
|
* Elements:
|
|
|
|
* Even though the Tilemap carries similarities with other
|
|
|
|
* SceneElements, it is not one itself but composed of multiple
|
|
|
|
* such elements (GroundLayer and ScanRows).
|
|
|
|
*
|
|
|
|
* GroundLayer:
|
|
|
|
* Every tile with priority=0 is drawn at z=0, so we
|
|
|
|
* collect all such tiles in one big quad array and
|
|
|
|
* draw them at once.
|
|
|
|
*
|
|
|
|
* ScanRow:
|
|
|
|
* Each tile in row n with priority=m is drawn at the same
|
|
|
|
* z as every tile in row n-1 with priority=m-1. This means
|
|
|
|
* we can collect all tiles sharing the same z in one quad
|
|
|
|
* array and draw them at once. I call these collections
|
|
|
|
* 'scanrows', as they're drawn from the top part of the map
|
|
|
|
* (lowest z) to the bottom part (highest z).
|
|
|
|
* Objects that would end up on the same scanrow are eg. trees.
|
|
|
|
*
|
2014-07-10 23:07:18 +00:00
|
|
|
* Map viewport:
|
|
|
|
* This rectangle describes the subregion of the map that is
|
|
|
|
* actually translated to vertices and stored on the GPU ready
|
|
|
|
* for rendering. Whenever, ox/oy are modified, its position is
|
|
|
|
* adjusted if necessary and the data is regenerated. Its size
|
|
|
|
* is fixed. This is NOT related to the RGSS Viewport class!
|
2013-09-01 14:27:21 +00:00
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2014-07-11 06:43:39 +00:00
|
|
|
static int wrap(int value, int range)
|
2013-09-01 14:27:21 +00:00
|
|
|
{
|
2014-07-10 23:07:18 +00:00
|
|
|
int res = value % range;
|
|
|
|
return res < 0 ? res + range : res;
|
|
|
|
}
|
2013-09-01 14:27:21 +00:00
|
|
|
|
2014-07-10 23:07:18 +00:00
|
|
|
static int16_t tableGetWrapped(const Table *t, int x, int y, int z = 0)
|
2013-09-01 14:27:21 +00:00
|
|
|
{
|
2014-07-10 23:07:18 +00:00
|
|
|
return t->get(wrap(x, t->xSize()),
|
|
|
|
wrap(y, t->ySize()),
|
|
|
|
z);
|
|
|
|
}
|
2013-09-01 14:27:21 +00:00
|
|
|
|
2013-10-09 09:52:39 +00:00
|
|
|
/* Autotile animation */
|
|
|
|
static const uint8_t atAnimation[16*4] =
|
|
|
|
{
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
|
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
|
|
|
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
|
|
|
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3
|
|
|
|
};
|
|
|
|
|
|
|
|
static elementsN(atAnimation);
|
|
|
|
|
|
|
|
/* Flash tiles pulsing opacity */
|
2013-09-23 06:27:28 +00:00
|
|
|
static const uint8_t flashAlpha[] =
|
|
|
|
{
|
|
|
|
/* Fade in */
|
|
|
|
0x3C, 0x3C, 0x3C, 0x3C, 0x4B, 0x4B, 0x4B, 0x4B,
|
|
|
|
0x5A, 0x5A, 0x5A, 0x5A, 0x69, 0x69, 0x69, 0x69,
|
|
|
|
/* Fade out */
|
|
|
|
0x78, 0x78, 0x78, 0x78, 0x69, 0x69, 0x69, 0x69,
|
|
|
|
0x5A, 0x5A, 0x5A, 0x5A, 0x4B, 0x4B, 0x4B, 0x4B
|
|
|
|
};
|
|
|
|
|
|
|
|
static elementsN(flashAlpha);
|
|
|
|
|
2013-09-01 14:27:21 +00:00
|
|
|
struct GroundLayer : public ViewportElement
|
|
|
|
{
|
|
|
|
GLsizei vboCount;
|
|
|
|
TilemapPrivate *p;
|
|
|
|
|
|
|
|
GroundLayer(TilemapPrivate *p, Viewport *viewport);
|
|
|
|
|
2014-07-10 23:07:18 +00:00
|
|
|
void updateVboCount();
|
|
|
|
|
2013-09-01 14:27:21 +00:00
|
|
|
void draw();
|
|
|
|
void drawInt();
|
|
|
|
void drawFlashInt();
|
|
|
|
|
|
|
|
void onGeometryChange(const Scene::Geometry &geo);
|
|
|
|
};
|
|
|
|
|
|
|
|
struct ScanRow : public ViewportElement
|
|
|
|
{
|
2014-07-10 23:07:18 +00:00
|
|
|
size_t index;
|
2013-09-01 14:27:21 +00:00
|
|
|
GLintptr vboOffset;
|
|
|
|
GLsizei vboCount;
|
|
|
|
TilemapPrivate *p;
|
|
|
|
|
2013-10-13 20:00:38 +00:00
|
|
|
/* If this row is part of a batch and not
|
|
|
|
* the head, it is 'muted' via this flag */
|
|
|
|
bool batchedFlag;
|
|
|
|
|
|
|
|
/* If this row is a batch head, this variable
|
|
|
|
* holds the element count of the entire batch */
|
|
|
|
GLsizei vboBatchCount;
|
|
|
|
|
2014-07-10 23:07:18 +00:00
|
|
|
ScanRow(TilemapPrivate *p, Viewport *viewport);
|
|
|
|
|
|
|
|
void setIndex(int value);
|
2013-09-01 14:27:21 +00:00
|
|
|
|
|
|
|
void draw();
|
|
|
|
void drawInt();
|
|
|
|
|
2014-07-10 23:07:18 +00:00
|
|
|
static int calculateZ(TilemapPrivate *p, int index);
|
|
|
|
|
2013-09-27 02:42:22 +00:00
|
|
|
void initUpdateZ();
|
2013-10-13 10:58:56 +00:00
|
|
|
void finiUpdateZ(ScanRow *prev);
|
2013-09-01 14:27:21 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
struct TilemapPrivate
|
|
|
|
{
|
|
|
|
Viewport *viewport;
|
|
|
|
|
|
|
|
Tilemap::Autotiles autotilesProxy;
|
Implement a new tileset atlas layout to allow for bigger tilesets
The atlas packing algorithm has been reworked to pack autotiles
and tileset very efficiently into a texture, splitting the tileset
in multiple ways and eliminating the previous duplication of image
data in the atlas across "frames". Animation, which these frames
were designed for, is now done via duplicated buffer frames,
ie. each animation frame has its own VBO and IBO data. This was
not done to save on VRAM (hardly less memory is used), but to
make place for the new atlas layout.
Thanks to this new layout, even with a max texture size of 2048,
one can use tilesets with up to 15000 height. Of course, such
a tileset couldn't be stored in a regular Bitmap to begin with,
which is why I also introduced a hack called "mega surfaces":
software surfaces stored in RAM and wrapped inside a Bitmap,
whose sole purpose is to be passed to a Tilemap as tilesets.
Various other minor changes and fixes are included.
2013-09-23 20:21:58 +00:00
|
|
|
Bitmap *autotiles[autotileCount];
|
2013-09-01 14:27:21 +00:00
|
|
|
|
|
|
|
Bitmap *tileset;
|
|
|
|
Table *mapData;
|
|
|
|
Table *flashData;
|
|
|
|
Table *priorities;
|
|
|
|
bool visible;
|
|
|
|
Vec2i offset;
|
|
|
|
|
|
|
|
Vec2i dispPos;
|
|
|
|
|
|
|
|
/* Tile atlas */
|
|
|
|
struct {
|
2013-09-06 10:26:41 +00:00
|
|
|
TEXFBO gl;
|
Implement a new tileset atlas layout to allow for bigger tilesets
The atlas packing algorithm has been reworked to pack autotiles
and tileset very efficiently into a texture, splitting the tileset
in multiple ways and eliminating the previous duplication of image
data in the atlas across "frames". Animation, which these frames
were designed for, is now done via duplicated buffer frames,
ie. each animation frame has its own VBO and IBO data. This was
not done to save on VRAM (hardly less memory is used), but to
make place for the new atlas layout.
Thanks to this new layout, even with a max texture size of 2048,
one can use tilesets with up to 15000 height. Of course, such
a tileset couldn't be stored in a regular Bitmap to begin with,
which is why I also introduced a hack called "mega surfaces":
software surfaces stored in RAM and wrapped inside a Bitmap,
whose sole purpose is to be passed to a Tilemap as tilesets.
Various other minor changes and fixes are included.
2013-09-23 20:21:58 +00:00
|
|
|
|
|
|
|
Vec2i size;
|
|
|
|
|
2013-09-29 23:38:46 +00:00
|
|
|
/* Effective tileset height,
|
|
|
|
* clamped to a multiple of 32 */
|
|
|
|
int efTilesetH;
|
|
|
|
|
Implement a new tileset atlas layout to allow for bigger tilesets
The atlas packing algorithm has been reworked to pack autotiles
and tileset very efficiently into a texture, splitting the tileset
in multiple ways and eliminating the previous duplication of image
data in the atlas across "frames". Animation, which these frames
were designed for, is now done via duplicated buffer frames,
ie. each animation frame has its own VBO and IBO data. This was
not done to save on VRAM (hardly less memory is used), but to
make place for the new atlas layout.
Thanks to this new layout, even with a max texture size of 2048,
one can use tilesets with up to 15000 height. Of course, such
a tileset couldn't be stored in a regular Bitmap to begin with,
which is why I also introduced a hack called "mega surfaces":
software surfaces stored in RAM and wrapped inside a Bitmap,
whose sole purpose is to be passed to a Tilemap as tilesets.
Various other minor changes and fixes are included.
2013-09-23 20:21:58 +00:00
|
|
|
/* Indices of usable
|
|
|
|
* (not null, not disposed) autotiles */
|
2013-12-26 19:18:33 +00:00
|
|
|
std::vector<uint8_t> usableATs;
|
Implement a new tileset atlas layout to allow for bigger tilesets
The atlas packing algorithm has been reworked to pack autotiles
and tileset very efficiently into a texture, splitting the tileset
in multiple ways and eliminating the previous duplication of image
data in the atlas across "frames". Animation, which these frames
were designed for, is now done via duplicated buffer frames,
ie. each animation frame has its own VBO and IBO data. This was
not done to save on VRAM (hardly less memory is used), but to
make place for the new atlas layout.
Thanks to this new layout, even with a max texture size of 2048,
one can use tilesets with up to 15000 height. Of course, such
a tileset couldn't be stored in a regular Bitmap to begin with,
which is why I also introduced a hack called "mega surfaces":
software surfaces stored in RAM and wrapped inside a Bitmap,
whose sole purpose is to be passed to a Tilemap as tilesets.
Various other minor changes and fixes are included.
2013-09-23 20:21:58 +00:00
|
|
|
|
2013-09-01 14:27:21 +00:00
|
|
|
/* Indices of animated autotiles */
|
2013-12-26 19:18:33 +00:00
|
|
|
std::vector<uint8_t> animatedATs;
|
2013-09-01 14:27:21 +00:00
|
|
|
} atlas;
|
|
|
|
|
2014-07-10 23:07:18 +00:00
|
|
|
/* Map viewport position */
|
|
|
|
Vec2i viewpPos;
|
2013-09-01 14:27:21 +00:00
|
|
|
|
|
|
|
/* Ground layer vertices */
|
Tilemap: Use vertex shader based autotile animation strategy
Previously, we would just stuff the entire tilemap vertex data
four times into the buffers, with only the autotile vertices
offset according to the animation frame. This meant we could
prepare the buffers once, and then just bind a different offset
for each animation frame without any shader changes, but it also
lead to a huge amount of data being duplicated (and blowing up
the buffer sizes).
The new method only requires one buffer, and instead animates by
recognizing vertices belonging to autotiles in a custom vertex
shader, which offsets them on the fly according to the animation
index.
With giant tilemaps, this method would turn out to be a little
less efficient, but considering the Tilemap is planned to be
rewritten to only hold the range of tiles visible on the screen
in its buffers, the on the fly offsetting will become neglient,
while at the same time the amount of data we have to send to the
GPU everytime the tilemap is updated is greatly reduced; so a
net win in the end.
2014-07-06 17:44:19 +00:00
|
|
|
SVVector groundVert;
|
2013-09-01 14:27:21 +00:00
|
|
|
|
|
|
|
/* Scanrow vertices */
|
2014-07-10 23:07:18 +00:00
|
|
|
SVVector scanrowVert[scanrowsMax];
|
2013-09-01 14:27:21 +00:00
|
|
|
|
|
|
|
/* Base quad indices of each scanrow
|
|
|
|
* in the shared buffer */
|
2014-07-10 23:07:18 +00:00
|
|
|
size_t scanrowBases[scanrowsMax+1];
|
2013-09-01 14:27:21 +00:00
|
|
|
|
|
|
|
/* Shared buffers for all tiles */
|
|
|
|
struct
|
|
|
|
{
|
2014-07-13 12:03:18 +00:00
|
|
|
GLMeta::VAO vao;
|
2013-09-01 14:27:21 +00:00
|
|
|
VBO::ID vbo;
|
Implement a new tileset atlas layout to allow for bigger tilesets
The atlas packing algorithm has been reworked to pack autotiles
and tileset very efficiently into a texture, splitting the tileset
in multiple ways and eliminating the previous duplication of image
data in the atlas across "frames". Animation, which these frames
were designed for, is now done via duplicated buffer frames,
ie. each animation frame has its own VBO and IBO data. This was
not done to save on VRAM (hardly less memory is used), but to
make place for the new atlas layout.
Thanks to this new layout, even with a max texture size of 2048,
one can use tilesets with up to 15000 height. Of course, such
a tileset couldn't be stored in a regular Bitmap to begin with,
which is why I also introduced a hack called "mega surfaces":
software surfaces stored in RAM and wrapped inside a Bitmap,
whose sole purpose is to be passed to a Tilemap as tilesets.
Various other minor changes and fixes are included.
2013-09-23 20:21:58 +00:00
|
|
|
bool animated;
|
|
|
|
|
|
|
|
/* Animation state */
|
|
|
|
uint8_t frameIdx;
|
|
|
|
uint8_t aniIdx;
|
2013-09-01 14:27:21 +00:00
|
|
|
} tiles;
|
|
|
|
|
|
|
|
/* Flash buffers */
|
|
|
|
struct
|
|
|
|
{
|
2014-07-13 12:03:18 +00:00
|
|
|
GLMeta::VAO vao;
|
2013-09-01 14:27:21 +00:00
|
|
|
VBO::ID vbo;
|
2013-12-26 19:18:33 +00:00
|
|
|
size_t quadCount;
|
2013-09-23 06:27:28 +00:00
|
|
|
uint8_t alphaIdx;
|
2013-09-01 14:27:21 +00:00
|
|
|
} flash;
|
|
|
|
|
|
|
|
/* Scene elements */
|
|
|
|
struct
|
|
|
|
{
|
|
|
|
GroundLayer *ground;
|
2014-07-10 23:07:18 +00:00
|
|
|
ScanRow* scanrows[scanrowsMax];
|
|
|
|
/* Used rows out of 'scanrows' (rest is hidden) */
|
|
|
|
size_t activeRows;
|
2013-09-01 14:27:21 +00:00
|
|
|
Scene::Geometry sceneGeo;
|
|
|
|
Vec2i sceneOffset;
|
2013-09-27 02:42:22 +00:00
|
|
|
|
|
|
|
/* The ground and scanrow elements' creationStamp
|
|
|
|
* should be aquired once (at Tilemap construction)
|
|
|
|
* instead of regenerated everytime the elements are
|
|
|
|
* (re)created. Scanrows can share one stamp because
|
|
|
|
* their z always differs anway */
|
|
|
|
unsigned int groundStamp;
|
|
|
|
unsigned int scanrowStamp;
|
2013-09-01 14:27:21 +00:00
|
|
|
} elem;
|
|
|
|
|
|
|
|
/* Affected by: autotiles, tileset */
|
|
|
|
bool atlasSizeDirty;
|
|
|
|
/* Affected by: autotiles(.changed), tileset(.changed), allocateAtlas */
|
|
|
|
bool atlasDirty;
|
|
|
|
/* Affected by: mapData(.changed), priorities(.changed) */
|
|
|
|
bool buffersDirty;
|
2014-07-10 23:07:18 +00:00
|
|
|
/* Affected by: ox, oy */
|
|
|
|
bool mapViewportDirty;
|
2013-09-01 14:27:21 +00:00
|
|
|
/* Affected by: oy */
|
|
|
|
bool zOrderDirty;
|
|
|
|
/* Affected by: flashData, buffersDirty */
|
|
|
|
bool flashDirty;
|
|
|
|
|
|
|
|
/* Resources are sufficient and tilemap is ready to be drawn */
|
|
|
|
bool tilemapReady;
|
|
|
|
|
|
|
|
/* Change watches */
|
|
|
|
sigc::connection tilesetCon;
|
Implement a new tileset atlas layout to allow for bigger tilesets
The atlas packing algorithm has been reworked to pack autotiles
and tileset very efficiently into a texture, splitting the tileset
in multiple ways and eliminating the previous duplication of image
data in the atlas across "frames". Animation, which these frames
were designed for, is now done via duplicated buffer frames,
ie. each animation frame has its own VBO and IBO data. This was
not done to save on VRAM (hardly less memory is used), but to
make place for the new atlas layout.
Thanks to this new layout, even with a max texture size of 2048,
one can use tilesets with up to 15000 height. Of course, such
a tileset couldn't be stored in a regular Bitmap to begin with,
which is why I also introduced a hack called "mega surfaces":
software surfaces stored in RAM and wrapped inside a Bitmap,
whose sole purpose is to be passed to a Tilemap as tilesets.
Various other minor changes and fixes are included.
2013-09-23 20:21:58 +00:00
|
|
|
sigc::connection autotilesCon[autotileCount];
|
2013-09-01 14:27:21 +00:00
|
|
|
sigc::connection mapDataCon;
|
|
|
|
sigc::connection prioritiesCon;
|
|
|
|
sigc::connection flashDataCon;
|
|
|
|
|
|
|
|
/* Dispose watches */
|
Implement a new tileset atlas layout to allow for bigger tilesets
The atlas packing algorithm has been reworked to pack autotiles
and tileset very efficiently into a texture, splitting the tileset
in multiple ways and eliminating the previous duplication of image
data in the atlas across "frames". Animation, which these frames
were designed for, is now done via duplicated buffer frames,
ie. each animation frame has its own VBO and IBO data. This was
not done to save on VRAM (hardly less memory is used), but to
make place for the new atlas layout.
Thanks to this new layout, even with a max texture size of 2048,
one can use tilesets with up to 15000 height. Of course, such
a tileset couldn't be stored in a regular Bitmap to begin with,
which is why I also introduced a hack called "mega surfaces":
software surfaces stored in RAM and wrapped inside a Bitmap,
whose sole purpose is to be passed to a Tilemap as tilesets.
Various other minor changes and fixes are included.
2013-09-23 20:21:58 +00:00
|
|
|
sigc::connection autotilesDispCon[autotileCount];
|
2013-09-01 14:27:21 +00:00
|
|
|
|
|
|
|
/* Draw prepare call */
|
|
|
|
sigc::connection prepareCon;
|
|
|
|
|
|
|
|
TilemapPrivate(Viewport *viewport)
|
|
|
|
: viewport(viewport),
|
|
|
|
tileset(0),
|
|
|
|
mapData(0),
|
|
|
|
flashData(0),
|
|
|
|
priorities(0),
|
|
|
|
visible(true),
|
|
|
|
atlasSizeDirty(false),
|
|
|
|
atlasDirty(false),
|
|
|
|
buffersDirty(false),
|
2014-07-10 23:07:18 +00:00
|
|
|
mapViewportDirty(false),
|
2013-09-01 14:27:21 +00:00
|
|
|
zOrderDirty(false),
|
|
|
|
flashDirty(false),
|
|
|
|
tilemapReady(false)
|
|
|
|
{
|
|
|
|
memset(autotiles, 0, sizeof(autotiles));
|
|
|
|
|
Implement a new tileset atlas layout to allow for bigger tilesets
The atlas packing algorithm has been reworked to pack autotiles
and tileset very efficiently into a texture, splitting the tileset
in multiple ways and eliminating the previous duplication of image
data in the atlas across "frames". Animation, which these frames
were designed for, is now done via duplicated buffer frames,
ie. each animation frame has its own VBO and IBO data. This was
not done to save on VRAM (hardly less memory is used), but to
make place for the new atlas layout.
Thanks to this new layout, even with a max texture size of 2048,
one can use tilesets with up to 15000 height. Of course, such
a tileset couldn't be stored in a regular Bitmap to begin with,
which is why I also introduced a hack called "mega surfaces":
software surfaces stored in RAM and wrapped inside a Bitmap,
whose sole purpose is to be passed to a Tilemap as tilesets.
Various other minor changes and fixes are included.
2013-09-23 20:21:58 +00:00
|
|
|
atlas.animatedATs.reserve(autotileCount);
|
2013-09-29 23:38:46 +00:00
|
|
|
atlas.efTilesetH = 0;
|
|
|
|
|
Implement a new tileset atlas layout to allow for bigger tilesets
The atlas packing algorithm has been reworked to pack autotiles
and tileset very efficiently into a texture, splitting the tileset
in multiple ways and eliminating the previous duplication of image
data in the atlas across "frames". Animation, which these frames
were designed for, is now done via duplicated buffer frames,
ie. each animation frame has its own VBO and IBO data. This was
not done to save on VRAM (hardly less memory is used), but to
make place for the new atlas layout.
Thanks to this new layout, even with a max texture size of 2048,
one can use tilesets with up to 15000 height. Of course, such
a tileset couldn't be stored in a regular Bitmap to begin with,
which is why I also introduced a hack called "mega surfaces":
software surfaces stored in RAM and wrapped inside a Bitmap,
whose sole purpose is to be passed to a Tilemap as tilesets.
Various other minor changes and fixes are included.
2013-09-23 20:21:58 +00:00
|
|
|
tiles.animated = false;
|
|
|
|
tiles.frameIdx = 0;
|
|
|
|
tiles.aniIdx = 0;
|
2013-09-01 14:27:21 +00:00
|
|
|
|
|
|
|
/* Init tile buffers */
|
|
|
|
tiles.vbo = VBO::gen();
|
|
|
|
|
2014-07-13 12:03:18 +00:00
|
|
|
GLMeta::vaoFillInVertexData<SVertex>(tiles.vao);
|
|
|
|
tiles.vao.vbo = tiles.vbo;
|
|
|
|
tiles.vao.ibo = shState->globalIBO().ibo;
|
2013-09-23 05:15:01 +00:00
|
|
|
|
2014-07-13 12:03:18 +00:00
|
|
|
GLMeta::vaoInit(tiles.vao);
|
2013-09-01 14:27:21 +00:00
|
|
|
|
|
|
|
/* Init flash buffers */
|
|
|
|
flash.vbo = VBO::gen();
|
|
|
|
|
2014-07-13 12:03:18 +00:00
|
|
|
GLMeta::vaoFillInVertexData<CVertex>(flash.vao);
|
|
|
|
flash.vao.vbo = flash.vbo;
|
|
|
|
flash.vao.ibo = shState->globalIBO().ibo;
|
2013-09-01 14:27:21 +00:00
|
|
|
|
2014-07-13 12:03:18 +00:00
|
|
|
GLMeta::vaoInit(flash.vao);
|
2013-09-01 14:27:21 +00:00
|
|
|
|
2014-07-13 12:03:18 +00:00
|
|
|
flash.quadCount = 0;
|
|
|
|
flash.alphaIdx = 0;
|
2013-09-01 14:27:21 +00:00
|
|
|
|
2013-10-09 10:30:33 +00:00
|
|
|
elem.groundStamp = shState->genTimeStamp();
|
|
|
|
elem.scanrowStamp = shState->genTimeStamp();
|
2013-09-27 02:42:22 +00:00
|
|
|
|
2014-07-10 23:07:18 +00:00
|
|
|
elem.ground = new GroundLayer(this, viewport);
|
|
|
|
|
|
|
|
for (size_t i = 0; i < scanrowsMax; ++i)
|
|
|
|
elem.scanrows[i] = new ScanRow(this, viewport);
|
|
|
|
|
2013-10-09 10:30:33 +00:00
|
|
|
prepareCon = shState->prepareDraw.connect
|
2013-09-01 14:27:21 +00:00
|
|
|
(sigc::mem_fun(this, &TilemapPrivate::prepare));
|
|
|
|
}
|
|
|
|
|
|
|
|
~TilemapPrivate()
|
|
|
|
{
|
2014-07-10 23:07:18 +00:00
|
|
|
/* Destroy elements */
|
|
|
|
delete elem.ground;
|
|
|
|
for (size_t i = 0; i < scanrowsMax; ++i)
|
|
|
|
delete elem.scanrows[i];
|
2013-09-01 14:27:21 +00:00
|
|
|
|
2013-10-22 04:36:13 +00:00
|
|
|
shState->releaseAtlasTex(atlas.gl);
|
2014-07-10 23:07:18 +00:00
|
|
|
|
|
|
|
/* Destroy tile buffers */
|
2014-07-13 12:03:18 +00:00
|
|
|
GLMeta::vaoFini(tiles.vao);
|
2013-09-01 14:27:21 +00:00
|
|
|
VBO::del(tiles.vbo);
|
|
|
|
|
2014-07-10 23:07:18 +00:00
|
|
|
/* Destroy flash buffers */
|
2014-07-13 12:03:18 +00:00
|
|
|
GLMeta::vaoFini(flash.vao);
|
2013-09-01 14:27:21 +00:00
|
|
|
VBO::del(flash.vbo);
|
|
|
|
|
2014-07-10 23:07:18 +00:00
|
|
|
/* Disconnect signal handlers */
|
2013-09-01 14:27:21 +00:00
|
|
|
tilesetCon.disconnect();
|
2014-07-19 00:58:57 +00:00
|
|
|
for (int i = 0; i < autotileCount; ++i)
|
2013-09-01 14:27:21 +00:00
|
|
|
{
|
|
|
|
autotilesCon[i].disconnect();
|
|
|
|
autotilesDispCon[i].disconnect();
|
|
|
|
}
|
|
|
|
mapDataCon.disconnect();
|
|
|
|
prioritiesCon.disconnect();
|
|
|
|
flashDataCon.disconnect();
|
|
|
|
|
|
|
|
prepareCon.disconnect();
|
|
|
|
}
|
|
|
|
|
Implement a new tileset atlas layout to allow for bigger tilesets
The atlas packing algorithm has been reworked to pack autotiles
and tileset very efficiently into a texture, splitting the tileset
in multiple ways and eliminating the previous duplication of image
data in the atlas across "frames". Animation, which these frames
were designed for, is now done via duplicated buffer frames,
ie. each animation frame has its own VBO and IBO data. This was
not done to save on VRAM (hardly less memory is used), but to
make place for the new atlas layout.
Thanks to this new layout, even with a max texture size of 2048,
one can use tilesets with up to 15000 height. Of course, such
a tileset couldn't be stored in a regular Bitmap to begin with,
which is why I also introduced a hack called "mega surfaces":
software surfaces stored in RAM and wrapped inside a Bitmap,
whose sole purpose is to be passed to a Tilemap as tilesets.
Various other minor changes and fixes are included.
2013-09-23 20:21:58 +00:00
|
|
|
void updateAtlasInfo()
|
|
|
|
{
|
|
|
|
if (!tileset || tileset->isDisposed())
|
|
|
|
{
|
|
|
|
atlas.size = Vec2i();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-09-29 23:38:46 +00:00
|
|
|
int tsH = tileset->height();
|
|
|
|
atlas.efTilesetH = tsH - (tsH % 32);
|
|
|
|
|
|
|
|
atlas.size = TileAtlas::minSize(atlas.efTilesetH, glState.caps.maxTexSize);
|
Implement a new tileset atlas layout to allow for bigger tilesets
The atlas packing algorithm has been reworked to pack autotiles
and tileset very efficiently into a texture, splitting the tileset
in multiple ways and eliminating the previous duplication of image
data in the atlas across "frames". Animation, which these frames
were designed for, is now done via duplicated buffer frames,
ie. each animation frame has its own VBO and IBO data. This was
not done to save on VRAM (hardly less memory is used), but to
make place for the new atlas layout.
Thanks to this new layout, even with a max texture size of 2048,
one can use tilesets with up to 15000 height. Of course, such
a tileset couldn't be stored in a regular Bitmap to begin with,
which is why I also introduced a hack called "mega surfaces":
software surfaces stored in RAM and wrapped inside a Bitmap,
whose sole purpose is to be passed to a Tilemap as tilesets.
Various other minor changes and fixes are included.
2013-09-23 20:21:58 +00:00
|
|
|
|
|
|
|
if (atlas.size.x < 0)
|
|
|
|
throw Exception(Exception::MKXPError,
|
|
|
|
"Cannot allocate big enough texture for tileset atlas");
|
|
|
|
}
|
|
|
|
|
|
|
|
void updateAutotileInfo()
|
|
|
|
{
|
|
|
|
/* Check if and which autotiles are animated */
|
2013-12-26 19:18:33 +00:00
|
|
|
std::vector<uint8_t> &usableATs = atlas.usableATs;
|
|
|
|
std::vector<uint8_t> &animatedATs = atlas.animatedATs;
|
Implement a new tileset atlas layout to allow for bigger tilesets
The atlas packing algorithm has been reworked to pack autotiles
and tileset very efficiently into a texture, splitting the tileset
in multiple ways and eliminating the previous duplication of image
data in the atlas across "frames". Animation, which these frames
were designed for, is now done via duplicated buffer frames,
ie. each animation frame has its own VBO and IBO data. This was
not done to save on VRAM (hardly less memory is used), but to
make place for the new atlas layout.
Thanks to this new layout, even with a max texture size of 2048,
one can use tilesets with up to 15000 height. Of course, such
a tileset couldn't be stored in a regular Bitmap to begin with,
which is why I also introduced a hack called "mega surfaces":
software surfaces stored in RAM and wrapped inside a Bitmap,
whose sole purpose is to be passed to a Tilemap as tilesets.
Various other minor changes and fixes are included.
2013-09-23 20:21:58 +00:00
|
|
|
|
|
|
|
usableATs.clear();
|
|
|
|
|
2014-07-19 00:58:57 +00:00
|
|
|
for (int i = 0; i < autotileCount; ++i)
|
Implement a new tileset atlas layout to allow for bigger tilesets
The atlas packing algorithm has been reworked to pack autotiles
and tileset very efficiently into a texture, splitting the tileset
in multiple ways and eliminating the previous duplication of image
data in the atlas across "frames". Animation, which these frames
were designed for, is now done via duplicated buffer frames,
ie. each animation frame has its own VBO and IBO data. This was
not done to save on VRAM (hardly less memory is used), but to
make place for the new atlas layout.
Thanks to this new layout, even with a max texture size of 2048,
one can use tilesets with up to 15000 height. Of course, such
a tileset couldn't be stored in a regular Bitmap to begin with,
which is why I also introduced a hack called "mega surfaces":
software surfaces stored in RAM and wrapped inside a Bitmap,
whose sole purpose is to be passed to a Tilemap as tilesets.
Various other minor changes and fixes are included.
2013-09-23 20:21:58 +00:00
|
|
|
{
|
|
|
|
if (!autotiles[i])
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (autotiles[i]->isDisposed())
|
|
|
|
continue;
|
|
|
|
|
2013-10-09 16:07:19 +00:00
|
|
|
if (autotiles[i]->megaSurface())
|
|
|
|
continue;
|
|
|
|
|
2013-12-26 19:18:33 +00:00
|
|
|
usableATs.push_back(i);
|
Implement a new tileset atlas layout to allow for bigger tilesets
The atlas packing algorithm has been reworked to pack autotiles
and tileset very efficiently into a texture, splitting the tileset
in multiple ways and eliminating the previous duplication of image
data in the atlas across "frames". Animation, which these frames
were designed for, is now done via duplicated buffer frames,
ie. each animation frame has its own VBO and IBO data. This was
not done to save on VRAM (hardly less memory is used), but to
make place for the new atlas layout.
Thanks to this new layout, even with a max texture size of 2048,
one can use tilesets with up to 15000 height. Of course, such
a tileset couldn't be stored in a regular Bitmap to begin with,
which is why I also introduced a hack called "mega surfaces":
software surfaces stored in RAM and wrapped inside a Bitmap,
whose sole purpose is to be passed to a Tilemap as tilesets.
Various other minor changes and fixes are included.
2013-09-23 20:21:58 +00:00
|
|
|
|
|
|
|
if (autotiles[i]->width() > autotileW)
|
2013-12-26 19:18:33 +00:00
|
|
|
animatedATs.push_back(i);
|
Implement a new tileset atlas layout to allow for bigger tilesets
The atlas packing algorithm has been reworked to pack autotiles
and tileset very efficiently into a texture, splitting the tileset
in multiple ways and eliminating the previous duplication of image
data in the atlas across "frames". Animation, which these frames
were designed for, is now done via duplicated buffer frames,
ie. each animation frame has its own VBO and IBO data. This was
not done to save on VRAM (hardly less memory is used), but to
make place for the new atlas layout.
Thanks to this new layout, even with a max texture size of 2048,
one can use tilesets with up to 15000 height. Of course, such
a tileset couldn't be stored in a regular Bitmap to begin with,
which is why I also introduced a hack called "mega surfaces":
software surfaces stored in RAM and wrapped inside a Bitmap,
whose sole purpose is to be passed to a Tilemap as tilesets.
Various other minor changes and fixes are included.
2013-09-23 20:21:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
tiles.animated = !animatedATs.empty();
|
|
|
|
}
|
|
|
|
|
2013-09-01 14:27:21 +00:00
|
|
|
void updateSceneGeometry(const Scene::Geometry &geo)
|
|
|
|
{
|
|
|
|
elem.sceneOffset.x = geo.rect.x - geo.xOrigin;
|
|
|
|
elem.sceneOffset.y = geo.rect.y - geo.yOrigin;
|
|
|
|
elem.sceneGeo = geo;
|
|
|
|
}
|
|
|
|
|
|
|
|
void updatePosition()
|
|
|
|
{
|
2014-07-10 23:07:18 +00:00
|
|
|
dispPos.x = -(offset.x - viewpPos.x * 32) + elem.sceneOffset.x;
|
|
|
|
dispPos.y = -(offset.y - viewpPos.y * 32) + elem.sceneOffset.x;
|
2013-09-01 14:27:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void invalidateAtlasSize()
|
|
|
|
{
|
|
|
|
atlasSizeDirty = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void invalidateAtlasContents()
|
|
|
|
{
|
|
|
|
atlasDirty = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void invalidateBuffers()
|
|
|
|
{
|
|
|
|
buffersDirty = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void invalidateFlash()
|
|
|
|
{
|
|
|
|
flashDirty = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Checks for the minimum amount of data needed to display */
|
|
|
|
bool verifyResources()
|
|
|
|
{
|
|
|
|
if (!tileset)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (tileset->isDisposed())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (!mapData)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Allocates correctly sized TexFBO for atlas */
|
|
|
|
void allocateAtlas()
|
|
|
|
{
|
Implement a new tileset atlas layout to allow for bigger tilesets
The atlas packing algorithm has been reworked to pack autotiles
and tileset very efficiently into a texture, splitting the tileset
in multiple ways and eliminating the previous duplication of image
data in the atlas across "frames". Animation, which these frames
were designed for, is now done via duplicated buffer frames,
ie. each animation frame has its own VBO and IBO data. This was
not done to save on VRAM (hardly less memory is used), but to
make place for the new atlas layout.
Thanks to this new layout, even with a max texture size of 2048,
one can use tilesets with up to 15000 height. Of course, such
a tileset couldn't be stored in a regular Bitmap to begin with,
which is why I also introduced a hack called "mega surfaces":
software surfaces stored in RAM and wrapped inside a Bitmap,
whose sole purpose is to be passed to a Tilemap as tilesets.
Various other minor changes and fixes are included.
2013-09-23 20:21:58 +00:00
|
|
|
updateAtlasInfo();
|
2013-09-01 14:27:21 +00:00
|
|
|
|
|
|
|
/* Aquire atlas tex */
|
2013-10-22 04:36:13 +00:00
|
|
|
shState->releaseAtlasTex(atlas.gl);
|
|
|
|
shState->requestAtlasTex(atlas.size.x, atlas.size.y, atlas.gl);
|
2013-09-01 14:27:21 +00:00
|
|
|
|
|
|
|
atlasDirty = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Assembles atlas from tileset and autotile bitmaps */
|
|
|
|
void buildAtlas()
|
|
|
|
{
|
Implement a new tileset atlas layout to allow for bigger tilesets
The atlas packing algorithm has been reworked to pack autotiles
and tileset very efficiently into a texture, splitting the tileset
in multiple ways and eliminating the previous duplication of image
data in the atlas across "frames". Animation, which these frames
were designed for, is now done via duplicated buffer frames,
ie. each animation frame has its own VBO and IBO data. This was
not done to save on VRAM (hardly less memory is used), but to
make place for the new atlas layout.
Thanks to this new layout, even with a max texture size of 2048,
one can use tilesets with up to 15000 height. Of course, such
a tileset couldn't be stored in a regular Bitmap to begin with,
which is why I also introduced a hack called "mega surfaces":
software surfaces stored in RAM and wrapped inside a Bitmap,
whose sole purpose is to be passed to a Tilemap as tilesets.
Various other minor changes and fixes are included.
2013-09-23 20:21:58 +00:00
|
|
|
updateAutotileInfo();
|
|
|
|
|
2014-01-16 18:16:09 +00:00
|
|
|
TileAtlas::BlitVec blits = TileAtlas::calcBlits(atlas.efTilesetH, atlas.size);
|
2013-09-01 14:27:21 +00:00
|
|
|
|
|
|
|
/* Clear atlas */
|
2014-07-16 03:22:43 +00:00
|
|
|
FBO::bind(atlas.gl.fbo);
|
2013-09-01 14:27:21 +00:00
|
|
|
glState.clearColor.pushSet(Vec4());
|
|
|
|
glState.scissorTest.pushSet(false);
|
|
|
|
|
2013-10-01 11:10:14 +00:00
|
|
|
FBO::clear();
|
2013-09-01 14:27:21 +00:00
|
|
|
|
|
|
|
glState.scissorTest.pop();
|
|
|
|
glState.clearColor.pop();
|
|
|
|
|
2014-07-16 02:48:40 +00:00
|
|
|
GLMeta::blitBegin(atlas.gl);
|
|
|
|
|
Implement a new tileset atlas layout to allow for bigger tilesets
The atlas packing algorithm has been reworked to pack autotiles
and tileset very efficiently into a texture, splitting the tileset
in multiple ways and eliminating the previous duplication of image
data in the atlas across "frames". Animation, which these frames
were designed for, is now done via duplicated buffer frames,
ie. each animation frame has its own VBO and IBO data. This was
not done to save on VRAM (hardly less memory is used), but to
make place for the new atlas layout.
Thanks to this new layout, even with a max texture size of 2048,
one can use tilesets with up to 15000 height. Of course, such
a tileset couldn't be stored in a regular Bitmap to begin with,
which is why I also introduced a hack called "mega surfaces":
software surfaces stored in RAM and wrapped inside a Bitmap,
whose sole purpose is to be passed to a Tilemap as tilesets.
Various other minor changes and fixes are included.
2013-09-23 20:21:58 +00:00
|
|
|
/* Blit autotiles */
|
2013-12-27 05:19:30 +00:00
|
|
|
for (size_t i = 0; i < atlas.usableATs.size(); ++i)
|
Implement a new tileset atlas layout to allow for bigger tilesets
The atlas packing algorithm has been reworked to pack autotiles
and tileset very efficiently into a texture, splitting the tileset
in multiple ways and eliminating the previous duplication of image
data in the atlas across "frames". Animation, which these frames
were designed for, is now done via duplicated buffer frames,
ie. each animation frame has its own VBO and IBO data. This was
not done to save on VRAM (hardly less memory is used), but to
make place for the new atlas layout.
Thanks to this new layout, even with a max texture size of 2048,
one can use tilesets with up to 15000 height. Of course, such
a tileset couldn't be stored in a regular Bitmap to begin with,
which is why I also introduced a hack called "mega surfaces":
software surfaces stored in RAM and wrapped inside a Bitmap,
whose sole purpose is to be passed to a Tilemap as tilesets.
Various other minor changes and fixes are included.
2013-09-23 20:21:58 +00:00
|
|
|
{
|
2013-12-27 05:19:30 +00:00
|
|
|
const uint8_t atInd = atlas.usableATs[i];
|
|
|
|
Bitmap *autotile = autotiles[atInd];
|
|
|
|
|
|
|
|
int blitW = std::min(autotile->width(), atAreaW);
|
|
|
|
int blitH = std::min(autotile->height(), atAreaH);
|
2013-09-01 14:27:21 +00:00
|
|
|
|
2014-07-16 02:48:40 +00:00
|
|
|
GLMeta::blitSource(autotile->getGLTypes());
|
Tilemap: Use vertex shader based autotile animation strategy
Previously, we would just stuff the entire tilemap vertex data
four times into the buffers, with only the autotile vertices
offset according to the animation frame. This meant we could
prepare the buffers once, and then just bind a different offset
for each animation frame without any shader changes, but it also
lead to a huge amount of data being duplicated (and blowing up
the buffer sizes).
The new method only requires one buffer, and instead animates by
recognizing vertices belonging to autotiles in a custom vertex
shader, which offsets them on the fly according to the animation
index.
With giant tilemaps, this method would turn out to be a little
less efficient, but considering the Tilemap is planned to be
rewritten to only hold the range of tiles visible on the screen
in its buffers, the on the fly offsetting will become neglient,
while at the same time the amount of data we have to send to the
GPU everytime the tilemap is updated is greatly reduced; so a
net win in the end.
2014-07-06 17:44:19 +00:00
|
|
|
|
2014-07-13 12:05:56 +00:00
|
|
|
if (blitW <= autotileW && tiles.animated)
|
Tilemap: Use vertex shader based autotile animation strategy
Previously, we would just stuff the entire tilemap vertex data
four times into the buffers, with only the autotile vertices
offset according to the animation frame. This meant we could
prepare the buffers once, and then just bind a different offset
for each animation frame without any shader changes, but it also
lead to a huge amount of data being duplicated (and blowing up
the buffer sizes).
The new method only requires one buffer, and instead animates by
recognizing vertices belonging to autotiles in a custom vertex
shader, which offsets them on the fly according to the animation
index.
With giant tilemaps, this method would turn out to be a little
less efficient, but considering the Tilemap is planned to be
rewritten to only hold the range of tiles visible on the screen
in its buffers, the on the fly offsetting will become neglient,
while at the same time the amount of data we have to send to the
GPU everytime the tilemap is updated is greatly reduced; so a
net win in the end.
2014-07-06 17:44:19 +00:00
|
|
|
{
|
|
|
|
/* Static autotile */
|
|
|
|
for (int j = 0; j < 4; ++j)
|
2014-07-16 02:48:40 +00:00
|
|
|
GLMeta::blitRectangle(IntRect(0, 0, blitW, blitH),
|
|
|
|
Vec2i(autotileW*j, atInd*autotileH));
|
Tilemap: Use vertex shader based autotile animation strategy
Previously, we would just stuff the entire tilemap vertex data
four times into the buffers, with only the autotile vertices
offset according to the animation frame. This meant we could
prepare the buffers once, and then just bind a different offset
for each animation frame without any shader changes, but it also
lead to a huge amount of data being duplicated (and blowing up
the buffer sizes).
The new method only requires one buffer, and instead animates by
recognizing vertices belonging to autotiles in a custom vertex
shader, which offsets them on the fly according to the animation
index.
With giant tilemaps, this method would turn out to be a little
less efficient, but considering the Tilemap is planned to be
rewritten to only hold the range of tiles visible on the screen
in its buffers, the on the fly offsetting will become neglient,
while at the same time the amount of data we have to send to the
GPU everytime the tilemap is updated is greatly reduced; so a
net win in the end.
2014-07-06 17:44:19 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Animated autotile */
|
2014-07-16 02:48:40 +00:00
|
|
|
GLMeta::blitRectangle(IntRect(0, 0, blitW, blitH),
|
|
|
|
Vec2i(0, atInd*autotileH));
|
Tilemap: Use vertex shader based autotile animation strategy
Previously, we would just stuff the entire tilemap vertex data
four times into the buffers, with only the autotile vertices
offset according to the animation frame. This meant we could
prepare the buffers once, and then just bind a different offset
for each animation frame without any shader changes, but it also
lead to a huge amount of data being duplicated (and blowing up
the buffer sizes).
The new method only requires one buffer, and instead animates by
recognizing vertices belonging to autotiles in a custom vertex
shader, which offsets them on the fly according to the animation
index.
With giant tilemaps, this method would turn out to be a little
less efficient, but considering the Tilemap is planned to be
rewritten to only hold the range of tiles visible on the screen
in its buffers, the on the fly offsetting will become neglient,
while at the same time the amount of data we have to send to the
GPU everytime the tilemap is updated is greatly reduced; so a
net win in the end.
2014-07-06 17:44:19 +00:00
|
|
|
}
|
Implement a new tileset atlas layout to allow for bigger tilesets
The atlas packing algorithm has been reworked to pack autotiles
and tileset very efficiently into a texture, splitting the tileset
in multiple ways and eliminating the previous duplication of image
data in the atlas across "frames". Animation, which these frames
were designed for, is now done via duplicated buffer frames,
ie. each animation frame has its own VBO and IBO data. This was
not done to save on VRAM (hardly less memory is used), but to
make place for the new atlas layout.
Thanks to this new layout, even with a max texture size of 2048,
one can use tilesets with up to 15000 height. Of course, such
a tileset couldn't be stored in a regular Bitmap to begin with,
which is why I also introduced a hack called "mega surfaces":
software surfaces stored in RAM and wrapped inside a Bitmap,
whose sole purpose is to be passed to a Tilemap as tilesets.
Various other minor changes and fixes are included.
2013-09-23 20:21:58 +00:00
|
|
|
}
|
2013-09-01 14:27:21 +00:00
|
|
|
|
2014-07-16 02:53:08 +00:00
|
|
|
GLMeta::blitEnd();
|
2014-07-16 02:48:40 +00:00
|
|
|
|
Implement a new tileset atlas layout to allow for bigger tilesets
The atlas packing algorithm has been reworked to pack autotiles
and tileset very efficiently into a texture, splitting the tileset
in multiple ways and eliminating the previous duplication of image
data in the atlas across "frames". Animation, which these frames
were designed for, is now done via duplicated buffer frames,
ie. each animation frame has its own VBO and IBO data. This was
not done to save on VRAM (hardly less memory is used), but to
make place for the new atlas layout.
Thanks to this new layout, even with a max texture size of 2048,
one can use tilesets with up to 15000 height. Of course, such
a tileset couldn't be stored in a regular Bitmap to begin with,
which is why I also introduced a hack called "mega surfaces":
software surfaces stored in RAM and wrapped inside a Bitmap,
whose sole purpose is to be passed to a Tilemap as tilesets.
Various other minor changes and fixes are included.
2013-09-23 20:21:58 +00:00
|
|
|
/* Blit tileset */
|
|
|
|
if (tileset->megaSurface())
|
2013-09-01 14:27:21 +00:00
|
|
|
{
|
Implement a new tileset atlas layout to allow for bigger tilesets
The atlas packing algorithm has been reworked to pack autotiles
and tileset very efficiently into a texture, splitting the tileset
in multiple ways and eliminating the previous duplication of image
data in the atlas across "frames". Animation, which these frames
were designed for, is now done via duplicated buffer frames,
ie. each animation frame has its own VBO and IBO data. This was
not done to save on VRAM (hardly less memory is used), but to
make place for the new atlas layout.
Thanks to this new layout, even with a max texture size of 2048,
one can use tilesets with up to 15000 height. Of course, such
a tileset couldn't be stored in a regular Bitmap to begin with,
which is why I also introduced a hack called "mega surfaces":
software surfaces stored in RAM and wrapped inside a Bitmap,
whose sole purpose is to be passed to a Tilemap as tilesets.
Various other minor changes and fixes are included.
2013-09-23 20:21:58 +00:00
|
|
|
/* Mega surface tileset */
|
|
|
|
TEX::bind(atlas.gl.tex);
|
2013-09-01 14:27:21 +00:00
|
|
|
|
Implement a new tileset atlas layout to allow for bigger tilesets
The atlas packing algorithm has been reworked to pack autotiles
and tileset very efficiently into a texture, splitting the tileset
in multiple ways and eliminating the previous duplication of image
data in the atlas across "frames". Animation, which these frames
were designed for, is now done via duplicated buffer frames,
ie. each animation frame has its own VBO and IBO data. This was
not done to save on VRAM (hardly less memory is used), but to
make place for the new atlas layout.
Thanks to this new layout, even with a max texture size of 2048,
one can use tilesets with up to 15000 height. Of course, such
a tileset couldn't be stored in a regular Bitmap to begin with,
which is why I also introduced a hack called "mega surfaces":
software surfaces stored in RAM and wrapped inside a Bitmap,
whose sole purpose is to be passed to a Tilemap as tilesets.
Various other minor changes and fixes are included.
2013-09-23 20:21:58 +00:00
|
|
|
SDL_Surface *tsSurf = tileset->megaSurface();
|
2013-09-01 14:27:21 +00:00
|
|
|
|
2013-12-26 19:18:33 +00:00
|
|
|
for (size_t i = 0; i < blits.size(); ++i)
|
Implement a new tileset atlas layout to allow for bigger tilesets
The atlas packing algorithm has been reworked to pack autotiles
and tileset very efficiently into a texture, splitting the tileset
in multiple ways and eliminating the previous duplication of image
data in the atlas across "frames". Animation, which these frames
were designed for, is now done via duplicated buffer frames,
ie. each animation frame has its own VBO and IBO data. This was
not done to save on VRAM (hardly less memory is used), but to
make place for the new atlas layout.
Thanks to this new layout, even with a max texture size of 2048,
one can use tilesets with up to 15000 height. Of course, such
a tileset couldn't be stored in a regular Bitmap to begin with,
which is why I also introduced a hack called "mega surfaces":
software surfaces stored in RAM and wrapped inside a Bitmap,
whose sole purpose is to be passed to a Tilemap as tilesets.
Various other minor changes and fixes are included.
2013-09-23 20:21:58 +00:00
|
|
|
{
|
2013-12-27 05:11:18 +00:00
|
|
|
const TileAtlas::Blit &blitOp = blits[i];
|
2013-09-01 14:27:21 +00:00
|
|
|
|
2014-07-11 06:31:12 +00:00
|
|
|
GLMeta::subRectImageUpload(tsSurf->w, blitOp.src.x, blitOp.src.y,
|
|
|
|
blitOp.dst.x, blitOp.dst.y, tsLaneW, blitOp.h, tsSurf, GL_RGBA);
|
Implement a new tileset atlas layout to allow for bigger tilesets
The atlas packing algorithm has been reworked to pack autotiles
and tileset very efficiently into a texture, splitting the tileset
in multiple ways and eliminating the previous duplication of image
data in the atlas across "frames". Animation, which these frames
were designed for, is now done via duplicated buffer frames,
ie. each animation frame has its own VBO and IBO data. This was
not done to save on VRAM (hardly less memory is used), but to
make place for the new atlas layout.
Thanks to this new layout, even with a max texture size of 2048,
one can use tilesets with up to 15000 height. Of course, such
a tileset couldn't be stored in a regular Bitmap to begin with,
which is why I also introduced a hack called "mega surfaces":
software surfaces stored in RAM and wrapped inside a Bitmap,
whose sole purpose is to be passed to a Tilemap as tilesets.
Various other minor changes and fixes are included.
2013-09-23 20:21:58 +00:00
|
|
|
}
|
2013-10-16 17:20:36 +00:00
|
|
|
|
2014-07-16 02:53:08 +00:00
|
|
|
GLMeta::subRectImageEnd();
|
Implement a new tileset atlas layout to allow for bigger tilesets
The atlas packing algorithm has been reworked to pack autotiles
and tileset very efficiently into a texture, splitting the tileset
in multiple ways and eliminating the previous duplication of image
data in the atlas across "frames". Animation, which these frames
were designed for, is now done via duplicated buffer frames,
ie. each animation frame has its own VBO and IBO data. This was
not done to save on VRAM (hardly less memory is used), but to
make place for the new atlas layout.
Thanks to this new layout, even with a max texture size of 2048,
one can use tilesets with up to 15000 height. Of course, such
a tileset couldn't be stored in a regular Bitmap to begin with,
which is why I also introduced a hack called "mega surfaces":
software surfaces stored in RAM and wrapped inside a Bitmap,
whose sole purpose is to be passed to a Tilemap as tilesets.
Various other minor changes and fixes are included.
2013-09-23 20:21:58 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Regular tileset */
|
2014-07-16 02:48:40 +00:00
|
|
|
GLMeta::blitBegin(atlas.gl);
|
|
|
|
GLMeta::blitSource(tileset->getGLTypes());
|
2013-09-01 14:27:21 +00:00
|
|
|
|
2013-12-26 19:18:33 +00:00
|
|
|
for (size_t i = 0; i < blits.size(); ++i)
|
Implement a new tileset atlas layout to allow for bigger tilesets
The atlas packing algorithm has been reworked to pack autotiles
and tileset very efficiently into a texture, splitting the tileset
in multiple ways and eliminating the previous duplication of image
data in the atlas across "frames". Animation, which these frames
were designed for, is now done via duplicated buffer frames,
ie. each animation frame has its own VBO and IBO data. This was
not done to save on VRAM (hardly less memory is used), but to
make place for the new atlas layout.
Thanks to this new layout, even with a max texture size of 2048,
one can use tilesets with up to 15000 height. Of course, such
a tileset couldn't be stored in a regular Bitmap to begin with,
which is why I also introduced a hack called "mega surfaces":
software surfaces stored in RAM and wrapped inside a Bitmap,
whose sole purpose is to be passed to a Tilemap as tilesets.
Various other minor changes and fixes are included.
2013-09-23 20:21:58 +00:00
|
|
|
{
|
2013-12-27 05:11:18 +00:00
|
|
|
const TileAtlas::Blit &blitOp = blits[i];
|
2013-09-01 14:27:21 +00:00
|
|
|
|
2014-07-16 02:48:40 +00:00
|
|
|
GLMeta::blitRectangle(IntRect(blitOp.src.x, blitOp.src.y, tsLaneW, blitOp.h),
|
|
|
|
blitOp.dst);
|
Implement a new tileset atlas layout to allow for bigger tilesets
The atlas packing algorithm has been reworked to pack autotiles
and tileset very efficiently into a texture, splitting the tileset
in multiple ways and eliminating the previous duplication of image
data in the atlas across "frames". Animation, which these frames
were designed for, is now done via duplicated buffer frames,
ie. each animation frame has its own VBO and IBO data. This was
not done to save on VRAM (hardly less memory is used), but to
make place for the new atlas layout.
Thanks to this new layout, even with a max texture size of 2048,
one can use tilesets with up to 15000 height. Of course, such
a tileset couldn't be stored in a regular Bitmap to begin with,
which is why I also introduced a hack called "mega surfaces":
software surfaces stored in RAM and wrapped inside a Bitmap,
whose sole purpose is to be passed to a Tilemap as tilesets.
Various other minor changes and fixes are included.
2013-09-23 20:21:58 +00:00
|
|
|
}
|
2014-07-16 02:48:40 +00:00
|
|
|
|
2014-07-16 02:53:08 +00:00
|
|
|
GLMeta::blitEnd();
|
2013-09-01 14:27:21 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int samplePriority(int tileInd)
|
|
|
|
{
|
|
|
|
if (!priorities)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (tileInd > priorities->xSize()-1)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
int value = priorities->at(tileInd);
|
|
|
|
|
|
|
|
if (value > 5)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
|
|
|
|
FloatRect getAutotilePieceRect(int x, int y, /* in pixel coords */
|
|
|
|
int corner)
|
|
|
|
{
|
|
|
|
switch (corner)
|
|
|
|
{
|
|
|
|
case 0 : break;
|
|
|
|
case 1 : x += 16; break;
|
|
|
|
case 2 : x += 16; y += 16; break;
|
|
|
|
case 3 : y += 16; break;
|
|
|
|
default: abort();
|
|
|
|
}
|
|
|
|
|
|
|
|
return FloatRect(x, y, 16, 16);
|
|
|
|
}
|
|
|
|
|
Tilemap: Use vertex shader based autotile animation strategy
Previously, we would just stuff the entire tilemap vertex data
four times into the buffers, with only the autotile vertices
offset according to the animation frame. This meant we could
prepare the buffers once, and then just bind a different offset
for each animation frame without any shader changes, but it also
lead to a huge amount of data being duplicated (and blowing up
the buffer sizes).
The new method only requires one buffer, and instead animates by
recognizing vertices belonging to autotiles in a custom vertex
shader, which offsets them on the fly according to the animation
index.
With giant tilemaps, this method would turn out to be a little
less efficient, but considering the Tilemap is planned to be
rewritten to only hold the range of tiles visible on the screen
in its buffers, the on the fly offsetting will become neglient,
while at the same time the amount of data we have to send to the
GPU everytime the tilemap is updated is greatly reduced; so a
net win in the end.
2014-07-06 17:44:19 +00:00
|
|
|
void handleAutotile(int x, int y, int tileInd, SVVector *array)
|
2013-09-01 14:27:21 +00:00
|
|
|
{
|
|
|
|
/* Which autotile [0-7] */
|
|
|
|
int atInd = tileInd / 48 - 1;
|
|
|
|
/* Which tile pattern of the autotile [0-47] */
|
|
|
|
int subInd = tileInd % 48;
|
|
|
|
|
|
|
|
const StaticRect *pieceRect = &autotileRects[subInd*4];
|
|
|
|
|
Implement a new tileset atlas layout to allow for bigger tilesets
The atlas packing algorithm has been reworked to pack autotiles
and tileset very efficiently into a texture, splitting the tileset
in multiple ways and eliminating the previous duplication of image
data in the atlas across "frames". Animation, which these frames
were designed for, is now done via duplicated buffer frames,
ie. each animation frame has its own VBO and IBO data. This was
not done to save on VRAM (hardly less memory is used), but to
make place for the new atlas layout.
Thanks to this new layout, even with a max texture size of 2048,
one can use tilesets with up to 15000 height. Of course, such
a tileset couldn't be stored in a regular Bitmap to begin with,
which is why I also introduced a hack called "mega surfaces":
software surfaces stored in RAM and wrapped inside a Bitmap,
whose sole purpose is to be passed to a Tilemap as tilesets.
Various other minor changes and fixes are included.
2013-09-23 20:21:58 +00:00
|
|
|
/* Iterate over the 4 tile pieces */
|
2013-09-01 14:27:21 +00:00
|
|
|
for (int i = 0; i < 4; ++i)
|
|
|
|
{
|
|
|
|
FloatRect posRect = getAutotilePieceRect(x*32, y*32, i);
|
|
|
|
FloatRect texRect = pieceRect[i];
|
|
|
|
|
|
|
|
/* Adjust to atlas coordinates */
|
|
|
|
texRect.y += atInd * autotileH;
|
|
|
|
|
Tilemap: Use vertex shader based autotile animation strategy
Previously, we would just stuff the entire tilemap vertex data
four times into the buffers, with only the autotile vertices
offset according to the animation frame. This meant we could
prepare the buffers once, and then just bind a different offset
for each animation frame without any shader changes, but it also
lead to a huge amount of data being duplicated (and blowing up
the buffer sizes).
The new method only requires one buffer, and instead animates by
recognizing vertices belonging to autotiles in a custom vertex
shader, which offsets them on the fly according to the animation
index.
With giant tilemaps, this method would turn out to be a little
less efficient, but considering the Tilemap is planned to be
rewritten to only hold the range of tiles visible on the screen
in its buffers, the on the fly offsetting will become neglient,
while at the same time the amount of data we have to send to the
GPU everytime the tilemap is updated is greatly reduced; so a
net win in the end.
2014-07-06 17:44:19 +00:00
|
|
|
SVertex v[4];
|
|
|
|
Quad::setTexPosRect(v, texRect, posRect);
|
2013-09-01 14:27:21 +00:00
|
|
|
|
Tilemap: Use vertex shader based autotile animation strategy
Previously, we would just stuff the entire tilemap vertex data
four times into the buffers, with only the autotile vertices
offset according to the animation frame. This meant we could
prepare the buffers once, and then just bind a different offset
for each animation frame without any shader changes, but it also
lead to a huge amount of data being duplicated (and blowing up
the buffer sizes).
The new method only requires one buffer, and instead animates by
recognizing vertices belonging to autotiles in a custom vertex
shader, which offsets them on the fly according to the animation
index.
With giant tilemaps, this method would turn out to be a little
less efficient, but considering the Tilemap is planned to be
rewritten to only hold the range of tiles visible on the screen
in its buffers, the on the fly offsetting will become neglient,
while at the same time the amount of data we have to send to the
GPU everytime the tilemap is updated is greatly reduced; so a
net win in the end.
2014-07-06 17:44:19 +00:00
|
|
|
/* Iterate over 4 vertices */
|
|
|
|
for (size_t i = 0; i < 4; ++i)
|
|
|
|
array->push_back(v[i]);
|
2013-09-01 14:27:21 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void handleTile(int x, int y, int z)
|
|
|
|
{
|
2014-07-10 23:07:18 +00:00
|
|
|
int tileInd =
|
|
|
|
tableGetWrapped(mapData, x + viewpPos.x, y + viewpPos.y, z);
|
2013-09-01 14:27:21 +00:00
|
|
|
|
|
|
|
/* Check for empty space */
|
|
|
|
if (tileInd < 48)
|
|
|
|
return;
|
|
|
|
|
|
|
|
int prio = samplePriority(tileInd);
|
|
|
|
|
|
|
|
/* Check for faulty data */
|
|
|
|
if (prio == -1)
|
|
|
|
return;
|
|
|
|
|
Tilemap: Use vertex shader based autotile animation strategy
Previously, we would just stuff the entire tilemap vertex data
four times into the buffers, with only the autotile vertices
offset according to the animation frame. This meant we could
prepare the buffers once, and then just bind a different offset
for each animation frame without any shader changes, but it also
lead to a huge amount of data being duplicated (and blowing up
the buffer sizes).
The new method only requires one buffer, and instead animates by
recognizing vertices belonging to autotiles in a custom vertex
shader, which offsets them on the fly according to the animation
index.
With giant tilemaps, this method would turn out to be a little
less efficient, but considering the Tilemap is planned to be
rewritten to only hold the range of tiles visible on the screen
in its buffers, the on the fly offsetting will become neglient,
while at the same time the amount of data we have to send to the
GPU everytime the tilemap is updated is greatly reduced; so a
net win in the end.
2014-07-06 17:44:19 +00:00
|
|
|
SVVector *targetArray;
|
2013-09-01 14:27:21 +00:00
|
|
|
|
|
|
|
/* Prio 0 tiles are all part of the same ground layer */
|
|
|
|
if (prio == 0)
|
|
|
|
{
|
|
|
|
targetArray = &groundVert;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
int scanInd = y + prio;
|
|
|
|
targetArray = &scanrowVert[scanInd];
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Check for autotile */
|
|
|
|
if (tileInd < 48*8)
|
|
|
|
{
|
Implement a new tileset atlas layout to allow for bigger tilesets
The atlas packing algorithm has been reworked to pack autotiles
and tileset very efficiently into a texture, splitting the tileset
in multiple ways and eliminating the previous duplication of image
data in the atlas across "frames". Animation, which these frames
were designed for, is now done via duplicated buffer frames,
ie. each animation frame has its own VBO and IBO data. This was
not done to save on VRAM (hardly less memory is used), but to
make place for the new atlas layout.
Thanks to this new layout, even with a max texture size of 2048,
one can use tilesets with up to 15000 height. Of course, such
a tileset couldn't be stored in a regular Bitmap to begin with,
which is why I also introduced a hack called "mega surfaces":
software surfaces stored in RAM and wrapped inside a Bitmap,
whose sole purpose is to be passed to a Tilemap as tilesets.
Various other minor changes and fixes are included.
2013-09-23 20:21:58 +00:00
|
|
|
handleAutotile(x, y, tileInd, targetArray);
|
2013-09-01 14:27:21 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
int tsInd = tileInd - 48*8;
|
|
|
|
int tileX = tsInd % 8;
|
|
|
|
int tileY = tsInd / 8;
|
|
|
|
|
2013-09-29 23:38:46 +00:00
|
|
|
Vec2i texPos = TileAtlas::tileToAtlasCoor(tileX, tileY, atlas.efTilesetH, atlas.size.y);
|
Implement a new tileset atlas layout to allow for bigger tilesets
The atlas packing algorithm has been reworked to pack autotiles
and tileset very efficiently into a texture, splitting the tileset
in multiple ways and eliminating the previous duplication of image
data in the atlas across "frames". Animation, which these frames
were designed for, is now done via duplicated buffer frames,
ie. each animation frame has its own VBO and IBO data. This was
not done to save on VRAM (hardly less memory is used), but to
make place for the new atlas layout.
Thanks to this new layout, even with a max texture size of 2048,
one can use tilesets with up to 15000 height. Of course, such
a tileset couldn't be stored in a regular Bitmap to begin with,
which is why I also introduced a hack called "mega surfaces":
software surfaces stored in RAM and wrapped inside a Bitmap,
whose sole purpose is to be passed to a Tilemap as tilesets.
Various other minor changes and fixes are included.
2013-09-23 20:21:58 +00:00
|
|
|
FloatRect texRect((float) texPos.x+.5, (float) texPos.y+.5, 31, 31);
|
2013-09-01 14:27:21 +00:00
|
|
|
FloatRect posRect(x*32, y*32, 32, 32);
|
|
|
|
|
|
|
|
SVertex v[4];
|
|
|
|
Quad::setTexPosRect(v, texRect, posRect);
|
|
|
|
|
Tilemap: Use vertex shader based autotile animation strategy
Previously, we would just stuff the entire tilemap vertex data
four times into the buffers, with only the autotile vertices
offset according to the animation frame. This meant we could
prepare the buffers once, and then just bind a different offset
for each animation frame without any shader changes, but it also
lead to a huge amount of data being duplicated (and blowing up
the buffer sizes).
The new method only requires one buffer, and instead animates by
recognizing vertices belonging to autotiles in a custom vertex
shader, which offsets them on the fly according to the animation
index.
With giant tilemaps, this method would turn out to be a little
less efficient, but considering the Tilemap is planned to be
rewritten to only hold the range of tiles visible on the screen
in its buffers, the on the fly offsetting will become neglient,
while at the same time the amount of data we have to send to the
GPU everytime the tilemap is updated is greatly reduced; so a
net win in the end.
2014-07-06 17:44:19 +00:00
|
|
|
for (size_t i = 0; i < 4; ++i)
|
|
|
|
targetArray->push_back(v[i]);
|
2013-09-01 14:27:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void clearQuadArrays()
|
|
|
|
{
|
Tilemap: Use vertex shader based autotile animation strategy
Previously, we would just stuff the entire tilemap vertex data
four times into the buffers, with only the autotile vertices
offset according to the animation frame. This meant we could
prepare the buffers once, and then just bind a different offset
for each animation frame without any shader changes, but it also
lead to a huge amount of data being duplicated (and blowing up
the buffer sizes).
The new method only requires one buffer, and instead animates by
recognizing vertices belonging to autotiles in a custom vertex
shader, which offsets them on the fly according to the animation
index.
With giant tilemaps, this method would turn out to be a little
less efficient, but considering the Tilemap is planned to be
rewritten to only hold the range of tiles visible on the screen
in its buffers, the on the fly offsetting will become neglient,
while at the same time the amount of data we have to send to the
GPU everytime the tilemap is updated is greatly reduced; so a
net win in the end.
2014-07-06 17:44:19 +00:00
|
|
|
groundVert.clear();
|
2013-12-26 19:18:33 +00:00
|
|
|
|
2014-07-10 23:07:18 +00:00
|
|
|
for (size_t i = 0; i < scanrowsMax; ++i)
|
|
|
|
scanrowVert[i].clear();
|
2013-09-01 14:27:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void buildQuadArray()
|
|
|
|
{
|
|
|
|
clearQuadArrays();
|
|
|
|
|
2014-07-10 23:07:18 +00:00
|
|
|
for (int x = 0; x < viewpW; ++x)
|
|
|
|
for (int y = 0; y < viewpH; ++y)
|
|
|
|
for (int z = 0; z < mapData->zSize(); ++z)
|
2013-09-01 14:27:21 +00:00
|
|
|
handleTile(x, y, z);
|
|
|
|
}
|
|
|
|
|
2013-12-26 19:18:33 +00:00
|
|
|
static size_t quadDataSize(size_t quadCount)
|
2013-09-01 14:27:21 +00:00
|
|
|
{
|
|
|
|
return quadCount * sizeof(SVertex) * 4;
|
|
|
|
}
|
|
|
|
|
2013-12-26 19:18:33 +00:00
|
|
|
size_t scanrowSize(size_t index)
|
2013-09-01 14:27:21 +00:00
|
|
|
{
|
|
|
|
return scanrowBases[index+1] - scanrowBases[index];
|
|
|
|
}
|
|
|
|
|
|
|
|
void uploadBuffers()
|
|
|
|
{
|
|
|
|
/* Calculate total quad count */
|
Tilemap: Use vertex shader based autotile animation strategy
Previously, we would just stuff the entire tilemap vertex data
four times into the buffers, with only the autotile vertices
offset according to the animation frame. This meant we could
prepare the buffers once, and then just bind a different offset
for each animation frame without any shader changes, but it also
lead to a huge amount of data being duplicated (and blowing up
the buffer sizes).
The new method only requires one buffer, and instead animates by
recognizing vertices belonging to autotiles in a custom vertex
shader, which offsets them on the fly according to the animation
index.
With giant tilemaps, this method would turn out to be a little
less efficient, but considering the Tilemap is planned to be
rewritten to only hold the range of tiles visible on the screen
in its buffers, the on the fly offsetting will become neglient,
while at the same time the amount of data we have to send to the
GPU everytime the tilemap is updated is greatly reduced; so a
net win in the end.
2014-07-06 17:44:19 +00:00
|
|
|
size_t groundQuadCount = groundVert.size() / 4;
|
2013-12-26 19:18:33 +00:00
|
|
|
size_t quadCount = groundQuadCount;
|
2013-09-01 14:27:21 +00:00
|
|
|
|
2014-07-10 23:07:18 +00:00
|
|
|
for (size_t i = 0; i < scanrowsMax; ++i)
|
2013-09-01 14:27:21 +00:00
|
|
|
{
|
|
|
|
scanrowBases[i] = quadCount;
|
Tilemap: Use vertex shader based autotile animation strategy
Previously, we would just stuff the entire tilemap vertex data
four times into the buffers, with only the autotile vertices
offset according to the animation frame. This meant we could
prepare the buffers once, and then just bind a different offset
for each animation frame without any shader changes, but it also
lead to a huge amount of data being duplicated (and blowing up
the buffer sizes).
The new method only requires one buffer, and instead animates by
recognizing vertices belonging to autotiles in a custom vertex
shader, which offsets them on the fly according to the animation
index.
With giant tilemaps, this method would turn out to be a little
less efficient, but considering the Tilemap is planned to be
rewritten to only hold the range of tiles visible on the screen
in its buffers, the on the fly offsetting will become neglient,
while at the same time the amount of data we have to send to the
GPU everytime the tilemap is updated is greatly reduced; so a
net win in the end.
2014-07-06 17:44:19 +00:00
|
|
|
quadCount += scanrowVert[i].size() / 4;
|
2013-09-01 14:27:21 +00:00
|
|
|
}
|
|
|
|
|
2014-07-10 23:07:18 +00:00
|
|
|
scanrowBases[scanrowsMax] = quadCount;
|
Implement a new tileset atlas layout to allow for bigger tilesets
The atlas packing algorithm has been reworked to pack autotiles
and tileset very efficiently into a texture, splitting the tileset
in multiple ways and eliminating the previous duplication of image
data in the atlas across "frames". Animation, which these frames
were designed for, is now done via duplicated buffer frames,
ie. each animation frame has its own VBO and IBO data. This was
not done to save on VRAM (hardly less memory is used), but to
make place for the new atlas layout.
Thanks to this new layout, even with a max texture size of 2048,
one can use tilesets with up to 15000 height. Of course, such
a tileset couldn't be stored in a regular Bitmap to begin with,
which is why I also introduced a hack called "mega surfaces":
software surfaces stored in RAM and wrapped inside a Bitmap,
whose sole purpose is to be passed to a Tilemap as tilesets.
Various other minor changes and fixes are included.
2013-09-23 20:21:58 +00:00
|
|
|
|
2013-09-01 14:27:21 +00:00
|
|
|
VBO::bind(tiles.vbo);
|
|
|
|
VBO::allocEmpty(quadDataSize(quadCount));
|
|
|
|
|
Tilemap: Use vertex shader based autotile animation strategy
Previously, we would just stuff the entire tilemap vertex data
four times into the buffers, with only the autotile vertices
offset according to the animation frame. This meant we could
prepare the buffers once, and then just bind a different offset
for each animation frame without any shader changes, but it also
lead to a huge amount of data being duplicated (and blowing up
the buffer sizes).
The new method only requires one buffer, and instead animates by
recognizing vertices belonging to autotiles in a custom vertex
shader, which offsets them on the fly according to the animation
index.
With giant tilemaps, this method would turn out to be a little
less efficient, but considering the Tilemap is planned to be
rewritten to only hold the range of tiles visible on the screen
in its buffers, the on the fly offsetting will become neglient,
while at the same time the amount of data we have to send to the
GPU everytime the tilemap is updated is greatly reduced; so a
net win in the end.
2014-07-06 17:44:19 +00:00
|
|
|
VBO::uploadSubData(0, quadDataSize(groundQuadCount), &groundVert[0]);
|
Implement a new tileset atlas layout to allow for bigger tilesets
The atlas packing algorithm has been reworked to pack autotiles
and tileset very efficiently into a texture, splitting the tileset
in multiple ways and eliminating the previous duplication of image
data in the atlas across "frames". Animation, which these frames
were designed for, is now done via duplicated buffer frames,
ie. each animation frame has its own VBO and IBO data. This was
not done to save on VRAM (hardly less memory is used), but to
make place for the new atlas layout.
Thanks to this new layout, even with a max texture size of 2048,
one can use tilesets with up to 15000 height. Of course, such
a tileset couldn't be stored in a regular Bitmap to begin with,
which is why I also introduced a hack called "mega surfaces":
software surfaces stored in RAM and wrapped inside a Bitmap,
whose sole purpose is to be passed to a Tilemap as tilesets.
Various other minor changes and fixes are included.
2013-09-23 20:21:58 +00:00
|
|
|
|
2014-07-10 23:07:18 +00:00
|
|
|
for (size_t i = 0; i < scanrowsMax; ++i)
|
Tilemap: Use vertex shader based autotile animation strategy
Previously, we would just stuff the entire tilemap vertex data
four times into the buffers, with only the autotile vertices
offset according to the animation frame. This meant we could
prepare the buffers once, and then just bind a different offset
for each animation frame without any shader changes, but it also
lead to a huge amount of data being duplicated (and blowing up
the buffer sizes).
The new method only requires one buffer, and instead animates by
recognizing vertices belonging to autotiles in a custom vertex
shader, which offsets them on the fly according to the animation
index.
With giant tilemaps, this method would turn out to be a little
less efficient, but considering the Tilemap is planned to be
rewritten to only hold the range of tiles visible on the screen
in its buffers, the on the fly offsetting will become neglient,
while at the same time the amount of data we have to send to the
GPU everytime the tilemap is updated is greatly reduced; so a
net win in the end.
2014-07-06 17:44:19 +00:00
|
|
|
{
|
|
|
|
if (scanrowVert[i].empty())
|
|
|
|
continue;
|
Implement a new tileset atlas layout to allow for bigger tilesets
The atlas packing algorithm has been reworked to pack autotiles
and tileset very efficiently into a texture, splitting the tileset
in multiple ways and eliminating the previous duplication of image
data in the atlas across "frames". Animation, which these frames
were designed for, is now done via duplicated buffer frames,
ie. each animation frame has its own VBO and IBO data. This was
not done to save on VRAM (hardly less memory is used), but to
make place for the new atlas layout.
Thanks to this new layout, even with a max texture size of 2048,
one can use tilesets with up to 15000 height. Of course, such
a tileset couldn't be stored in a regular Bitmap to begin with,
which is why I also introduced a hack called "mega surfaces":
software surfaces stored in RAM and wrapped inside a Bitmap,
whose sole purpose is to be passed to a Tilemap as tilesets.
Various other minor changes and fixes are included.
2013-09-23 20:21:58 +00:00
|
|
|
|
Tilemap: Use vertex shader based autotile animation strategy
Previously, we would just stuff the entire tilemap vertex data
four times into the buffers, with only the autotile vertices
offset according to the animation frame. This meant we could
prepare the buffers once, and then just bind a different offset
for each animation frame without any shader changes, but it also
lead to a huge amount of data being duplicated (and blowing up
the buffer sizes).
The new method only requires one buffer, and instead animates by
recognizing vertices belonging to autotiles in a custom vertex
shader, which offsets them on the fly according to the animation
index.
With giant tilemaps, this method would turn out to be a little
less efficient, but considering the Tilemap is planned to be
rewritten to only hold the range of tiles visible on the screen
in its buffers, the on the fly offsetting will become neglient,
while at the same time the amount of data we have to send to the
GPU everytime the tilemap is updated is greatly reduced; so a
net win in the end.
2014-07-06 17:44:19 +00:00
|
|
|
VBO::uploadSubData(quadDataSize(scanrowBases[i]),
|
|
|
|
quadDataSize(scanrowSize(i)), &scanrowVert[i][0]);
|
2013-09-01 14:27:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
VBO::unbind();
|
|
|
|
|
|
|
|
/* Ensure global IBO size */
|
Tilemap: Use vertex shader based autotile animation strategy
Previously, we would just stuff the entire tilemap vertex data
four times into the buffers, with only the autotile vertices
offset according to the animation frame. This meant we could
prepare the buffers once, and then just bind a different offset
for each animation frame without any shader changes, but it also
lead to a huge amount of data being duplicated (and blowing up
the buffer sizes).
The new method only requires one buffer, and instead animates by
recognizing vertices belonging to autotiles in a custom vertex
shader, which offsets them on the fly according to the animation
index.
With giant tilemaps, this method would turn out to be a little
less efficient, but considering the Tilemap is planned to be
rewritten to only hold the range of tiles visible on the screen
in its buffers, the on the fly offsetting will become neglient,
while at the same time the amount of data we have to send to the
GPU everytime the tilemap is updated is greatly reduced; so a
net win in the end.
2014-07-06 17:44:19 +00:00
|
|
|
shState->ensureQuadIBO(quadCount);
|
|
|
|
}
|
|
|
|
|
|
|
|
void bindShader(ShaderBase *&shaderVar)
|
|
|
|
{
|
|
|
|
if (tiles.animated)
|
|
|
|
{
|
|
|
|
TilemapShader &tilemapShader = shState->shaders().tilemap;
|
|
|
|
tilemapShader.bind();
|
|
|
|
tilemapShader.setAniIndex(tiles.frameIdx);
|
|
|
|
shaderVar = &tilemapShader;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
shaderVar = &shState->shaders().simple;
|
|
|
|
shaderVar->bind();
|
|
|
|
}
|
|
|
|
|
|
|
|
shaderVar->applyViewportProj();
|
2013-09-01 14:27:21 +00:00
|
|
|
}
|
|
|
|
|
Tilemap: Use vertex shader based autotile animation strategy
Previously, we would just stuff the entire tilemap vertex data
four times into the buffers, with only the autotile vertices
offset according to the animation frame. This meant we could
prepare the buffers once, and then just bind a different offset
for each animation frame without any shader changes, but it also
lead to a huge amount of data being duplicated (and blowing up
the buffer sizes).
The new method only requires one buffer, and instead animates by
recognizing vertices belonging to autotiles in a custom vertex
shader, which offsets them on the fly according to the animation
index.
With giant tilemaps, this method would turn out to be a little
less efficient, but considering the Tilemap is planned to be
rewritten to only hold the range of tiles visible on the screen
in its buffers, the on the fly offsetting will become neglient,
while at the same time the amount of data we have to send to the
GPU everytime the tilemap is updated is greatly reduced; so a
net win in the end.
2014-07-06 17:44:19 +00:00
|
|
|
void bindAtlas(ShaderBase &shader)
|
2013-09-01 14:27:21 +00:00
|
|
|
{
|
2013-09-06 10:26:41 +00:00
|
|
|
TEX::bind(atlas.gl.tex);
|
Implement a new tileset atlas layout to allow for bigger tilesets
The atlas packing algorithm has been reworked to pack autotiles
and tileset very efficiently into a texture, splitting the tileset
in multiple ways and eliminating the previous duplication of image
data in the atlas across "frames". Animation, which these frames
were designed for, is now done via duplicated buffer frames,
ie. each animation frame has its own VBO and IBO data. This was
not done to save on VRAM (hardly less memory is used), but to
make place for the new atlas layout.
Thanks to this new layout, even with a max texture size of 2048,
one can use tilesets with up to 15000 height. Of course, such
a tileset couldn't be stored in a regular Bitmap to begin with,
which is why I also introduced a hack called "mega surfaces":
software surfaces stored in RAM and wrapped inside a Bitmap,
whose sole purpose is to be passed to a Tilemap as tilesets.
Various other minor changes and fixes are included.
2013-09-23 20:21:58 +00:00
|
|
|
shader.setTexSize(atlas.size);
|
2013-09-01 14:27:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool sampleFlashColor(Vec4 &out, int x, int y)
|
|
|
|
{
|
2014-07-10 23:07:18 +00:00
|
|
|
int16_t packed = tableGetWrapped(flashData, x, y);
|
2013-09-01 14:27:21 +00:00
|
|
|
|
|
|
|
if (packed == 0)
|
|
|
|
return false;
|
|
|
|
|
2013-09-23 06:27:28 +00:00
|
|
|
const float max = 0xF;
|
2013-09-01 14:27:21 +00:00
|
|
|
|
2013-09-23 06:27:28 +00:00
|
|
|
float b = ((packed & 0x000F) >> 0) / max;
|
|
|
|
float g = ((packed & 0x00F0) >> 4) / max;
|
|
|
|
float r = ((packed & 0x0F00) >> 8) / max;
|
2013-09-01 14:27:21 +00:00
|
|
|
|
|
|
|
out = Vec4(r, g, b, 1);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void updateFlash()
|
|
|
|
{
|
2014-07-10 23:07:18 +00:00
|
|
|
if (!flashData)
|
|
|
|
return;
|
|
|
|
|
2013-12-26 19:18:33 +00:00
|
|
|
std::vector<CVertex> vertices;
|
2013-09-01 14:27:21 +00:00
|
|
|
|
2014-07-10 23:07:18 +00:00
|
|
|
for (int x = 0; x < viewpW; ++x)
|
|
|
|
for (int y = 0; y < viewpH; ++y)
|
2013-09-01 14:27:21 +00:00
|
|
|
{
|
|
|
|
Vec4 color;
|
2014-07-10 23:07:18 +00:00
|
|
|
if (!sampleFlashColor(color, x+viewpPos.x, y+viewpPos.y))
|
2013-09-01 14:27:21 +00:00
|
|
|
continue;
|
|
|
|
|
|
|
|
FloatRect posRect(x*32, y*32, 32, 32);
|
|
|
|
|
|
|
|
CVertex v[4];
|
|
|
|
Quad::setPosRect(v, posRect);
|
|
|
|
Quad::setColor(v, color);
|
|
|
|
|
2013-12-26 19:18:33 +00:00
|
|
|
for (size_t i = 0; i < 4; ++i)
|
|
|
|
vertices.push_back(v[i]);
|
2013-09-01 14:27:21 +00:00
|
|
|
}
|
|
|
|
|
2013-12-26 19:18:33 +00:00
|
|
|
flash.quadCount = vertices.size() / 4;
|
2013-09-01 14:27:21 +00:00
|
|
|
|
|
|
|
if (flash.quadCount == 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
VBO::bind(flash.vbo);
|
2013-12-26 19:18:33 +00:00
|
|
|
VBO::uploadData(sizeof(CVertex) * vertices.size(), &vertices[0]);
|
2013-09-01 14:27:21 +00:00
|
|
|
VBO::unbind();
|
|
|
|
|
|
|
|
/* Ensure global IBO size */
|
2013-10-09 10:30:33 +00:00
|
|
|
shState->ensureQuadIBO(flash.quadCount);
|
2013-09-01 14:27:21 +00:00
|
|
|
}
|
|
|
|
|
2014-07-10 23:07:18 +00:00
|
|
|
void updateActiveElements(std::vector<int> &scanrowInd)
|
2013-09-01 14:27:21 +00:00
|
|
|
{
|
2014-07-10 23:07:18 +00:00
|
|
|
elem.ground->updateVboCount();
|
2013-09-01 14:27:21 +00:00
|
|
|
|
2014-07-10 23:07:18 +00:00
|
|
|
for (size_t i = 0; i < scanrowsMax; ++i)
|
2013-09-01 14:27:21 +00:00
|
|
|
{
|
2014-07-10 23:07:18 +00:00
|
|
|
if (i < scanrowInd.size())
|
|
|
|
{
|
|
|
|
int index = scanrowInd[i];
|
|
|
|
elem.scanrows[i]->setVisible(visible);
|
|
|
|
elem.scanrows[i]->setIndex(index);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Hide unused rows */
|
|
|
|
elem.scanrows[i]->setVisible(false);
|
|
|
|
}
|
2013-09-01 14:27:21 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-07-10 23:07:18 +00:00
|
|
|
void updateSceneElements()
|
2013-09-01 14:27:21 +00:00
|
|
|
{
|
2014-07-10 23:07:18 +00:00
|
|
|
/* Only allocate elements for non-emtpy scanrows */
|
2013-12-26 19:18:33 +00:00
|
|
|
std::vector<int> scanrowInd;
|
|
|
|
|
2014-07-10 23:07:18 +00:00
|
|
|
for (size_t i = 0; i < scanrowsMax; ++i)
|
Tilemap: Use vertex shader based autotile animation strategy
Previously, we would just stuff the entire tilemap vertex data
four times into the buffers, with only the autotile vertices
offset according to the animation frame. This meant we could
prepare the buffers once, and then just bind a different offset
for each animation frame without any shader changes, but it also
lead to a huge amount of data being duplicated (and blowing up
the buffer sizes).
The new method only requires one buffer, and instead animates by
recognizing vertices belonging to autotiles in a custom vertex
shader, which offsets them on the fly according to the animation
index.
With giant tilemaps, this method would turn out to be a little
less efficient, but considering the Tilemap is planned to be
rewritten to only hold the range of tiles visible on the screen
in its buffers, the on the fly offsetting will become neglient,
while at the same time the amount of data we have to send to the
GPU everytime the tilemap is updated is greatly reduced; so a
net win in the end.
2014-07-06 17:44:19 +00:00
|
|
|
if (scanrowVert[i].size() > 0)
|
2013-12-26 19:18:33 +00:00
|
|
|
scanrowInd.push_back(i);
|
2013-09-01 14:27:21 +00:00
|
|
|
|
2014-07-10 23:07:18 +00:00
|
|
|
updateActiveElements(scanrowInd);
|
|
|
|
elem.activeRows = scanrowInd.size();
|
|
|
|
zOrderDirty = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void hideElements()
|
|
|
|
{
|
|
|
|
elem.ground->setVisible(false);
|
|
|
|
|
|
|
|
for (size_t i = 0; i < scanrowsMax; ++i)
|
|
|
|
elem.scanrows[i]->setVisible(false);
|
2013-09-01 14:27:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void updateZOrder()
|
|
|
|
{
|
2014-07-10 23:07:18 +00:00
|
|
|
if (elem.activeRows == 0)
|
2013-10-13 10:58:56 +00:00
|
|
|
return;
|
|
|
|
|
2014-07-10 23:07:18 +00:00
|
|
|
for (size_t i = 0; i < elem.activeRows; ++i)
|
2013-09-27 02:42:22 +00:00
|
|
|
elem.scanrows[i]->initUpdateZ();
|
|
|
|
|
2014-07-10 23:07:18 +00:00
|
|
|
ScanRow *prev = elem.scanrows[0];
|
2013-10-13 10:58:56 +00:00
|
|
|
prev->finiUpdateZ(0);
|
|
|
|
|
2014-07-10 23:07:18 +00:00
|
|
|
for (size_t i = 1; i < elem.activeRows; ++i)
|
2013-10-13 10:58:56 +00:00
|
|
|
{
|
|
|
|
ScanRow *row = elem.scanrows[i];
|
|
|
|
row->finiUpdateZ(prev);
|
|
|
|
prev = row;
|
|
|
|
}
|
2013-09-01 14:27:21 +00:00
|
|
|
}
|
|
|
|
|
2013-10-13 20:00:38 +00:00
|
|
|
/* When there are two or more scanrows with no other
|
|
|
|
* elements between them in the scene list, we can
|
|
|
|
* render them in a batch (as the scanrow data itself
|
|
|
|
* is ordered sequentially in VRAM). Every frame, we
|
|
|
|
* scan the scene list for such sequential rows and
|
|
|
|
* batch them up for drawing. The first row of the batch
|
|
|
|
* (the "batch head") executes the draw call, all others
|
|
|
|
* are muted via the 'batchedFlag'. For simplicity,
|
|
|
|
* single sized batches are possible. */
|
|
|
|
void prepareScanrowBatches()
|
|
|
|
{
|
2014-07-10 23:07:18 +00:00
|
|
|
ScanRow *const *scanrows = elem.scanrows;
|
2013-10-13 20:00:38 +00:00
|
|
|
|
2014-07-10 23:07:18 +00:00
|
|
|
for (size_t i = 0; i < elem.activeRows; ++i)
|
2013-10-13 20:00:38 +00:00
|
|
|
{
|
|
|
|
ScanRow *batchHead = scanrows[i];
|
|
|
|
batchHead->batchedFlag = false;
|
|
|
|
|
|
|
|
GLsizei vboBatchCount = batchHead->vboCount;
|
|
|
|
IntruListLink<SceneElement> *iter = &batchHead->link;
|
|
|
|
|
2014-07-10 23:07:18 +00:00
|
|
|
for (i = i+1; i < elem.activeRows; ++i)
|
2013-10-13 20:00:38 +00:00
|
|
|
{
|
|
|
|
iter = iter->next;
|
|
|
|
ScanRow *row = scanrows[i];
|
|
|
|
|
|
|
|
/* Check if the next SceneElement is also
|
|
|
|
* the next scanrow in our list. If not,
|
|
|
|
* the current batch is complete */
|
|
|
|
if (iter != &row->link)
|
|
|
|
break;
|
|
|
|
|
|
|
|
vboBatchCount += row->vboCount;
|
|
|
|
row->batchedFlag = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
batchHead->vboBatchCount = vboBatchCount;
|
|
|
|
--i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-07-10 23:07:18 +00:00
|
|
|
void updateMapViewport()
|
|
|
|
{
|
|
|
|
int tileOX, tileOY;
|
|
|
|
|
|
|
|
if (offset.x >= 0)
|
|
|
|
tileOX = offset.x / 32;
|
|
|
|
else
|
|
|
|
tileOX = -(-(offset.x-31) / 32);
|
|
|
|
|
|
|
|
if (offset.y >= 0)
|
|
|
|
tileOY = offset.y / 32;
|
|
|
|
else
|
|
|
|
tileOY = -(-(offset.y-31) / 32);
|
|
|
|
|
|
|
|
bool dirty = false;
|
|
|
|
|
|
|
|
if (tileOX < viewpPos.x || tileOX + 21 > viewpPos.x + viewpW)
|
|
|
|
{
|
|
|
|
viewpPos.x = tileOX;
|
|
|
|
dirty = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (tileOY < viewpPos.y || tileOY + 16 > viewpPos.y + viewpH)
|
|
|
|
{
|
|
|
|
viewpPos.y = tileOY;
|
|
|
|
dirty = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (dirty)
|
|
|
|
{
|
|
|
|
buffersDirty = true;
|
|
|
|
flashDirty = true;
|
|
|
|
updatePosition();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-09-01 14:27:21 +00:00
|
|
|
void prepare()
|
|
|
|
{
|
|
|
|
if (!verifyResources())
|
|
|
|
{
|
2014-07-10 23:07:18 +00:00
|
|
|
if (tilemapReady)
|
|
|
|
hideElements();
|
2013-09-01 14:27:21 +00:00
|
|
|
tilemapReady = false;
|
2014-07-10 23:07:18 +00:00
|
|
|
|
2013-09-01 14:27:21 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (atlasSizeDirty)
|
|
|
|
{
|
|
|
|
allocateAtlas();
|
|
|
|
atlasSizeDirty = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (atlasDirty)
|
|
|
|
{
|
|
|
|
buildAtlas();
|
|
|
|
atlasDirty = false;
|
|
|
|
}
|
|
|
|
|
2014-07-10 23:07:18 +00:00
|
|
|
if (mapViewportDirty)
|
|
|
|
{
|
|
|
|
updateMapViewport();
|
|
|
|
mapViewportDirty = false;
|
|
|
|
}
|
|
|
|
|
2013-09-01 14:27:21 +00:00
|
|
|
if (buffersDirty)
|
|
|
|
{
|
|
|
|
buildQuadArray();
|
|
|
|
uploadBuffers();
|
2014-07-10 23:07:18 +00:00
|
|
|
updateSceneElements();
|
2013-09-01 14:27:21 +00:00
|
|
|
buffersDirty = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (flashDirty)
|
|
|
|
{
|
|
|
|
updateFlash();
|
|
|
|
flashDirty = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (zOrderDirty)
|
|
|
|
{
|
|
|
|
updateZOrder();
|
|
|
|
zOrderDirty = false;
|
|
|
|
}
|
|
|
|
|
2013-10-13 20:00:38 +00:00
|
|
|
prepareScanrowBatches();
|
|
|
|
|
2013-09-01 14:27:21 +00:00
|
|
|
tilemapReady = true;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
GroundLayer::GroundLayer(TilemapPrivate *p, Viewport *viewport)
|
2013-09-27 02:42:22 +00:00
|
|
|
: ViewportElement(viewport, 0, p->elem.groundStamp),
|
2014-07-10 23:07:18 +00:00
|
|
|
vboCount(0),
|
2013-09-01 14:27:21 +00:00
|
|
|
p(p)
|
|
|
|
{
|
|
|
|
onGeometryChange(scene->getGeometry());
|
|
|
|
}
|
|
|
|
|
2014-07-10 23:07:18 +00:00
|
|
|
void GroundLayer::updateVboCount()
|
|
|
|
{
|
|
|
|
vboCount = p->scanrowBases[0] * 6;
|
|
|
|
}
|
|
|
|
|
2013-09-01 14:27:21 +00:00
|
|
|
void GroundLayer::draw()
|
|
|
|
{
|
Tilemap: Use vertex shader based autotile animation strategy
Previously, we would just stuff the entire tilemap vertex data
four times into the buffers, with only the autotile vertices
offset according to the animation frame. This meant we could
prepare the buffers once, and then just bind a different offset
for each animation frame without any shader changes, but it also
lead to a huge amount of data being duplicated (and blowing up
the buffer sizes).
The new method only requires one buffer, and instead animates by
recognizing vertices belonging to autotiles in a custom vertex
shader, which offsets them on the fly according to the animation
index.
With giant tilemaps, this method would turn out to be a little
less efficient, but considering the Tilemap is planned to be
rewritten to only hold the range of tiles visible on the screen
in its buffers, the on the fly offsetting will become neglient,
while at the same time the amount of data we have to send to the
GPU everytime the tilemap is updated is greatly reduced; so a
net win in the end.
2014-07-06 17:44:19 +00:00
|
|
|
ShaderBase *shader;
|
2013-09-23 05:15:01 +00:00
|
|
|
|
Tilemap: Use vertex shader based autotile animation strategy
Previously, we would just stuff the entire tilemap vertex data
four times into the buffers, with only the autotile vertices
offset according to the animation frame. This meant we could
prepare the buffers once, and then just bind a different offset
for each animation frame without any shader changes, but it also
lead to a huge amount of data being duplicated (and blowing up
the buffer sizes).
The new method only requires one buffer, and instead animates by
recognizing vertices belonging to autotiles in a custom vertex
shader, which offsets them on the fly according to the animation
index.
With giant tilemaps, this method would turn out to be a little
less efficient, but considering the Tilemap is planned to be
rewritten to only hold the range of tiles visible on the screen
in its buffers, the on the fly offsetting will become neglient,
while at the same time the amount of data we have to send to the
GPU everytime the tilemap is updated is greatly reduced; so a
net win in the end.
2014-07-06 17:44:19 +00:00
|
|
|
p->bindShader(shader);
|
|
|
|
p->bindAtlas(*shader);
|
2013-09-01 14:27:21 +00:00
|
|
|
|
2014-07-13 12:03:18 +00:00
|
|
|
GLMeta::vaoBind(p->tiles.vao);
|
2013-09-01 14:27:21 +00:00
|
|
|
|
2014-07-10 23:07:18 +00:00
|
|
|
shader->setTranslation(p->dispPos);
|
|
|
|
drawInt();
|
2013-09-01 14:27:21 +00:00
|
|
|
|
2014-07-13 12:03:18 +00:00
|
|
|
GLMeta::vaoUnbind(p->tiles.vao);
|
|
|
|
|
2013-09-01 14:27:21 +00:00
|
|
|
if (p->flash.quadCount > 0)
|
|
|
|
{
|
2014-07-13 12:03:18 +00:00
|
|
|
GLMeta::vaoBind(p->flash.vao);
|
2013-09-01 14:27:21 +00:00
|
|
|
glState.blendMode.pushSet(BlendAddition);
|
|
|
|
|
2013-12-11 04:22:13 +00:00
|
|
|
FlashMapShader &shader = shState->shaders().flashMap;
|
2013-09-23 05:15:01 +00:00
|
|
|
shader.bind();
|
|
|
|
shader.applyViewportProj();
|
2013-09-23 06:27:28 +00:00
|
|
|
shader.setAlpha(flashAlpha[p->flash.alphaIdx] / 255.f);
|
2014-07-10 23:07:18 +00:00
|
|
|
shader.setTranslation(p->dispPos);
|
2013-09-23 05:15:01 +00:00
|
|
|
|
2014-07-10 23:07:18 +00:00
|
|
|
drawFlashInt();
|
2013-09-01 14:27:21 +00:00
|
|
|
|
|
|
|
glState.blendMode.pop();
|
|
|
|
|
2014-07-13 12:03:18 +00:00
|
|
|
GLMeta::vaoUnbind(p->flash.vao);
|
|
|
|
}
|
2013-09-01 14:27:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void GroundLayer::drawInt()
|
|
|
|
{
|
2014-07-11 00:09:53 +00:00
|
|
|
gl.DrawElements(GL_TRIANGLES, vboCount, _GL_INDEX_TYPE, (GLvoid*) 0);
|
2013-09-01 14:27:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void GroundLayer::drawFlashInt()
|
|
|
|
{
|
2014-07-11 00:09:53 +00:00
|
|
|
gl.DrawElements(GL_TRIANGLES, p->flash.quadCount * 6, _GL_INDEX_TYPE, 0);
|
2013-09-01 14:27:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void GroundLayer::onGeometryChange(const Scene::Geometry &geo)
|
|
|
|
{
|
|
|
|
p->updateSceneGeometry(geo);
|
|
|
|
p->updatePosition();
|
|
|
|
}
|
|
|
|
|
2014-07-10 23:07:18 +00:00
|
|
|
ScanRow::ScanRow(TilemapPrivate *p, Viewport *viewport)
|
|
|
|
: ViewportElement(viewport, 0, p->elem.scanrowStamp),
|
|
|
|
index(0),
|
|
|
|
vboOffset(0),
|
|
|
|
vboCount(0),
|
2013-10-13 20:00:38 +00:00
|
|
|
p(p),
|
|
|
|
vboBatchCount(0)
|
2014-07-10 23:07:18 +00:00
|
|
|
{}
|
|
|
|
|
|
|
|
void ScanRow::setIndex(int value)
|
2013-09-01 14:27:21 +00:00
|
|
|
{
|
2014-07-10 23:07:18 +00:00
|
|
|
index = value;
|
|
|
|
|
|
|
|
z = calculateZ(p, index);
|
|
|
|
scene->reinsert(*this);
|
|
|
|
|
2014-07-11 00:09:53 +00:00
|
|
|
vboOffset = p->scanrowBases[index] * sizeof(index_t) * 6;
|
2013-09-01 14:27:21 +00:00
|
|
|
vboCount = p->scanrowSize(index) * 6;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ScanRow::draw()
|
|
|
|
{
|
2013-10-13 20:00:38 +00:00
|
|
|
if (batchedFlag)
|
|
|
|
return;
|
|
|
|
|
Tilemap: Use vertex shader based autotile animation strategy
Previously, we would just stuff the entire tilemap vertex data
four times into the buffers, with only the autotile vertices
offset according to the animation frame. This meant we could
prepare the buffers once, and then just bind a different offset
for each animation frame without any shader changes, but it also
lead to a huge amount of data being duplicated (and blowing up
the buffer sizes).
The new method only requires one buffer, and instead animates by
recognizing vertices belonging to autotiles in a custom vertex
shader, which offsets them on the fly according to the animation
index.
With giant tilemaps, this method would turn out to be a little
less efficient, but considering the Tilemap is planned to be
rewritten to only hold the range of tiles visible on the screen
in its buffers, the on the fly offsetting will become neglient,
while at the same time the amount of data we have to send to the
GPU everytime the tilemap is updated is greatly reduced; so a
net win in the end.
2014-07-06 17:44:19 +00:00
|
|
|
ShaderBase *shader;
|
2013-09-23 05:15:01 +00:00
|
|
|
|
Tilemap: Use vertex shader based autotile animation strategy
Previously, we would just stuff the entire tilemap vertex data
four times into the buffers, with only the autotile vertices
offset according to the animation frame. This meant we could
prepare the buffers once, and then just bind a different offset
for each animation frame without any shader changes, but it also
lead to a huge amount of data being duplicated (and blowing up
the buffer sizes).
The new method only requires one buffer, and instead animates by
recognizing vertices belonging to autotiles in a custom vertex
shader, which offsets them on the fly according to the animation
index.
With giant tilemaps, this method would turn out to be a little
less efficient, but considering the Tilemap is planned to be
rewritten to only hold the range of tiles visible on the screen
in its buffers, the on the fly offsetting will become neglient,
while at the same time the amount of data we have to send to the
GPU everytime the tilemap is updated is greatly reduced; so a
net win in the end.
2014-07-06 17:44:19 +00:00
|
|
|
p->bindShader(shader);
|
|
|
|
p->bindAtlas(*shader);
|
2013-09-01 14:27:21 +00:00
|
|
|
|
2014-07-13 12:03:18 +00:00
|
|
|
GLMeta::vaoBind(p->tiles.vao);
|
2013-09-01 14:27:21 +00:00
|
|
|
|
2014-07-10 23:07:18 +00:00
|
|
|
shader->setTranslation(p->dispPos);
|
|
|
|
drawInt();
|
2013-09-01 14:27:21 +00:00
|
|
|
|
2014-07-13 12:03:18 +00:00
|
|
|
GLMeta::vaoUnbind(p->tiles.vao);
|
2013-09-01 14:27:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void ScanRow::drawInt()
|
|
|
|
{
|
2014-07-11 00:09:53 +00:00
|
|
|
gl.DrawElements(GL_TRIANGLES, vboBatchCount, _GL_INDEX_TYPE, (GLvoid*) vboOffset);
|
2014-07-10 23:07:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int ScanRow::calculateZ(TilemapPrivate *p, int index)
|
|
|
|
{
|
|
|
|
return 32 * (index + p->viewpPos.y + 1) - p->offset.y;
|
2013-09-01 14:27:21 +00:00
|
|
|
}
|
|
|
|
|
2013-09-27 02:42:22 +00:00
|
|
|
void ScanRow::initUpdateZ()
|
2013-09-01 14:27:21 +00:00
|
|
|
{
|
2013-09-27 02:42:22 +00:00
|
|
|
unlink();
|
|
|
|
}
|
|
|
|
|
2013-10-13 10:58:56 +00:00
|
|
|
void ScanRow::finiUpdateZ(ScanRow *prev)
|
2013-09-27 02:42:22 +00:00
|
|
|
{
|
2014-07-10 23:07:18 +00:00
|
|
|
z = calculateZ(p, index);
|
2013-09-27 02:42:22 +00:00
|
|
|
|
2013-10-13 10:58:56 +00:00
|
|
|
if (prev)
|
|
|
|
scene->insertAfter(*this, *prev);
|
|
|
|
else
|
|
|
|
scene->insert(*this);
|
2013-09-01 14:27:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Tilemap::Autotiles::set(int i, Bitmap *bitmap)
|
|
|
|
{
|
Implement a new tileset atlas layout to allow for bigger tilesets
The atlas packing algorithm has been reworked to pack autotiles
and tileset very efficiently into a texture, splitting the tileset
in multiple ways and eliminating the previous duplication of image
data in the atlas across "frames". Animation, which these frames
were designed for, is now done via duplicated buffer frames,
ie. each animation frame has its own VBO and IBO data. This was
not done to save on VRAM (hardly less memory is used), but to
make place for the new atlas layout.
Thanks to this new layout, even with a max texture size of 2048,
one can use tilesets with up to 15000 height. Of course, such
a tileset couldn't be stored in a regular Bitmap to begin with,
which is why I also introduced a hack called "mega surfaces":
software surfaces stored in RAM and wrapped inside a Bitmap,
whose sole purpose is to be passed to a Tilemap as tilesets.
Various other minor changes and fixes are included.
2013-09-23 20:21:58 +00:00
|
|
|
if (i < 0 || i > autotileCount-1)
|
2013-09-01 14:27:21 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
if (p->autotiles[i] == bitmap)
|
|
|
|
return;
|
|
|
|
|
|
|
|
p->autotiles[i] = bitmap;
|
|
|
|
|
|
|
|
p->invalidateAtlasContents();
|
|
|
|
|
|
|
|
p->autotilesCon[i].disconnect();
|
|
|
|
p->autotilesCon[i] = bitmap->modified.connect
|
|
|
|
(sigc::mem_fun(p, &TilemapPrivate::invalidateAtlasContents));
|
|
|
|
|
|
|
|
p->autotilesDispCon[i].disconnect();
|
|
|
|
p->autotilesDispCon[i] = bitmap->wasDisposed.connect
|
|
|
|
(sigc::mem_fun(p, &TilemapPrivate::invalidateAtlasContents));
|
Implement a new tileset atlas layout to allow for bigger tilesets
The atlas packing algorithm has been reworked to pack autotiles
and tileset very efficiently into a texture, splitting the tileset
in multiple ways and eliminating the previous duplication of image
data in the atlas across "frames". Animation, which these frames
were designed for, is now done via duplicated buffer frames,
ie. each animation frame has its own VBO and IBO data. This was
not done to save on VRAM (hardly less memory is used), but to
make place for the new atlas layout.
Thanks to this new layout, even with a max texture size of 2048,
one can use tilesets with up to 15000 height. Of course, such
a tileset couldn't be stored in a regular Bitmap to begin with,
which is why I also introduced a hack called "mega surfaces":
software surfaces stored in RAM and wrapped inside a Bitmap,
whose sole purpose is to be passed to a Tilemap as tilesets.
Various other minor changes and fixes are included.
2013-09-23 20:21:58 +00:00
|
|
|
|
|
|
|
p->updateAutotileInfo();
|
2013-09-01 14:27:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Bitmap *Tilemap::Autotiles::get(int i) const
|
|
|
|
{
|
Implement a new tileset atlas layout to allow for bigger tilesets
The atlas packing algorithm has been reworked to pack autotiles
and tileset very efficiently into a texture, splitting the tileset
in multiple ways and eliminating the previous duplication of image
data in the atlas across "frames". Animation, which these frames
were designed for, is now done via duplicated buffer frames,
ie. each animation frame has its own VBO and IBO data. This was
not done to save on VRAM (hardly less memory is used), but to
make place for the new atlas layout.
Thanks to this new layout, even with a max texture size of 2048,
one can use tilesets with up to 15000 height. Of course, such
a tileset couldn't be stored in a regular Bitmap to begin with,
which is why I also introduced a hack called "mega surfaces":
software surfaces stored in RAM and wrapped inside a Bitmap,
whose sole purpose is to be passed to a Tilemap as tilesets.
Various other minor changes and fixes are included.
2013-09-23 20:21:58 +00:00
|
|
|
if (i < 0 || i > autotileCount-1)
|
2013-09-01 14:27:21 +00:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
return p->autotiles[i];
|
|
|
|
}
|
|
|
|
|
|
|
|
Tilemap::Tilemap(Viewport *viewport)
|
|
|
|
{
|
|
|
|
p = new TilemapPrivate(viewport);
|
|
|
|
p->autotilesProxy.p = p;
|
|
|
|
}
|
|
|
|
|
|
|
|
Tilemap::~Tilemap()
|
|
|
|
{
|
|
|
|
dispose();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Tilemap::update()
|
|
|
|
{
|
Implement a new tileset atlas layout to allow for bigger tilesets
The atlas packing algorithm has been reworked to pack autotiles
and tileset very efficiently into a texture, splitting the tileset
in multiple ways and eliminating the previous duplication of image
data in the atlas across "frames". Animation, which these frames
were designed for, is now done via duplicated buffer frames,
ie. each animation frame has its own VBO and IBO data. This was
not done to save on VRAM (hardly less memory is used), but to
make place for the new atlas layout.
Thanks to this new layout, even with a max texture size of 2048,
one can use tilesets with up to 15000 height. Of course, such
a tileset couldn't be stored in a regular Bitmap to begin with,
which is why I also introduced a hack called "mega surfaces":
software surfaces stored in RAM and wrapped inside a Bitmap,
whose sole purpose is to be passed to a Tilemap as tilesets.
Various other minor changes and fixes are included.
2013-09-23 20:21:58 +00:00
|
|
|
if (!p->tilemapReady)
|
|
|
|
return;
|
|
|
|
|
2013-09-23 06:27:28 +00:00
|
|
|
/* Animate flash */
|
Implement a new tileset atlas layout to allow for bigger tilesets
The atlas packing algorithm has been reworked to pack autotiles
and tileset very efficiently into a texture, splitting the tileset
in multiple ways and eliminating the previous duplication of image
data in the atlas across "frames". Animation, which these frames
were designed for, is now done via duplicated buffer frames,
ie. each animation frame has its own VBO and IBO data. This was
not done to save on VRAM (hardly less memory is used), but to
make place for the new atlas layout.
Thanks to this new layout, even with a max texture size of 2048,
one can use tilesets with up to 15000 height. Of course, such
a tileset couldn't be stored in a regular Bitmap to begin with,
which is why I also introduced a hack called "mega surfaces":
software surfaces stored in RAM and wrapped inside a Bitmap,
whose sole purpose is to be passed to a Tilemap as tilesets.
Various other minor changes and fixes are included.
2013-09-23 20:21:58 +00:00
|
|
|
if (++p->flash.alphaIdx >= flashAlphaN)
|
2013-09-23 06:27:28 +00:00
|
|
|
p->flash.alphaIdx = 0;
|
|
|
|
|
|
|
|
/* Animate autotiles */
|
Implement a new tileset atlas layout to allow for bigger tilesets
The atlas packing algorithm has been reworked to pack autotiles
and tileset very efficiently into a texture, splitting the tileset
in multiple ways and eliminating the previous duplication of image
data in the atlas across "frames". Animation, which these frames
were designed for, is now done via duplicated buffer frames,
ie. each animation frame has its own VBO and IBO data. This was
not done to save on VRAM (hardly less memory is used), but to
make place for the new atlas layout.
Thanks to this new layout, even with a max texture size of 2048,
one can use tilesets with up to 15000 height. Of course, such
a tileset couldn't be stored in a regular Bitmap to begin with,
which is why I also introduced a hack called "mega surfaces":
software surfaces stored in RAM and wrapped inside a Bitmap,
whose sole purpose is to be passed to a Tilemap as tilesets.
Various other minor changes and fixes are included.
2013-09-23 20:21:58 +00:00
|
|
|
if (!p->tiles.animated)
|
2013-09-01 14:27:21 +00:00
|
|
|
return;
|
|
|
|
|
Implement a new tileset atlas layout to allow for bigger tilesets
The atlas packing algorithm has been reworked to pack autotiles
and tileset very efficiently into a texture, splitting the tileset
in multiple ways and eliminating the previous duplication of image
data in the atlas across "frames". Animation, which these frames
were designed for, is now done via duplicated buffer frames,
ie. each animation frame has its own VBO and IBO data. This was
not done to save on VRAM (hardly less memory is used), but to
make place for the new atlas layout.
Thanks to this new layout, even with a max texture size of 2048,
one can use tilesets with up to 15000 height. Of course, such
a tileset couldn't be stored in a regular Bitmap to begin with,
which is why I also introduced a hack called "mega surfaces":
software surfaces stored in RAM and wrapped inside a Bitmap,
whose sole purpose is to be passed to a Tilemap as tilesets.
Various other minor changes and fixes are included.
2013-09-23 20:21:58 +00:00
|
|
|
p->tiles.frameIdx = atAnimation[p->tiles.aniIdx];
|
2013-09-01 14:27:21 +00:00
|
|
|
|
Implement a new tileset atlas layout to allow for bigger tilesets
The atlas packing algorithm has been reworked to pack autotiles
and tileset very efficiently into a texture, splitting the tileset
in multiple ways and eliminating the previous duplication of image
data in the atlas across "frames". Animation, which these frames
were designed for, is now done via duplicated buffer frames,
ie. each animation frame has its own VBO and IBO data. This was
not done to save on VRAM (hardly less memory is used), but to
make place for the new atlas layout.
Thanks to this new layout, even with a max texture size of 2048,
one can use tilesets with up to 15000 height. Of course, such
a tileset couldn't be stored in a regular Bitmap to begin with,
which is why I also introduced a hack called "mega surfaces":
software surfaces stored in RAM and wrapped inside a Bitmap,
whose sole purpose is to be passed to a Tilemap as tilesets.
Various other minor changes and fixes are included.
2013-09-23 20:21:58 +00:00
|
|
|
if (++p->tiles.aniIdx >= atAnimationN)
|
|
|
|
p->tiles.aniIdx = 0;
|
2013-09-01 14:27:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Tilemap::Autotiles &Tilemap::getAutotiles() const
|
|
|
|
{
|
|
|
|
return p->autotilesProxy;
|
|
|
|
}
|
|
|
|
|
|
|
|
#define DISP_CLASS_NAME "tilemap"
|
|
|
|
|
|
|
|
DEF_ATTR_RD_SIMPLE(Tilemap, Viewport, Viewport*, p->viewport)
|
|
|
|
DEF_ATTR_RD_SIMPLE(Tilemap, Tileset, Bitmap*, p->tileset)
|
|
|
|
DEF_ATTR_RD_SIMPLE(Tilemap, MapData, Table*, p->mapData)
|
|
|
|
DEF_ATTR_RD_SIMPLE(Tilemap, FlashData, Table*, p->flashData)
|
|
|
|
DEF_ATTR_RD_SIMPLE(Tilemap, Priorities, Table*, p->priorities)
|
|
|
|
DEF_ATTR_RD_SIMPLE(Tilemap, Visible, bool, p->visible)
|
|
|
|
DEF_ATTR_RD_SIMPLE(Tilemap, OX, int, p->offset.x)
|
|
|
|
DEF_ATTR_RD_SIMPLE(Tilemap, OY, int, p->offset.y)
|
|
|
|
|
2013-10-06 07:55:27 +00:00
|
|
|
#ifdef RGSS2
|
|
|
|
|
2013-09-01 14:27:21 +00:00
|
|
|
void Tilemap::setViewport(Viewport *value)
|
|
|
|
{
|
|
|
|
GUARD_DISPOSED
|
|
|
|
|
|
|
|
if (p->viewport == value)
|
|
|
|
return;
|
|
|
|
|
|
|
|
p->viewport = value;
|
|
|
|
|
|
|
|
if (!p->tilemapReady)
|
|
|
|
return;
|
|
|
|
|
|
|
|
p->elem.ground->setViewport(value);
|
|
|
|
|
2014-07-13 03:34:18 +00:00
|
|
|
for (size_t i = 0; i < scanrowsMax; ++i)
|
2013-09-01 14:27:21 +00:00
|
|
|
p->elem.scanrows[i]->setViewport(value);
|
|
|
|
}
|
|
|
|
|
2013-10-06 07:55:27 +00:00
|
|
|
#endif
|
|
|
|
|
2013-09-01 14:27:21 +00:00
|
|
|
void Tilemap::setTileset(Bitmap *value)
|
|
|
|
{
|
|
|
|
GUARD_DISPOSED
|
|
|
|
|
|
|
|
if (p->tileset == value)
|
|
|
|
return;
|
|
|
|
|
|
|
|
p->tileset = value;
|
|
|
|
|
|
|
|
p->invalidateAtlasSize();
|
|
|
|
p->tilesetCon.disconnect();
|
|
|
|
p->tilesetCon = value->modified.connect
|
|
|
|
(sigc::mem_fun(p, &TilemapPrivate::invalidateAtlasSize));
|
Implement a new tileset atlas layout to allow for bigger tilesets
The atlas packing algorithm has been reworked to pack autotiles
and tileset very efficiently into a texture, splitting the tileset
in multiple ways and eliminating the previous duplication of image
data in the atlas across "frames". Animation, which these frames
were designed for, is now done via duplicated buffer frames,
ie. each animation frame has its own VBO and IBO data. This was
not done to save on VRAM (hardly less memory is used), but to
make place for the new atlas layout.
Thanks to this new layout, even with a max texture size of 2048,
one can use tilesets with up to 15000 height. Of course, such
a tileset couldn't be stored in a regular Bitmap to begin with,
which is why I also introduced a hack called "mega surfaces":
software surfaces stored in RAM and wrapped inside a Bitmap,
whose sole purpose is to be passed to a Tilemap as tilesets.
Various other minor changes and fixes are included.
2013-09-23 20:21:58 +00:00
|
|
|
|
|
|
|
p->updateAtlasInfo();
|
2013-09-01 14:27:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Tilemap::setMapData(Table *value)
|
|
|
|
{
|
|
|
|
GUARD_DISPOSED
|
|
|
|
|
|
|
|
if (p->mapData == value)
|
|
|
|
return;
|
|
|
|
|
|
|
|
p->mapData = value;
|
|
|
|
|
|
|
|
p->invalidateBuffers();
|
|
|
|
p->mapDataCon.disconnect();
|
|
|
|
p->mapDataCon = value->modified.connect
|
|
|
|
(sigc::mem_fun(p, &TilemapPrivate::invalidateBuffers));
|
|
|
|
}
|
|
|
|
|
|
|
|
void Tilemap::setFlashData(Table *value)
|
|
|
|
{
|
|
|
|
GUARD_DISPOSED
|
|
|
|
|
|
|
|
if (p->flashData == value)
|
|
|
|
return;
|
|
|
|
|
|
|
|
p->flashData = value;
|
|
|
|
|
|
|
|
p->invalidateFlash();
|
|
|
|
p->flashDataCon.disconnect();
|
|
|
|
p->flashDataCon = value->modified.connect
|
|
|
|
(sigc::mem_fun(p, &TilemapPrivate::invalidateFlash));
|
|
|
|
}
|
|
|
|
|
|
|
|
void Tilemap::setPriorities(Table *value)
|
|
|
|
{
|
|
|
|
GUARD_DISPOSED
|
|
|
|
|
|
|
|
if (p->priorities == value)
|
|
|
|
return;
|
|
|
|
|
|
|
|
p->priorities = value;
|
|
|
|
|
|
|
|
p->invalidateBuffers();
|
|
|
|
p->prioritiesCon.disconnect();
|
|
|
|
p->prioritiesCon = value->modified.connect
|
|
|
|
(sigc::mem_fun(p, &TilemapPrivate::invalidateBuffers));
|
|
|
|
}
|
|
|
|
|
|
|
|
void Tilemap::setVisible(bool value)
|
|
|
|
{
|
|
|
|
GUARD_DISPOSED
|
|
|
|
|
|
|
|
if (p->visible == value)
|
|
|
|
return;
|
|
|
|
|
|
|
|
p->visible = value;
|
|
|
|
|
|
|
|
if (!p->tilemapReady)
|
|
|
|
return;
|
|
|
|
|
|
|
|
p->elem.ground->setVisible(value);
|
2014-07-10 23:07:18 +00:00
|
|
|
for (size_t i = 0; i < p->elem.activeRows; ++i)
|
2013-09-01 14:27:21 +00:00
|
|
|
p->elem.scanrows[i]->setVisible(value);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Tilemap::setOX(int value)
|
|
|
|
{
|
|
|
|
GUARD_DISPOSED
|
|
|
|
|
|
|
|
if (p->offset.x == value)
|
|
|
|
return;
|
|
|
|
|
|
|
|
p->offset.x = value;
|
|
|
|
p->updatePosition();
|
2014-07-10 23:07:18 +00:00
|
|
|
p->mapViewportDirty = true;
|
2013-09-01 14:27:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Tilemap::setOY(int value)
|
|
|
|
{
|
|
|
|
GUARD_DISPOSED
|
|
|
|
|
|
|
|
if (p->offset.y == value)
|
|
|
|
return;
|
|
|
|
|
|
|
|
p->offset.y = value;
|
|
|
|
p->updatePosition();
|
2013-09-27 02:42:22 +00:00
|
|
|
p->zOrderDirty = true;
|
2014-07-10 23:07:18 +00:00
|
|
|
p->mapViewportDirty = true;
|
2013-09-01 14:27:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Tilemap::releaseResources()
|
|
|
|
{
|
|
|
|
delete p;
|
|
|
|
}
|