aboutsummaryrefslogtreecommitdiff
path: root/Minecraft.Client/LevelRenderer.h
blob: 37e0b813d83af652196b7a2b606924b4a941252b (plain)
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
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
#pragma once
#include "..\Minecraft.World\LevelListener.h"
#include "..\Minecraft.World\Definitions.h"
#include "OffsettedRenderList.h"
#include "..\Minecraft.World\JavaIntHash.h"
#include "..\Minecraft.World\Level.h"
#include "ResourceLocation.h"
#include <xmcore.h>
#ifdef __PS3__
#include "C4JSpursJob.h"
#endif
class MultiPlayerLevel;
class Textures;
class Chunk;
class Minecraft;
class TileRenderer;
class Culler;
class Entity;
class TileEntity;
class Mob;
class Vec3;
class Particle;
class BlockDestructionProgress;
class IconRegister;
class Tesselator;
using namespace std;

// AP - this is a system that works out which chunks actually need to be grouped together via the deferral system when doing chunk::rebuild. Doing this will reduce the number
// of chunks built in a single group and reduce the chance of seeing through the landscape when digging near the edges/corners of a chunk.
// I've added another chunk flag to mark a chunk critical so it swipes a bit from the reference count value (goes to 3 bits to 2). This works on Vita because it doesn't have
// split screen reference counting.
#ifdef __PSVITA__
#define _CRITICAL_CHUNKS
#endif

class LevelRenderer : public LevelListener
{
	friend class Chunk;

private:
	static ResourceLocation MOON_LOCATION;
	static ResourceLocation MOON_PHASES_LOCATION;
	static ResourceLocation SUN_LOCATION;
	static ResourceLocation CLOUDS_LOCATION;
	static ResourceLocation END_SKY_LOCATION;

public:
	static const int CHUNK_XZSIZE = 16;
#ifdef _LARGE_WORLDS
	static const int CHUNK_SIZE = 16;
#else
	static const int CHUNK_SIZE = 16;
#endif
	static const int CHUNK_Y_COUNT = Level::maxBuildHeight / CHUNK_SIZE;
#if defined _WINDOWS64
	static const int MAX_COMMANDBUFFER_ALLOCATIONS = 2047 * 1024 * 1024;	// Changed to 2047. 4J had set to 512.
#elif defined _XBOX_ONE
	static const int MAX_COMMANDBUFFER_ALLOCATIONS = 512 * 1024 * 1024;		// 4J - added
#elif defined __ORBIS__
	static const int MAX_COMMANDBUFFER_ALLOCATIONS = 448 * 1024 * 1024;		// 4J - added - hard limit is 512 so giving a lot of headroom here for fragmentation (have seen 16MB lost to fragmentation in multiplayer crash dump before)
#elif defined __PS3__
	static const int MAX_COMMANDBUFFER_ALLOCATIONS = 110 * 1024 * 1024;		// 4J - added
#else
	static const int MAX_COMMANDBUFFER_ALLOCATIONS = 55 * 1024 * 1024;		// 4J - added
#endif
public:
	LevelRenderer(Minecraft *mc, Textures *textures);
private:
	void renderStars();
	void createCloudMesh();	// 4J added
public:
	void setLevel(int playerIndex, MultiPlayerLevel *level);
	void allChanged();
	void allChanged(int playerIndex);

