-
Notifications
You must be signed in to change notification settings - Fork 43
/
render.h
executable file
·214 lines (161 loc) · 7.66 KB
/
render.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
// Copyright 2010, 2011 Michael J. Nelson
//
// This file is part of pigmap.
//
// pigmap 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 3 of the License, or
// (at your option) any later version.
//
// pigmap 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 pigmap. If not, see <http://www.gnu.org/licenses/>.
#ifndef RENDER_H
#define RENDER_H
#include <string>
#include <stdint.h>
#include "map.h"
#include "tables.h"
#include "chunk.h"
#include "blockimages.h"
#include "rgba.h"
struct RenderStats
{
int64_t reqchunkcount, reqregioncount, reqtilecount; // number of required chunks/regions and base tiles
uint64_t heapusage; // estimated peak heap memory usage (if available)
ChunkCacheStats chunkcache;
RegionCacheStats regioncache;
RenderStats() : reqchunkcount(0), reqregioncount(0), reqtilecount(0), heapusage(0) {}
};
struct SceneGraph;
struct TileCache;
struct ThreadOutputCache;
struct RenderJob : private nocopy
{
bool fullrender; // whether we're doing the entire world, as opposed to an incremental update
bool regionformat; // whether the world is in region format (chunk format assumed if not)
MapParams mp;
std::string inputpath, outputpath;
BlockImages blockimages;
std::auto_ptr<ChunkTable> chunktable;
std::auto_ptr<ChunkCache> chunkcache;
std::auto_ptr<RegionTable> regiontable;
std::auto_ptr<RegionCache> regioncache;
std::auto_ptr<TileTable> tiletable;
std::auto_ptr<TileCache> tilecache;
std::auto_ptr<SceneGraph> scenegraph; // reuse this for each tile to avoid reallocation
RenderStats stats;
// don't actually draw anything or read chunks; just iterate through the data structures
// ...scenegraph, chunkcache, and regioncache are not required if in test mode
bool testmode;
};
// render a base tile into an RGBAImage, and also write it to disk
// ...do nothing and return false if the tile is not required or is out of range
bool renderTile(const TileIdx& ti, RenderJob& rj, RGBAImage& tile);
// recursively render all the required tiles that a zoom tile depends on, and then the tile itself;
// stores the result into the supplied RGBAImage, and also writes it to disk
// do nothing and return false if the tile is not required
bool renderZoomTile(const ZoomTileIdx& zti, RenderJob& rj, RGBAImage& tile);
// for second phase of multithreaded operation: recursively render all the required tiles that a zoom tile
// depends on, but stop recursing at the ThreadOutputCache level rather than the base tile level
bool renderZoomTile(const ZoomTileIdx& zti, RenderJob& rj, RGBAImage& tile, const ThreadOutputCache& tocache);
// as we render tiles recursively, we need to be able to hold 4 intermediate results at each zoom level;
// this holds the space for those images, so we don't reallocate all the time
struct TileCache
{
struct ZoomLevel
{
bool used[4]; // which of the images actually have data
RGBAImage tiles[4]; // actual image data for the four tiles
};
std::vector<ZoomLevel> levels; // indexed by baseZoom - zoom
TileCache(const MapParams& mp) : levels(mp.baseZoom)
{
// reserve memory
for (int i = 0; i < mp.baseZoom; i++)
for (int j = 0; j < 4; j++)
levels[i].tiles[j].create(mp.tileSize(), mp.tileSize());
}
};
// when rendering with multiple threads, the individual threads only go up to a certain zoom level, then
// the main thread does the last few levels on its own; the worker threads store their results in this
struct ThreadOutputCache
{
int zoom; // which zoom level the threads are working at
std::vector<RGBAImage> images; // use getIndex() to get index into this from zoom tile
std::vector<bool> used; // which images actually have data
int getIndex(const ZoomTileIdx& zti) const; // get index into images, or -1 if zoom is wrong
ThreadOutputCache(int z) : zoom(z), images((1 << zoom) * (1 << zoom)), used((1 << zoom) * (1 << zoom), false) {}
};
// the blocks in a tile can be partitioned by their center pixels into pseudocolumns--sets of blocks that cover
// exactly the same pixels (each block covers the block immediately SED of it, and so on)
// also, each block can partially occlude blocks in 6 neighboring pseudocolumns: E, SE, S, W, NW, N (that is,
// the pseudocolumns that contain the block's immediate neighbors to the E, SE, etc.)
// ...so we can build a DAG representing the blocks in the tile: each block has up to 7 pointers, each one going to
// the topmost occluded block in a pseudocolumn
// a block can be drawn when all its descendents have been drawn
struct SceneGraphNode
{
int32_t xstart, ystart; // top-left corner of block bounding box in tile image coords
int bimgoffset; // offset into blockimages
// whether to darken various edges to indicate drop-off
bool darkenEU, darkenSU, darkenND, darkenWD;
bool drawn;
BlockIdx bi;
// first child is same pseudocolumn, then N, E, SE, S, W, NW; values are indices into
// the SceneGraph's nodes vector, or -1 for "null"
int children[7];
SceneGraphNode(int32_t x, int32_t y, const BlockIdx& bidx, int offset)
: xstart(x), ystart(y), bimgoffset(offset), darkenEU(false), darkenSU(false), darkenND(false), darkenWD(false),
drawn(false), bi(bidx) {std::fill(children, children + 7, -1);}
};
struct SceneGraph
{
// all nodes from all pseudocolumns go in here, in sequence (ordered by pseudocolumn, and within
// pseudocolumns by height)
std::vector<SceneGraphNode> nodes;
// offset into nodes vector of each pseudocolumn (-1 for pseudocolumns with no nodes)
std::vector<int> pcols;
void clear() {nodes.clear(); pcols.clear();}
int getTopNode(int pcol) {return pcols[pcol];}
// scratch space for use while traversing the DAG
std::vector<int> nodestack;
SceneGraph() {nodes.reserve(2048);}
};
// iterate over the hexagonal block-center grid pixels whose blocks touch a tile
struct TileBlockIterator
{
bool end; // true when there are no more points
// these guys are valid when end == false:
Pixel current; // the current grid point
int pos; // the position of this point within this tile's sequence of points
int nextN, nextE, nextSE; // the sequence positions of the neighboring points; -1 if the neighbor isn't in the tile
const MapParams& mparams;
TileIdx tile;
// the tile's bounding box, expanded by half a block's bounding box, so that any block centered on a point
// within this box will hit the tile
BBox expandedBBox;
int lastTop, lastBottom; // positions of the most recent column top, bottom we've encountered (or -1)
// constructor initializes to the upper-left grid point
TileBlockIterator(const TileIdx& ti, const MapParams& mp);
// movement goes down the columns, then rightward to the next column
void advance();
};
// iterate through the blocks that project to the same place, from top to bottom
struct PseudocolumnIterator
{
bool end; // true when we've run out of blocks
BlockIdx current; // when end == false, holds current block
const MapParams& mparams;
// constructor initializes to topmost block
PseudocolumnIterator(const Pixel& center, const MapParams& mp);
// move to the next block (which is one step SED), or the end
void advance();
};
void testTileIterator();
void testPColIterator();
#endif // RENDER_H