Exemplo n.º 1
0
void DrawLandscapeTopDown(StageOneShader *shader, int width, int height, bool forceload, DL_Type dlType) {
	if (!Model::gPlayer.KnownPosition())
		return;
	ChunkCoord player_cc;
	Model::gPlayer.GetChunkCoord(&player_cc);

	int verticallimit = (height+CHUNK_SIZE-1)/CHUNK_SIZE/2;
	int horisontallimit = (width+CHUNK_SIZE-1)/CHUNK_SIZE/2;

	// Draw all visible chunks. Chunks that are not loaded will trigger a reload from the server. The top chunks
	// should be loaded first, as they affect the lighting on the chunks below.
	for (int dz = verticallimit; dz >= -verticallimit; dz--) for (int dx = -horisontallimit; dx <= horisontallimit; dx++) for (int dy = -horisontallimit; dy <= horisontallimit; dy++) {
				glm::mat4 modelMatrix = glm::translate(glm::mat4(1.0f), glm::vec3(dx*CHUNK_SIZE, dz*CHUNK_SIZE, -dy*CHUNK_SIZE));

				ChunkCoord cc;
				cc.x = player_cc.x + dx;
				cc.y = player_cc.y + dy;
				cc.z = player_cc.z + dz;
				Chunk *cp = ChunkFind(&cc, forceload);
				if (cp == 0)
					continue;

				shader->Model(modelMatrix);

				// Draw the chunk
				if (!cp->IsDirty() && cp->fChunkObject && cp->fChunkObject->Empty()) {
					// This chunk exists, is updated, but contains nothing.
					continue;
				}
				cp->Draw(shader, 0, dlType);
				cp->DrawObjects(shader, dx, dy, dz, true);
			}
}
Exemplo n.º 2
0
void DrawLandscapeForShadows(StageOneShader *shader) {
	if (!Model::gPlayer.KnownPosition())
		return;
	ChunkCoord player_cc;
	Model::gPlayer.GetChunkCoord(&player_cc);

	// Draw all visible chunks. Chunks that are not loaded will trigger a reload from the server. The top chunks
	// should be loaded first, as they affect the lighting on the chunks below.
	for (auto it=sShadowChunks.begin() ; it != sShadowChunks.end(); it++ ) {
		Chunk *cp = ChunkFind(&(*it), true);

		if (!cp->IsDirty() && cp->fChunkObject && cp->fChunkObject->Empty()) {
			// This chunk exists, is updated, but contains nothing.
			continue;
		}

		int dx = cp->cc.x - player_cc.x;
		int dy = cp->cc.y - player_cc.y;
		int dz = cp->cc.z - player_cc.z;
		glm::mat4 modelMatrix = glm::translate(glm::mat4(1.0f), glm::vec3(dx*CHUNK_SIZE, dz*CHUNK_SIZE, -dy*CHUNK_SIZE));

		shader->Model(modelMatrix);
		cp->Draw(shader, 0, DL_NoTransparent);
		cp->DrawObjects(shader, dx, dy, dz, true);
	}
}
Exemplo n.º 3
0
// TODO: This function should be split into a separate function for picking mode.
void DrawLandscape(StageOneShader *shader, DL_Type dlType) {
	if (!Model::gPlayer.KnownPosition())
		return;
	if (dlType == DL_NoTransparent) {
		// The lits of chunks used for shadowing is computed below, when in non-transparent mode.
		// Start the list empty.
		sShadowChunks.clear();
	}

	FindAllNearChunks(sChunkDistances);
	ChunkCoord player_cc;
	Model::gPlayer.GetChunkCoord(&player_cc);

	// Draw all visible chunks. Chunks that are not loaded will trigger a reload from the server. The top chunks
	// should be loaded first, as they affect the lighting on the chunks below.
	int chunkHor = (int)(maxRenderDistance / CHUNK_SIZE + 1);

	// At 80m viewing distance, there are 895 chunks. Using various filters, the actual chunks that can be seen are
	// much fewer. Save the filtered list, to speed up the drawing.
	int listOfVisibleChunks[sMaxVolume];
	int src, dst;
	// Create list of visible chunks. This check is faster than using queries, so it is a good filter to
	// start with.
	for (src=0, dst=0; sChunkDistances[src].distance < chunkHor; src++) {
		if (src > sMaxVolume)
			break; // Just a safety precaution, should never happen
		Chunk *cp = sListOfNearChunks[src];
		if (cp) {
			if (cp->fScheduledForLoading)
				continue; // Chunk doesn't exist yet
			// Do not ignore the chunk just because it doesn't have any data yet, as the data update is triggered
			// by the drawing function.
			if (!cp->IsDirty() && cp->fChunkObject && cp->fChunkObject->Empty()) {
				// This chunk exists, is updated, but contains nothing.
				continue;
			}
		}
		int dx = sChunkDistances[src].dx;
		int dy = sChunkDistances[src].dy;
		int dz = sChunkDistances[src].dz;
		glm::mat4 modelMatrix = glm::translate(glm::mat4(1.0f), glm::vec3(dx*CHUNK_SIZE, dz*CHUNK_SIZE, -dy*CHUNK_SIZE));
		if (Outside(dx, dy , dz, modelMatrix)) {
			continue; // Go to next chunk
		}
		listOfVisibleChunks[dst++] = src;
	}
	int visibleChunklistLength = dst;
	// printf("DrawLandscape: listOfVisibleChunks %d\n", visibleChunklistLength);
	bool insideAnyTeleport = false;

	// We need to know which TP is the nearest.
	float distanceToNearTP2 = 1000.0f*1000.0f; // Distance^2 to the nearest TP, initialized to something big.
	glm::vec3 TPPosition;
	for (int i=0; i<visibleChunklistLength; i++) {
		if (i%NUMQUERIES == 0 && dlType == DL_NoTransparent) {
			// Request NUMQUERIES queries, every NUMQUERIES chunk.
			// The chunks that are tested is not the same ones that will be drawn,
			// to allow the reading of the query result to be with a delay.
			// The first NUMQUERIES chunks are not tested. The occlusion test using queries is most effective
			// for long viewing distances, where there is a high chance of chunks not being visible.
			// TODO: The test could also be used for transparent objects, if it wasn't that QuerySetup() enables depth update again.
			int from = i+NUMQUERIES;
			int to = i+NUMQUERIES*2;
			if (to > visibleChunklistLength)
				to = visibleChunklistLength;
			if (to > from)
				QuerySetup(shader, from, to, listOfVisibleChunks); // Initiate the query for a group of chunks
		}
		int ind = listOfVisibleChunks[i];
		if (dlType == DL_OnlyTransparent)
			ind = listOfVisibleChunks[visibleChunklistLength-i-1]; // Read chunks in reverse order for transparent objects
		if (i >= NUMQUERIES && dlType == DL_NoTransparent) { // There is no query initiated for the first NUMQUERIES chunks.
			GLuint numSamples = 1;
			glGetQueryObjectuiv(sQueryId[i%(NUMQUERIES*2)], GL_QUERY_RESULT, &numSamples);
			if (numSamples == 0)
				continue; // No pixels changed by this chunk, skip it!
		}
		int dx = sChunkDistances[ind].dx;
		int dy = sChunkDistances[ind].dy;
		int dz = sChunkDistances[ind].dz;
		glm::mat4 modelMatrix = glm::translate(glm::mat4(1.0f), glm::vec3(dx*CHUNK_SIZE, dz*CHUNK_SIZE, -dy*CHUNK_SIZE));

		// Don't allow picking outside of near chunks.
		if (dlType == DL_Picking && (dx < -1 || dx > 1 || dy < -1 || dy > 1 || dz < -1 || dz > 1))
			break;

		ChunkCoord cc;
		cc.x = player_cc.x + dx;
		cc.y = player_cc.y + dy;
		cc.z = player_cc.z + dz;
		// If we have come this far, a null pointer is no longer accepted. The chunk is needed. Either we get
		// the real chunk, or an empty one.
		Chunk *cp = ChunkFind(&cc, true);

		if (dlType == DL_Picking) {
			// Picking mode. Throw away the previous triangles, and replace it with special triangles used
			// for the picking mode. These contain colour information to allow identification of cubes.
			cp->fChunkBlocks->TestJellyBlockTimeout(true);
			cp->PushTriangles(ChunkObject::Make(cp, true, dx, dy, dz)); // Stash away the old triangles for quick restore
			gChunkShaderPicking.Model(modelMatrix);
		} else {
			cp->fChunkBlocks->TestJellyBlockTimeout(false);
			shader->Model(modelMatrix);
		}

		if (dlType == DL_NoTransparent)
			AddChunkToShadowList(cp);

		// Draw the chunk
		cp->Draw(shader, &gChunkShaderPicking, dlType);

		if (dlType == DL_Picking) {
			// Picking mode. Restore the normal triangles again.
			cp->PopTriangles();
		}

		if (dlType == DL_NoTransparent) {
			cp->DrawObjects(shader, dx, dy, dz, false);
		}

		if (dlType == DL_OnlyTransparent) {
			unsigned char tx, ty, tz;
			if (gMode.CommunicationAllowed() && Model::gSuperChunkManager.GetTeleport(&tx, &ty, &tz, &cp->cc)) {
				double diffX = double(Model::gPlayer.x)/BLOCK_COORD_RES - cc.x*CHUNK_SIZE - tx - 0.5;
				double diffY = double(Model::gPlayer.y)/BLOCK_COORD_RES - cc.y*CHUNK_SIZE - ty - 0.5;
				double diffZ = double(Model::gPlayer.z)/BLOCK_COORD_RES - cc.z*CHUNK_SIZE - tz - PLAYER_HEIGHT*2;
				double d2 = diffX*diffX + diffY*diffY + diffZ*diffZ;
				if (diffX < 1.5 && diffX > -1.5 && diffY < 1.5 && diffY > -1.5 && diffZ < 3.0 && diffZ > 0.0)
					insideAnyTeleport = true;
				// printf("%.2f, %.2f, %.2f\n", diffX, diffY, diffZ);
				if (gMode.Get() == GameMode::GAME) {
					// When in teleport mode, the teleports are drawn elsewhere.
					float x = (float)tx + dx*CHUNK_SIZE + 0.5f;
					float y = (float)tz + dz*CHUNK_SIZE + 0.5f;
					float z = -(float)ty - dy*CHUNK_SIZE - 0.5f;
					gDrawObjectList.emplace_back(glm::vec3(x, y+2, z), BT_Teleport);
					// gMsgWindow.Add("chunk::DrawObjects Teleport at %f,%f,%f\n", x, y, z);
					glm::mat4 modelMatrix = glm::translate(glm::mat4(1.0f), glm::vec3(x, y, z));
					glBindTexture(GL_TEXTURE_2D, GameTexture::Teleport);
					modelMatrix = glm::scale(modelMatrix, glm::vec3(4.0f, 4.0f, 4.0f));
					modelMatrix = glm::rotate(modelMatrix, 45.0f, glm::vec3(0,1,0));
					shader->Model(modelMatrix);
					gLantern.Draw();
				}
				if (d2 < distanceToNearTP2) {
					TPPosition.x = diffX;
					TPPosition.y = diffY;
					TPPosition.z = diffZ;
					distanceToNearTP2 = d2;
				}
			}
		}
	}

	if (dlType == DL_OnlyTransparent) {
		static bool wasNearTP = false;
		if (distanceToNearTP2 < 100) {
			// Update sound effect only if inside a limited distance.
			gSoundControl.SetEnvironmentSound(SoundControl::STeleport, 0, -800*TPPosition.x, -800*TPPosition.y, -800*TPPosition.z);
			wasNearTP = true;
		} else if (wasNearTP) {
			wasNearTP = false;
			gSoundControl.RemoveEnvironmentSound(SoundControl::STeleport, 0);
		}

		// Test for being inside teleports is only done in transparent mode
		switch(gMode.Get()) {
		case GameMode::GAME:
			if (insideAnyTeleport) {
				gMode.Set(GameMode::TELEPORT);
			}
			break;
		case GameMode::TELEPORT:
			if (!insideAnyTeleport && !gAdminTP) {
				gMode.Set(GameMode::GAME);
			}
			break;
		case GameMode::CONSTRUCT:
			// Draw the semi transparent boundaries between chunks.
			DrawChunkBorders(shader);
			break;
		case GameMode::INIT: case GameMode::ESC: case GameMode::EXIT: case GameMode::LOGIN: case GameMode::LOGIN_FAILED:
		case GameMode::PASSWORD: case GameMode::REQ_PASSWD: case GameMode::WAIT_ACK:
			break; // Ignore
		}
	}
}