	// 4J-PB added
	void AddDLCSkinsToMemTextures();
public:
	void renderEntities(Vec3 *cam, Culler *culler, float a);
	wstring gatherStats1();
	wstring gatherStats2();
private:
	void resortChunks(int xc, int yc, int zc);
public:
	int render(shared_ptr<LivingEntity> player, int layer, double alpha, bool updateChunks);
private:
	int renderChunks(int from, int to, int layer, double alpha);
public:
	int activePlayers();	// 4J - added
public:
	void renderSameAsLast(int layer, double alpha);
	void tick();
	void renderSky(float alpha);
	void renderHaloRing(float alpha);
	void renderClouds(float alpha);
	bool isInCloud(double x, double y, double z, float alpha);
	void renderAdvancedClouds(float alpha);
	bool updateDirtyChunks();

public:
	void renderHit(shared_ptr<Player> player, HitResult *h, int mode, shared_ptr<ItemInstance> inventoryItem, float a);
	void renderDestroyAnimation(Tesselator *t, shared_ptr<Player> player, float a);
	void renderHitOutline(shared_ptr<Player> player, HitResult *h, int mode, float a);
	void render(AABB *b);
	void setDirty(int x0, int y0, int z0, int x1, int y1, int z1, Level *level);		// 4J - added level param
	void tileChanged(int x, int y, int z);
	void tileLightChanged(int x, int y, int z);
	void setTilesDirty(int x0, int y0, int z0, int x1, int y1, int z1, Level *level);	// 4J - added level param

#ifdef __PS3__
	void cull_SPU(int playerIndex, Culler *culler, float a);
	void waitForCull_SPU();
	C4JSpursJobQueue::Port* m_jobPort_CullSPU;
	C4JSpursJobQueue::Port* m_jobPort_FindNearestChunk;
	bool	m_bSPUCullStarted[4];
#endif // __PS3__
	void cull(Culler *culler, float a);
	void playStreamingMusic(const wstring& name, int x, int y, int z);
	void playSound(int iSound, double x, double y, double z, float volume, float pitch, float fSoundClipDist=16.0f);
	void playSound(shared_ptr<Entity> entity,int iSound, double x, double y, double z, float volume, float pitch, float fSoundClipDist=16.0f);
	void playSoundExceptPlayer(shared_ptr<Player> player, int iSound, double x, double y, double z, float volume, float pitch, float fSoundClipDist=16.0f);
	void addParticle(ePARTICLE_TYPE eParticleType, double x, double y, double z, double xa, double ya, double za); // 4J added
	shared_ptr<Particle> addParticleInternal(ePARTICLE_TYPE eParticleType, double x, double y, double z, double xa, double ya, double za); // 4J added
	void entityAdded(shared_ptr<Entity> entity);
	void entityRemoved(shared_ptr<Entity> entity);
	void playerRemoved(shared_ptr<Entity> entity) {}		// 4J added - for when a player is removed from the level's player array, not just the entity storage
	void skyColorChanged();
	void clear();
	void globalLevelEvent(int type, int sourceX, int sourceY, int sourceZ, int data);
	void levelEvent(shared_ptr<Player> source, int type, int x, int y, int z, int data);
	void destroyTileProgress(int id, int x, int y, int z, int progress);
	void registerTextures(IconRegister *iconRegister);

	typedef unordered_map<int, vector<shared_ptr<TileEntity> >, IntKeyHash, IntKeyEq> rteMap;
private:

	// debug
	int m_freezeticks; // used to freeze the clouds

	// 4J - this block of declarations was scattered round the code but have gathered everything into one place
	rteMap renderableTileEntities;			// 4J - changed - was vector<shared_ptr<TileEntity>, now hashed by chunk so we can find them
	CRITICAL_SECTION					m_csRenderableTileEntities;
	MultiPlayerLevel *level[4];					// 4J - now one per player
	Textures *textures;
	//    vector<Chunk *> *sortedChunks[4];	// 4J - removed - not sorting our chunks anymore
	ClipChunkArray chunks[4];			// 4J - now one per player
	int lastPlayerCount[4];				// 4J - added
	int xChunks, yChunks, zChunks;
	int chunkLists;
	Minecraft *mc;
	TileRenderer *tileRenderer[4];		// 4J - now one per player
	int ticks;
	int starList, skyList, darkList, haloRingList;
	int cloudList;	// 4J added
	int xMinChunk, yMinChunk, zMinChunk;
	int xMaxChunk, yMaxChunk, zMaxChunk;
	int lastViewDistance;
	int noEntityRenderFrames;
	int totalEntities;
	int renderedEntities;
	int culledEntities;
	int chunkFixOffs;
	vector<Chunk *> _renderChunks;
	int frame;
	int repeatList;
	double xOld[4];						// 4J - now one per player
	double yOld[4];						// 4J - now one per player
	double zOld[4];						// 4J - now one per player

	int totalChunks, offscreenChunks, occludedChunks, renderedChunks, emptyChunks;
	static const int RENDERLISTS_LENGTH = 4;		// 4J - added
	OffsettedRenderList renderLists[RENDERLISTS_LENGTH];

	unordered_map<int, BlockDestructionProgress *> destroyingBlocks;
	Icon **breakingTextures;

public:
	void				fullyFlagRenderableTileEntitiesToBeRemoved();		// 4J added

	CRITICAL_SECTION	m_csDirtyChunks;
	bool				m_nearDirtyChunk;


	// 4J - Destroyed Tile Management - these things added so we can track tiles which have been recently destroyed, and
	// provide temporary collision for them until the render data has been updated to reflect this change
	class DestroyedTileManager
	{
	private:
		class RecentTile
		{
		public:
			int			x;
			int			y;
			int			z;
			Level		*level;
			AABBList	boxes;
			int			timeout_ticks;
			bool		rebuilt;
			RecentTile(int x, int y, int z, Level *level);
			~RecentTile();
		};
		CRITICAL_SECTION			m_csDestroyedTiles;
		vector<RecentTile *>		m_destroyedTiles;
	public:
		void destroyingTileAt( Level *level, int x, int y, int z );									// For game to let this manager know that a tile is about to be destroyed (must be called before it actually is)
		void updatedChunkAt( Level * level, int x, int y, int z, int veryNearCount );				// For chunk rebuilding to inform the manager that a chunk (a 16x16x16 tile render chunk) has been updated
		void addAABBs( Level *level, AABB *box, AABBList *boxes );									// For game to get any AABBs that the user should be colliding with as render data has not yet been updated
		void tick();
		DestroyedTileManager();
		~DestroyedTileManager();
	};
	DestroyedTileManager *destroyedTileManager;

	float destroyProgress;

	// 4J - added for new render list handling
	// This defines the maximum size of renderable level, must be big enough to cope with actual size of level + view distance at each side
	// so that we can render the "infinite" sea at the edges
	static const int	MAX_LEVEL_RENDER_SIZE[3];
	static const int    DIMENSION_OFFSETS[3];
	// This is the TOTAL area of columns of chunks to be allocated for render round the players. So for one player, it would be a region of
	// sqrt(PLAYER_RENDER_AREA) x sqrt(PLAYER_RENDER_AREA)
#ifdef _LARGE_WORLDS
	static const int	PLAYER_VIEW_DISTANCE = 18; // Straight line distance from centre to extent of visible world
	static const int	PLAYER_RENDER_AREA = (PLAYER_VIEW_DISTANCE * PLAYER_VIEW_DISTANCE * 4);
#else
	static const int	PLAYER_RENDER_AREA = 400;
#endif

	static int			getDimensionIndexFromId(int id);
	static int			getGlobalIndexForChunk(int x, int y, int z, Level *level);
	static int			getGlobalIndexForChunk(int x, int y, int z, int dimensionId);
	static bool			isGlobalIndexInSameDimension( int idx, Level *level);
	static int			getGlobalChunkCount();
	static int			getGlobalChunkCountForOverworld();

	// Get/set/clear individual flags
	bool				getGlobalChunkFlag(int x, int y, int z, Level *level, unsigned char flag, unsigned char shift = 0);
	void				setGlobalChunkFlag(int x, int y, int z, Level *level, unsigned char flag, unsigned char shift = 0);
	void				setGlobalChunkFlag(int index, unsigned char flag, unsigned char shift = 0);
	void				clearGlobalChunkFlag(int x, int y, int z, Level *level, unsigned char flag, unsigned char shift = 0);

	// Get/set whole byte of flags
	unsigned char		getGlobalChunkFlags(int x, int y, int z, Level *level);
	void				setGlobalChunkFlags(int x, int y, int z, Level *level, unsigned char flags);

	// Reference counting
	unsigned char		incGlobalChunkRefCount(int x, int y, int z, Level *level);
	unsigned char		decGlobalChunkRefCount(int x, int y, int z, Level *level);

	// Actual storage for flags
	unsigned char		*globalChunkFlags;

	// The flag definitions
	static const int    CHUNK_FLAG_COMPILED		= 0x01;
	static const int    CHUNK_FLAG_DIRTY		= 0x02;
	static const int    CHUNK_FLAG_EMPTY0		= 0x04;
	static const int    CHUNK_FLAG_EMPTY1		= 0x08;
	static const int	CHUNK_FLAG_EMPTYBOTH	= 0x0c;
	static const int    CHUNK_FLAG_NOTSKYLIT	= 0x10;
#ifdef _CRITICAL_CHUNKS
	static const int    CHUNK_FLAG_CRITICAL		= 0x20;
	static const int    CHUNK_FLAG_CUT_OUT		= 0x40;
	static const int	CHUNK_FLAG_REF_MASK		= 0x01;
	static const int	CHUNK_FLAG_REF_SHIFT	= 7;
#else
	static const int	CHUNK_FLAG_REF_MASK		= 0x07;
	static const int	CHUNK_FLAG_REF_SHIFT	= 5;
#endif

	XLockFreeStack<int> dirtyChunksLockFreeStack;

	bool				dirtyChunkPresent;
	int64_t				lastDirtyChunkFound;
	static const int	FORCE_DIRTY_CHUNK_CHECK_PERIOD_MS = 125; // decreased from 250 to 125 - updated by detectiveren

#ifdef _LARGE_WORLDS
	static const int MAX_CONCURRENT_CHUNK_REBUILDS = 8; // increased from 4 to 8 - updated by detectiveren
	static const int MAX_CHUNK_REBUILD_THREADS = MAX_CONCURRENT_CHUNK_REBUILDS - 1;
	static Chunk permaChunk[MAX_CONCURRENT_CHUNK_REBUILDS];
	static C4JThread *rebuildThreads[MAX_CHUNK_REBUILD_THREADS];
	static C4JThread::EventArray *s_rebuildCompleteEvents;
	static C4JThread::Event *s_activationEventA[MAX_CHUNK_REBUILD_THREADS];
	static void staticCtor();
	static int rebuildChunkThreadProc(LPVOID lpParam);

	CRITICAL_SECTION m_csChunkFlags;
#endif
	void nonStackDirtyChunksAdded();

	int checkAllPresentChunks(bool *faultFound);		// 4J - added for testing
};