Episode 5

This commit is contained in:
WSAL Evan 2024-11-01 13:41:23 -04:00
parent 70157a4f7f
commit 41e3abe45e
29 changed files with 1257 additions and 404 deletions

View File

@ -157,11 +157,14 @@
<ClCompile Include="src\Block.cpp" />
<ClCompile Include="src\Camera.cpp" />
<ClCompile Include="src\Chunk.cpp" />
<ClCompile Include="src\ChunkData.cpp" />
<ClCompile Include="src\ChunkPos.cpp" />
<ClCompile Include="src\NoiseSettings.cpp" />
<ClCompile Include="src\Physics.cpp" />
<ClCompile Include="src\Planet.cpp" />
<ClCompile Include="src\Shader.cpp" />
<ClCompile Include="src\SurfaceFeature.cpp" />
<ClCompile Include="src\TupleHash.h" />
<ClCompile Include="src\ChunkPosHash.h" />
<ClCompile Include="src\WorldGen.cpp" />
<ClCompile Include="src\WorldGen.h" />
<ClCompile Include="vendor\glad.c" />
@ -178,7 +181,10 @@
<ClInclude Include="src\Blocks.h" />
<ClInclude Include="src\Camera.h" />
<ClInclude Include="src\Chunk.h" />
<ClInclude Include="src\ChunkData.h" />
<ClInclude Include="src\ChunkPos.h" />
<ClInclude Include="src\NoiseSettings.h" />
<ClInclude Include="src\Physics.h" />
<ClInclude Include="src\Planet.h" />
<ClInclude Include="src\Shader.h" />
<ClInclude Include="src\SurfaceFeature.h" />
@ -198,6 +204,10 @@
<ItemGroup>
<None Include="assets\shaders\billboard_frag.glsl" />
<None Include="assets\shaders\billboard_vert.glsl" />
<None Include="assets\shaders\block_outline_frag.glsl" />
<None Include="assets\shaders\block_outline_vert.glsl" />
<None Include="assets\shaders\crosshair_frag.glsl" />
<None Include="assets\shaders\crosshair_vert.glsl" />
<None Include="assets\shaders\framebuffer_frag.glsl" />
<None Include="assets\shaders\framebuffer_vert.glsl" />
<None Include="assets\shaders\main_frag.glsl" />
@ -207,6 +217,7 @@
</ItemGroup>
<ItemGroup>
<Image Include="assets\sprites\block_map.png" />
<Image Include="assets\sprites\crosshair.png" />
</ItemGroup>
<ItemGroup>
<Text Include="vendor\imgui\LICENSE.txt" />

View File

@ -33,7 +33,7 @@
<ClCompile Include="src\Block.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\TupleHash.h">
<ClCompile Include="src\ChunkPosHash.h">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\WorldGen.h">
@ -72,6 +72,15 @@
<ClCompile Include="src\SurfaceFeature.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\Physics.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\ChunkPos.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\ChunkData.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="src\Shader.h">
@ -134,6 +143,15 @@
<ClInclude Include="src\Vertex.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\Physics.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\ChunkPos.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\ChunkData.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<None Include="assets\shaders\main_vert.glsl" />
@ -144,11 +162,18 @@
<None Include="assets\shaders\billboard_frag.glsl" />
<None Include="assets\shaders\framebuffer_vert.glsl" />
<None Include="assets\shaders\framebuffer_frag.glsl" />
<None Include="assets\shaders\block_outline_vert.glsl" />
<None Include="assets\shaders\block_outline_frag.glsl" />
<None Include="assets\shaders\crosshair_frag.glsl" />
<None Include="assets\shaders\crosshair_vert.glsl" />
</ItemGroup>
<ItemGroup>
<Image Include="assets\sprites\block_map.png">
<Filter>Resource Files</Filter>
</Image>
<Image Include="assets\sprites\crosshair.png">
<Filter>Resource Files</Filter>
</Image>
</ItemGroup>
<ItemGroup>
<Text Include="vendor\imgui\LICENSE.txt" />

View File

@ -0,0 +1,10 @@
#version 330 core
out vec4 FragColor;
uniform float time;
void main()
{
FragColor = vec4(0.0, 0.0, 0.0, 1.0);
}

View File

@ -0,0 +1,12 @@
#version 330 core
layout (location = 0) in vec3 aPos;
uniform vec3 model;
uniform mat4 view;
uniform mat4 projection;
void main()
{
gl_Position = projection * view * vec4(aPos + model, 1.0);
}

View File

@ -0,0 +1,18 @@
#version 330 core
in vec2 TexCoord;
out vec4 FragColor;
uniform sampler2D tex;
void main()
{
vec4 texResult = texture(tex, TexCoord);
if (texResult.a == 0)
discard;
texResult.a = 0.8;
FragColor = texResult;
}

View File

@ -0,0 +1,14 @@
#version 330 core
layout (location = 0) in vec2 inPos;
layout (location = 1) in vec2 inTexCoords;
uniform mat4 projection;
out vec2 TexCoord;
void main()
{
gl_Position = projection * vec4(inPos, 0.0, 1.0);
TexCoord = inTexCoords;
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.7 KiB

After

Width:  |  Height:  |  Size: 9.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 246 B

View File

@ -24,11 +24,13 @@
#include "Camera.h"
#include "Planet.h"
#include "Blocks.h"
#include "Physics.h"
void framebufferSizeCallback(GLFWwindow* window, int width, int height);
void processInput(GLFWwindow* window);
void mouse_callback(GLFWwindow* window, double xpos, double ypos);
void scroll_callback(GLFWwindow* window, double xoffset, double yoffset);
void mouse_button_callback(GLFWwindow* window, int button, int action, int mods);
float deltaTime = 0.0f;
float lastFrame = 0.0f;
@ -42,18 +44,22 @@ bool firstMouse = true;
bool menuMode = false;
bool escapeDown = false;
bool f1Down = false;
// Window settings
float windowX = 1920;
float windowY = 1080;
bool vsync = true;
uint16_t selectedBlock = 1;
bool uiEnabled = true;
Camera camera;
GLuint framebufferTexture;
GLuint depthTexture;
// Window options
#define VSYNC 1 // 0 for off, 1 for on
float rectangleVertices[] =
{
// Coords // TexCoords
@ -66,7 +72,38 @@ float rectangleVertices[] =
-1.0f, 1.0f, 0.0f, 1.0f
};
int main (int argc, char *argv[]) {
float outlineVertices[] =
{
-.001f, -.001f, -.001f, 1.001f, -.001f, -.001f,
1.001f, -.001f, -.001f, 1.001f, 1.001f, -.001f,
1.001f, 1.001f, -.001f, -.001f, 1.001f, -.001f,
-.001f, 1.001f, -.001f, -.001f, -.001f, -.001f,
-.001f, -.001f, -.001f, -.001f, -.001f, 1.001f,
-.001f, -.001f, 1.001f, -.001f, 1.001f, 1.001f,
-.001f, 1.001f, 1.001f, -.001f, 1.001f, -.001f,
1.001f, -.001f, -.001f, 1.001f, -.001f, 1.001f,
1.001f, -.001f, 1.001f, 1.001f, 1.001f, 1.001f,
1.001f, 1.001f, 1.001f, 1.001f, 1.001f, -.001f,
-.001f, -.001f, 1.001f, 1.001f, -.001f, 1.001f,
-.001f, 1.001f, 1.001f, 1.001f, 1.001f, 1.001f,
};
float crosshairVertices[] =
{
windowX / 2 - 13.5, windowY / 2 - 13.5, 0.0f, 0.0f,
windowX / 2 + 13.5, windowY / 2 - 13.5, 1.0f, 0.0f,
windowX / 2 + 13.5, windowY / 2 + 13.5, 1.0f, 1.0f,
windowX / 2 - 13.5, windowY / 2 - 13.5, 0.0f, 0.0f,
windowX / 2 - 13.5, windowY / 2 + 13.5, 0.0f, 1.0f,
windowX / 2 + 13.5, windowY / 2 + 13.5, 1.0f, 1.0f,
};
int main(int argc, char *argv[])
{
#ifdef LINUX
char* resolved_path = realpath(argv[0], NULL);
if (resolved_path == NULL) {
@ -74,7 +111,6 @@ int main (int argc, char *argv[]) {
exit(1);
}
size_t resolved_length = strlen(resolved_path);
// remove executable from path
for (size_t i = resolved_length; i > 0; i--) {
if (resolved_path[i] == '/' && resolved_path[i + 1] != 0) {
@ -83,7 +119,6 @@ int main (int argc, char *argv[]) {
break;
}
}
char* assets_path = (char*)malloc(resolved_length + strlen("assets") + 2);
strcpy(assets_path, resolved_path);
strcpy(assets_path + resolved_length + 1, "assets");
@ -92,13 +127,11 @@ int main (int argc, char *argv[]) {
printf("%s: Asset directory not found\n", argv[0]);
exit(1);
}
free(assets_path);
chdir(resolved_path);
free(resolved_path);
#endif
// Initialize GLFW
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
@ -114,7 +147,7 @@ int main (int argc, char *argv[]) {
return -1;
}
glfwMakeContextCurrent(window);
glfwSwapInterval(VSYNC);
glfwSwapInterval(vsync ? 1 : 0);
// Initialize GLAD
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
@ -128,6 +161,7 @@ int main (int argc, char *argv[]) {
glfwSetFramebufferSizeCallback(window, framebufferSizeCallback);
glfwSetCursorPosCallback(window, mouse_callback);
glfwSetScrollCallback(window, scroll_callback);
glfwSetMouseButtonCallback(window, mouse_button_callback);
glClearColor(0.6f, 0.8f, 1.0f, 1.0f);
@ -156,6 +190,10 @@ int main (int argc, char *argv[]) {
Shader framebufferShader("assets/shaders/framebuffer_vert.glsl", "assets/shaders/framebuffer_frag.glsl");
Shader outlineShader("assets/shaders/block_outline_vert.glsl", "assets/shaders/block_outline_frag.glsl");
Shader crosshairShader("assets/shaders/crosshair_vert.glsl", "assets/shaders/crosshair_frag.glsl");
// Create post-processing framebuffer
unsigned int FBO;
glGenFramebuffers(1, &FBO);
@ -198,6 +236,26 @@ int main (int argc, char *argv[]) {
glUniform1i(glGetUniformLocation(framebufferShader.ID, "screenTexture"), 0);
glUniform1i(glGetUniformLocation(framebufferShader.ID, "depthTexture"), 1);
unsigned int outlineVAO, outlineVBO;
glGenVertexArrays(1, &outlineVAO);
glGenBuffers(1, &outlineVBO);
glBindVertexArray(outlineVAO);
glBindBuffer(GL_ARRAY_BUFFER, outlineVBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(outlineVertices), &outlineVertices, GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
unsigned int crosshairVAO, crosshairVBO;
glGenVertexArrays(1, &crosshairVAO);
glGenBuffers(1, &crosshairVBO);
glBindVertexArray(crosshairVAO);
glBindBuffer(GL_ARRAY_BUFFER, crosshairVBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(crosshairVertices), &crosshairVertices, GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)0);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)(2 * sizeof(float)));
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
// Create terrain texture
@ -227,6 +285,30 @@ int main (int argc, char *argv[]) {
stbi_image_free(data);
// Create crosshair texture
unsigned int crosshairTexture;
glGenTextures(1, &crosshairTexture);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, crosshairTexture);
// Set texture parameters
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
// Load Crosshair Texture
unsigned char* data2 = stbi_load("assets/sprites/crosshair.png", &width, &height, &nrChannels, 0);
if (data2)
{
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data2);
glGenerateMipmap(GL_TEXTURE_2D);
}
else
{
std::cout << "Failed to load texture\n";
}
stbi_image_free(data2);
// Create camera
camera = Camera(glm::vec3(0.0f, 25.0f, 0.0f));
@ -234,6 +316,8 @@ int main (int argc, char *argv[]) {
Planet::planet = new Planet(&shader, &waterShader, &billboardShader);
glm::mat4 ortho = glm::ortho(0.0f, (float)windowX, (float)windowY, 0.0f, 0.0f, 10.0f);
// Initialize ImGui
IMGUI_CHECKVERSION();
ImGui::CreateContext();
@ -270,6 +354,8 @@ int main (int argc, char *argv[]) {
waterShader.use();
waterShader.setFloat("time", currentFrame);
outlineShader.use();
outlineShader.setFloat("time", currentFrame);
// Input
processInput(window);
@ -311,24 +397,60 @@ int main (int argc, char *argv[]) {
projectionLoc = glGetUniformLocation(billboardShader.ID, "projection");
glUniformMatrix4fv(projectionLoc, 1, GL_FALSE, glm::value_ptr(projection));
Planet::planet->Update(camera.Position.x, camera.Position.y, camera.Position.z);
outlineShader.use();
viewLoc = glGetUniformLocation(outlineShader.ID, "view");
glUniformMatrix4fv(viewLoc, 1, GL_FALSE, glm::value_ptr(view));
projectionLoc = glGetUniformLocation(outlineShader.ID, "projection");
glUniformMatrix4fv(projectionLoc, 1, GL_FALSE, glm::value_ptr(projection));
Planet::planet->Update(camera.Position);
// -- Render block outline -- //
if (uiEnabled)
{
// Get block position
auto result = Physics::Raycast(camera.Position, camera.Front, 5);
if (result.hit)
{
outlineShader.use();
// Set outline view to position
unsigned int modelLoc = glGetUniformLocation(outlineShader.ID, "model");
glUniform3f(modelLoc, result.blockX, result.blockY, result.blockZ);
// Render
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
//glEnable(GL_COLOR_LOGIC_OP);
glLogicOp(GL_INVERT);
glDisable(GL_CULL_FACE);
glBindVertexArray(outlineVAO);
glLineWidth(2.0);
glDrawArrays(GL_LINES, 0, 24);
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
glEnable(GL_CULL_FACE);
//glDisable(GL_COLOR_LOGIC_OP);
}
}
framebufferShader.use();
// -- Post Processing Stuff -- //
// Check if player is underwater
int blockX = camera.Position.x < 0 ? camera.Position.x - 1 : camera.Position.x;
int blockY = camera.Position.y < 0 ? camera.Position.y - 1 : camera.Position.y;
int blockZ = camera.Position.z < 0 ? camera.Position.z - 1 : camera.Position.z;
int chunkX = blockX < 0 ? floorf(blockX / (float)Planet::chunkSize) : blockX / (int)Planet::chunkSize;
int chunkY = blockY < 0 ? floorf(blockY / (float)Planet::chunkSize) : blockY / (int)Planet::chunkSize;
int chunkZ = blockZ < 0 ? floorf(blockZ / (float)Planet::chunkSize) : blockZ / (int)Planet::chunkSize;
int chunkX = blockX < 0 ? floorf(blockX / (float)CHUNK_SIZE) : blockX / (int)CHUNK_SIZE;
int chunkY = blockY < 0 ? floorf(blockY / (float)CHUNK_SIZE) : blockY / (int)CHUNK_SIZE;
int chunkZ = blockZ < 0 ? floorf(blockZ / (float)CHUNK_SIZE) : blockZ / (int)CHUNK_SIZE;
int localBlockX = blockX - (chunkX * Planet::chunkSize);
int localBlockY = blockY - (chunkY * Planet::chunkSize);
int localBlockZ = blockZ - (chunkZ * Planet::chunkSize);
int localBlockX = blockX - (chunkX * CHUNK_SIZE);
int localBlockY = blockY - (chunkY * CHUNK_SIZE);
int localBlockZ = blockZ - (chunkZ * CHUNK_SIZE);
Chunk* chunk = Planet::planet->GetChunk(chunkX, chunkY, chunkZ);
Chunk* chunk = Planet::planet->GetChunk(ChunkPos(chunkX, chunkY, chunkZ));
if (chunk != nullptr)
{
unsigned int blockType = chunk->GetBlockAtPos(
@ -346,6 +468,7 @@ int main (int argc, char *argv[]) {
}
}
// Post Processing
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glBindVertexArray(rectVAO);
glDisable(GL_DEPTH_TEST);
@ -355,15 +478,50 @@ int main (int argc, char *argv[]) {
glBindTexture(GL_TEXTURE_2D, depthTexture);
glDrawArrays(GL_TRIANGLES, 0, 6);
if (uiEnabled)
{
// -- Render Crosshair -- //
// Render
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, crosshairTexture);
crosshairShader.use();
glDisable(GL_CULL_FACE);
glDisable(GL_DEPTH_TEST);
glEnable(GL_BLEND);
glEnable(GL_COLOR_LOGIC_OP);
unsigned int crosshairProjLoc = glGetUniformLocation(crosshairShader.ID, "projection");
glUniformMatrix4fv(crosshairProjLoc, 1, GL_FALSE, glm::value_ptr(ortho));
glBindVertexArray(crosshairVAO);
glDrawArrays(GL_TRIANGLES, 0, 6);
glEnable(GL_CULL_FACE);
glEnable(GL_DEPTH_TEST);
glDisable(GL_BLEND);
glDisable(GL_COLOR_LOGIC_OP);
// Draw ImGui UI
ImGui::Begin("Test");
ImGui::Text("FPS: %f (Avg: %f, Min: %f, Max: %f)", fps, avgFps, lowestFps, highestFps);
ImGui::Text("FPS: %d (Avg: %d, Min: %d, Max: %d)", (int)fps, (int)avgFps, (int)lowestFps, (int)highestFps);
ImGui::Text("MS: %f", deltaTime * 100.0f);
if (ImGui::Checkbox("VSYNC", &vsync))
glfwSwapInterval(vsync ? 1 : 0);
ImGui::Text("Chunks: %d (%d rendered)", Planet::planet->numChunks, Planet::planet->numChunksRendered);
ImGui::Text("Position: x: %f, y: %f, z: %f", camera.Position.x, camera.Position.y, camera.Position.z);
ImGui::Text("Direction: x: %f, y: %f, z: %f", camera.Front.x, camera.Front.y, camera.Front.z);
ImGui::Text("Selected Block: %s", Blocks::blocks[selectedBlock].blockName);
if (ImGui::SliderInt("Render Distance", &Planet::planet->renderDistance, 0, 30))
Planet::planet->ClearChunkQueue();
if (ImGui::SliderInt("Render Height", &Planet::planet->renderHeight, 0, 10))
Planet::planet->ClearChunkQueue();
ImGui::Checkbox("Use absolute Y axis for camera vertical movement", &camera.absoluteVerticalMovement);
ImGui::End();
ImGui::Render();
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
}
// Check and call events and swap buffers
glfwSwapBuffers(window);
@ -372,6 +530,8 @@ int main (int argc, char *argv[]) {
//std::cout << camera.Position.x << ", " << camera.Position.y << ", " << camera.Position.z << '\n';
}
delete Planet::planet;
ImGui_ImplOpenGL3_Shutdown();
ImGui_ImplGlfw_Shutdown();
ImGui::DestroyContext();
@ -388,7 +548,6 @@ void framebufferSizeCallback(GLFWwindow* window, int width, int height)
// resize framebuffer texture
glBindTexture(GL_TEXTURE_2D, framebufferTexture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, windowX, windowY, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
// resize framebuffer depth texture
glBindTexture(GL_TEXTURE_2D, depthTexture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, windowX, windowY, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL);
@ -396,6 +555,7 @@ void framebufferSizeCallback(GLFWwindow* window, int width, int height)
void processInput(GLFWwindow* window)
{
// Pause
if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
{
if (escapeDown)
@ -410,6 +570,18 @@ void processInput(GLFWwindow* window)
else
escapeDown = false;
// UI Toggle
if (glfwGetKey(window, GLFW_KEY_F1) == GLFW_PRESS)
{
if (f1Down)
return;
f1Down = true;
uiEnabled = !uiEnabled;
}
else
f1Down = false;
if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS)
{
if (glfwGetKey(window, GLFW_KEY_SPACE) == GLFW_PRESS)
@ -429,6 +601,61 @@ void processInput(GLFWwindow* window)
camera.ProcessKeyboard(DOWN, deltaTime);
}
void mouse_button_callback(GLFWwindow* window, int button, int action, int mods)
{
if (button == GLFW_MOUSE_BUTTON_LEFT && action == GLFW_PRESS)
{
auto result = Physics::Raycast(camera.Position, camera.Front, 5);
if (!result.hit)
return;
result.chunk->UpdateBlock(result.localBlockX, result.localBlockY, result.localBlockZ, 0);
}
else if (button == GLFW_MOUSE_BUTTON_MIDDLE && action == GLFW_PRESS)
{
auto result = Physics::Raycast(camera.Position, camera.Front, 5);
if (!result.hit)
return;
selectedBlock = result.chunk->GetBlockAtPos(result.localBlockX, result.localBlockY, result.localBlockZ);
}
else if (button == GLFW_MOUSE_BUTTON_RIGHT && action == GLFW_PRESS)
{
auto result = Physics::Raycast(camera.Position, camera.Front, 5);
if (!result.hit)
return;
float distX = result.hitPos.x - (result.blockX + .5f);
float distY = result.hitPos.y - (result.blockY + .5f);
float distZ = result.hitPos.z - (result.blockZ + .5f);
int blockX = result.blockX;
int blockY = result.blockY;
int blockZ = result.blockZ;
// Choose face to place on
if (abs(distX) > abs(distY) && abs(distX) > abs(distZ))
blockX += (distX > 0 ? 1 : -1);
else if (abs(distY) > abs(distX) && abs(distY) > abs(distZ))
blockY += (distY > 0 ? 1 : -1);
else
blockZ += (distZ > 0 ? 1 : -1);
int chunkX = blockX < 0 ? floorf(blockX / (float)CHUNK_SIZE) : blockX / (int)CHUNK_SIZE;
int chunkY = blockY < 0 ? floorf(blockY / (float)CHUNK_SIZE) : blockY / (int)CHUNK_SIZE;
int chunkZ = blockZ < 0 ? floorf(blockZ / (float)CHUNK_SIZE) : blockZ / (int)CHUNK_SIZE;
int localBlockX = blockX - (chunkX * CHUNK_SIZE);
int localBlockY = blockY - (chunkY * CHUNK_SIZE);
int localBlockZ = blockZ - (chunkZ * CHUNK_SIZE);
Chunk* chunk = Planet::planet->GetChunk(ChunkPos(chunkX, chunkY, chunkZ));
uint16_t blockToReplace = chunk->GetBlockAtPos(localBlockX, localBlockY, localBlockZ);
if (chunk != nullptr && (blockToReplace == 0 || Blocks::blocks[blockToReplace].blockType == Block::LIQUID))
chunk->UpdateBlock(localBlockX, localBlockY, localBlockZ, selectedBlock);
}
}
void mouse_callback(GLFWwindow* window, double xpos, double ypos)
{
if (menuMode)

View File

@ -1,7 +1,7 @@
#include "Block.h"
Block::Block(char minX, char minY, char maxX, char maxY, BLOCK_TYPE blockType)
: blockType(blockType)
Block::Block(char minX, char minY, char maxX, char maxY, BLOCK_TYPE blockType, std::string blockName)
: blockType(blockType), blockName(blockName)
{
topMinX = minX;
topMinY = minY;
@ -21,8 +21,8 @@ Block::Block(char minX, char minY, char maxX, char maxY, BLOCK_TYPE blockType)
Block::Block(char topMinX, char topMinY, char topMaxX, char topMaxY,
char bottomMinX, char bottomMinY, char bottomMaxX, char bottomMaxY,
char sideMinX, char sideMinY, char sideMaxX, char sideMaxY, BLOCK_TYPE blockType)
: blockType(blockType)
char sideMinX, char sideMinY, char sideMaxX, char sideMaxY, BLOCK_TYPE blockType, std::string blockName)
: blockType(blockType), blockName(blockName)
{
this->topMinX = topMinX;
this->topMinY = topMinY;

View File

@ -1,5 +1,7 @@
#pragma once
#include <string>
struct Block
{
public:
@ -16,10 +18,11 @@ public:
char bottomMinX, bottomMinY, bottomMaxX, bottomMaxY;
char sideMinX, sideMinY, sideMaxX, sideMaxY;
BLOCK_TYPE blockType;
std::string blockName;
Block(char minX, char minY, char maxX, char maxY, BLOCK_TYPE blockType);
Block(char minX, char minY, char maxX, char maxY, BLOCK_TYPE blockType, std::string blockName);
Block(char topMinX, char topMinY, char topMaxX, char topMaxY,
char bottomMinX, char bottomMinY, char bottomMaxX, char bottomMaxY,
char sideMinX, char sideMinY, char sideMaxX, char sideMaxY, BLOCK_TYPE blockType);
char sideMinX, char sideMinY, char sideMaxX, char sideMaxY, BLOCK_TYPE blockType, std::string blockName);
};

View File

@ -1,34 +1,36 @@
#pragma once
#include <vector>
#include <array>
#include "Block.h"
namespace Blocks
{
const std::vector<Block> blocks{
Block(0, 0, 0, 0, Block::TRANSPARENT), // Air block
Block(0, 0, 1, 1, Block::SOLID), // Dirt block
Block(0, 0, 0, 0, Block::TRANSPARENT, "Air"), // Air block
Block(0, 0, 1, 1, Block::SOLID, "Dirt"), // Dirt block
Block(1, 1, 2, 2, // Grass block
0, 0, 1, 1,
1, 0, 2, 1, Block::SOLID),
1, 0, 2, 1, Block::SOLID, "Grass Block"),
Block(0, 1, 1, 2, Block::SOLID), // Stone block
Block(0, 1, 1, 2, Block::SOLID, "Stone"), // Stone block
Block(2, 1, 3, 2, // Log
2, 1, 3, 2,
2, 0, 3, 1, Block::SOLID),
2, 0, 3, 1, Block::SOLID, "Log"),
Block(0, 2, 1, 3, Block::LEAVES), // Leaves
Block(1, 2, 2, 3, Block::BILLBOARD), // Grass
Block(3, 0, 4, 1, Block::BILLBOARD), // Tall Grass Bottom
Block(3, 1, 4, 2, Block::BILLBOARD), // Tall Grass Top
Block(0, 3, 1, 4, Block::BILLBOARD), // Poppy
Block(2, 2, 3, 3, Block::BILLBOARD), // White Tulip
Block(3, 2, 4, 3, Block::BILLBOARD), // Pink Tulip
Block(1, 3, 2, 4, Block::BILLBOARD), // Orange Tulip
Block(0, 4, 1, 5, Block::LIQUID) // Water
Block(0, 2, 1, 3, Block::LEAVES, "Leaves"), // Leaves
Block(1, 2, 2, 3, Block::BILLBOARD, "Grass"), // Grass
Block(3, 0, 4, 1, Block::BILLBOARD, "Tall Grass Bot"), // Tall Grass Bottom
Block(3, 1, 4, 2, Block::BILLBOARD, "Tall Grass Top"), // Tall Grass Top
Block(0, 3, 1, 4, Block::BILLBOARD, "Poppy"), // Poppy
Block(2, 2, 3, 3, Block::BILLBOARD, "White Tulip"), // White Tulip
Block(3, 2, 4, 3, Block::BILLBOARD, "Pink Tulip"), // Pink Tulip
Block(1, 3, 2, 4, Block::BILLBOARD, "Orange Tulip"), // Orange Tulip
Block(0, 4, 1, 5, Block::LIQUID, "Water"), // Water
Block(4, 0, 5, 1, Block::SOLID, "Sand"), // Sand
};
enum BLOCKS
@ -46,6 +48,7 @@ namespace Blocks
WHITE_TULIP = 10,
PINK_TULIP = 11,
ORANGE_TULIP = 12,
WATER = 13
WATER = 13,
SAND = 14,
};
}

View File

@ -38,9 +38,9 @@ void Camera::ProcessKeyboard(Camera_Movement direction, float deltaTime)
if (direction == RIGHT)
Position += Right * velocity;
if (direction == UP)
Position.y += 1 * velocity;
Position += (absoluteVerticalMovement ? glm::vec3(0, 1, 0) : Up) * velocity;
if (direction == DOWN)
Position.y -= 1 * velocity;
Position -= (absoluteVerticalMovement ? glm::vec3(0, 1, 0) : Up) * velocity;
if (direction == FORWARD_NO_Y)
{
glm::vec3 moveDir = Front;

View File

@ -36,6 +36,7 @@ public:
float MovementSpeed;
float MouseSensitivity;
float Zoom;
bool absoluteVerticalMovement = true;
Camera(glm::vec3 position = glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3 up = glm::vec3(0.0f, 1.0f, 0.0f), float yaw = YAW, float pitch = PITCH);

View File

@ -10,14 +10,13 @@
#include "Blocks.h"
#include "WorldGen.h"
Chunk::Chunk(unsigned int chunkSize, glm::vec3 chunkPos, Shader* shader, Shader* waterShader)
: chunkSize(chunkSize), chunkPos(chunkPos)
Chunk::Chunk(ChunkPos chunkPos, Shader* shader, Shader* waterShader)
: chunkPos(chunkPos)
{
worldPos = glm::vec3(chunkPos.x * chunkSize, chunkPos.y * chunkSize, chunkPos.z * chunkSize);
worldPos = glm::vec3(chunkPos.x * (float)CHUNK_SIZE, chunkPos.y * (float)CHUNK_SIZE, chunkPos.z * (float)CHUNK_SIZE);
ready = false;
generated = false;
chunkThread = std::thread(&Chunk::GenerateChunk, this);
}
Chunk::~Chunk()
@ -38,47 +37,41 @@ Chunk::~Chunk()
glDeleteVertexArrays(1, &billboardVAO);
}
void Chunk::GenerateChunk()
void Chunk::GenerateChunkMesh()
{
//std::cout << "Started thread: " << std::this_thread::get_id() << '\n';
WorldGen::GenerateChunkData(chunkPos.x, chunkPos.y, chunkPos.z, chunkSize, &chunkData);
std::vector<unsigned int> northData, southData, eastData, westData, upData, downData;
WorldGen::GenerateChunkData(chunkPos.x, chunkPos.y, chunkPos.z - 1, chunkSize, &northData);
WorldGen::GenerateChunkData(chunkPos.x, chunkPos.y, chunkPos.z + 1, chunkSize, &southData);
WorldGen::GenerateChunkData(chunkPos.x + 1, chunkPos.y, chunkPos.z, chunkSize, &eastData);
WorldGen::GenerateChunkData(chunkPos.x - 1, chunkPos.y, chunkPos.z, chunkSize, &westData);
WorldGen::GenerateChunkData(chunkPos.x, chunkPos.y + 1, chunkPos.z, chunkSize, &upData);
WorldGen::GenerateChunkData(chunkPos.x, chunkPos.y - 1, chunkPos.z, chunkSize, &downData);
//std::cout << "Got chunk data in thread: " << std::this_thread::get_id() << '\n';
mainVertices.clear();
mainIndices.clear();
waterVertices.clear();
waterIndices.clear();
billboardVertices.clear();
billboardIndices.clear();
numTrianglesMain = 0;
numTrianglesWater = 0;
numTrianglesBillboard = 0;
unsigned int currentVertex = 0;
unsigned int currentLiquidVertex = 0;
unsigned int currentBillboardVertex = 0;
for (char x = 0; x < chunkSize; x++)
for (char x = 0; x < CHUNK_SIZE; x++)
{
for (char z = 0; z < chunkSize; z++)
for (char z = 0; z < CHUNK_SIZE; z++)
{
for (char y = 0; y < chunkSize; y++)
for (char y = 0; y < CHUNK_SIZE; y++)
{
int index = x * chunkSize * chunkSize + z * chunkSize + y;
if (chunkData[index] == 0)
if (chunkData->GetBlock(x, y, z) == 0)
continue;
const Block* block = &Blocks::blocks[chunkData[index]];
const Block* block = &Blocks::blocks[chunkData->GetBlock(x, y, z)];
int topBlock;
if (y < chunkSize - 1)
if (y < CHUNK_SIZE - 1)
{
int blockIndex = x * chunkSize * chunkSize + z * chunkSize + (y + 1);
topBlock = chunkData[blockIndex];
topBlock = chunkData->GetBlock(x, y + 1, z);
}
else
{
int blockIndex = x * chunkSize * chunkSize + z * chunkSize + 0;
topBlock = upData[blockIndex];
int blockIndex = x * CHUNK_SIZE * CHUNK_SIZE + z * CHUNK_SIZE + 0;
topBlock = upData->GetBlock(x, 0, z);
}
const Block* topBlockType = &Blocks::blocks[topBlock];
@ -119,13 +112,11 @@ void Chunk::GenerateChunk()
int northBlock;
if (z > 0)
{
int northIndex = x * chunkSize * chunkSize + (z - 1) * chunkSize + y;
northBlock = chunkData[northIndex];
northBlock = chunkData->GetBlock(x, y, z - 1);
}
else
{
int northIndex = x * chunkSize * chunkSize + (chunkSize - 1) * chunkSize + y;
northBlock = northData[northIndex];
northBlock = northData->GetBlock(x, y, CHUNK_SIZE - 1);
}
const Block* northBlockType = &Blocks::blocks[northBlock];
@ -157,12 +148,12 @@ void Chunk::GenerateChunk()
mainVertices.push_back(Vertex(x + 1, y + 1, z + 0, block->sideMinX, block->sideMaxY, 0));
mainVertices.push_back(Vertex(x + 0, y + 1, z + 0, block->sideMaxX, block->sideMaxY, 0));
mianIndices.push_back(currentVertex + 0);
mianIndices.push_back(currentVertex + 3);
mianIndices.push_back(currentVertex + 1);
mianIndices.push_back(currentVertex + 0);
mianIndices.push_back(currentVertex + 2);
mianIndices.push_back(currentVertex + 3);
mainIndices.push_back(currentVertex + 0);
mainIndices.push_back(currentVertex + 3);
mainIndices.push_back(currentVertex + 1);
mainIndices.push_back(currentVertex + 0);
mainIndices.push_back(currentVertex + 2);
mainIndices.push_back(currentVertex + 3);
currentVertex += 4;
}
}
@ -171,15 +162,13 @@ void Chunk::GenerateChunk()
// South
{
int southBlock;
if (z < chunkSize - 1)
if (z < CHUNK_SIZE - 1)
{
int southIndex = x * chunkSize * chunkSize + (z + 1) * chunkSize + y;
southBlock = chunkData[southIndex];
southBlock = chunkData->GetBlock(x, y, z + 1);
}
else
{
int southIndex = x * chunkSize * chunkSize + 0 * chunkSize + y;
southBlock = southData[southIndex];
southBlock = southData->GetBlock(x, y, 0);
}
const Block* southBlockType = &Blocks::blocks[southBlock];
@ -211,12 +200,12 @@ void Chunk::GenerateChunk()
mainVertices.push_back(Vertex(x + 0, y + 1, z + 1, block->sideMinX, block->sideMaxY, 1));
mainVertices.push_back(Vertex(x + 1, y + 1, z + 1, block->sideMaxX, block->sideMaxY, 1));
mianIndices.push_back(currentVertex + 0);
mianIndices.push_back(currentVertex + 3);
mianIndices.push_back(currentVertex + 1);
mianIndices.push_back(currentVertex + 0);
mianIndices.push_back(currentVertex + 2);
mianIndices.push_back(currentVertex + 3);
mainIndices.push_back(currentVertex + 0);
mainIndices.push_back(currentVertex + 3);
mainIndices.push_back(currentVertex + 1);
mainIndices.push_back(currentVertex + 0);
mainIndices.push_back(currentVertex + 2);
mainIndices.push_back(currentVertex + 3);
currentVertex += 4;
}
}
@ -227,13 +216,11 @@ void Chunk::GenerateChunk()
int westBlock;
if (x > 0)
{
int blockIndex = (x - 1) * chunkSize * chunkSize + z * chunkSize + y;
westBlock = chunkData[blockIndex];
westBlock = chunkData->GetBlock(x - 1, y, z);
}
else
{
int blockIndex = (chunkSize - 1) * chunkSize * chunkSize + z * chunkSize + y;
westBlock = westData[blockIndex];
westBlock = westData->GetBlock(CHUNK_SIZE - 1, y, z);
}
const Block* westBlockType = &Blocks::blocks[westBlock];
@ -265,12 +252,12 @@ void Chunk::GenerateChunk()
mainVertices.push_back(Vertex(x + 0, y + 1, z + 0, block->sideMinX, block->sideMaxY, 2));
mainVertices.push_back(Vertex(x + 0, y + 1, z + 1, block->sideMaxX, block->sideMaxY, 2));
mianIndices.push_back(currentVertex + 0);
mianIndices.push_back(currentVertex + 3);
mianIndices.push_back(currentVertex + 1);
mianIndices.push_back(currentVertex + 0);
mianIndices.push_back(currentVertex + 2);
mianIndices.push_back(currentVertex + 3);
mainIndices.push_back(currentVertex + 0);
mainIndices.push_back(currentVertex + 3);
mainIndices.push_back(currentVertex + 1);
mainIndices.push_back(currentVertex + 0);
mainIndices.push_back(currentVertex + 2);
mainIndices.push_back(currentVertex + 3);
currentVertex += 4;
}
}
@ -279,15 +266,13 @@ void Chunk::GenerateChunk()
// East
{
int eastBlock;
if (x < chunkSize - 1)
if (x < CHUNK_SIZE - 1)
{
int blockIndex = (x + 1) * chunkSize * chunkSize + z * chunkSize + y;
eastBlock = chunkData[blockIndex];
eastBlock = chunkData->GetBlock(x + 1, y, z);
}
else
{
int blockIndex = 0 * chunkSize * chunkSize + z * chunkSize + y;
eastBlock = eastData[blockIndex];
eastBlock = eastData->GetBlock(0, y, z);
}
const Block* eastBlockType = &Blocks::blocks[eastBlock];
@ -319,12 +304,12 @@ void Chunk::GenerateChunk()
mainVertices.push_back(Vertex(x + 1, y + 1, z + 1, block->sideMinX, block->sideMaxY, 3));
mainVertices.push_back(Vertex(x + 1, y + 1, z + 0, block->sideMaxX, block->sideMaxY, 3));
mianIndices.push_back(currentVertex + 0);
mianIndices.push_back(currentVertex + 3);
mianIndices.push_back(currentVertex + 1);
mianIndices.push_back(currentVertex + 0);
mianIndices.push_back(currentVertex + 2);
mianIndices.push_back(currentVertex + 3);
mainIndices.push_back(currentVertex + 0);
mainIndices.push_back(currentVertex + 3);
mainIndices.push_back(currentVertex + 1);
mainIndices.push_back(currentVertex + 0);
mainIndices.push_back(currentVertex + 2);
mainIndices.push_back(currentVertex + 3);
currentVertex += 4;
}
}
@ -335,13 +320,12 @@ void Chunk::GenerateChunk()
int bottomBlock;
if (y > 0)
{
int blockIndex = x * chunkSize * chunkSize + z * chunkSize + (y - 1);
bottomBlock = chunkData[blockIndex];
bottomBlock = chunkData->GetBlock(x, y - 1, z);
}
else
{
int blockIndex = x * chunkSize * chunkSize + z * chunkSize + (chunkSize - 1);
bottomBlock = downData[blockIndex];
//int blockIndex = x * chunkSize * chunkSize + z * chunkSize + (chunkSize - 1);
bottomBlock = downData->GetBlock(x, CHUNK_SIZE - 1, z);
}
const Block* bottomBlockType = &Blocks::blocks[bottomBlock];
@ -373,12 +357,12 @@ void Chunk::GenerateChunk()
mainVertices.push_back(Vertex(x + 1, y + 0, z + 0, block->bottomMinX, block->bottomMaxY, 4));
mainVertices.push_back(Vertex(x + 0, y + 0, z + 0, block->bottomMaxX, block->bottomMaxY, 4));
mianIndices.push_back(currentVertex + 0);
mianIndices.push_back(currentVertex + 3);
mianIndices.push_back(currentVertex + 1);
mianIndices.push_back(currentVertex + 0);
mianIndices.push_back(currentVertex + 2);
mianIndices.push_back(currentVertex + 3);
mainIndices.push_back(currentVertex + 0);
mainIndices.push_back(currentVertex + 3);
mainIndices.push_back(currentVertex + 1);
mainIndices.push_back(currentVertex + 0);
mainIndices.push_back(currentVertex + 2);
mainIndices.push_back(currentVertex + 3);
currentVertex += 4;
}
}
@ -427,12 +411,12 @@ void Chunk::GenerateChunk()
mainVertices.push_back(Vertex(x + 0, y + 1, z + 0, block->topMinX, block->topMaxY, 5));
mainVertices.push_back(Vertex(x + 1, y + 1, z + 0, block->topMaxX, block->topMaxY, 5));
mianIndices.push_back(currentVertex + 0);
mianIndices.push_back(currentVertex + 3);
mianIndices.push_back(currentVertex + 1);
mianIndices.push_back(currentVertex + 0);
mianIndices.push_back(currentVertex + 2);
mianIndices.push_back(currentVertex + 3);
mainIndices.push_back(currentVertex + 0);
mainIndices.push_back(currentVertex + 3);
mainIndices.push_back(currentVertex + 1);
mainIndices.push_back(currentVertex + 0);
mainIndices.push_back(currentVertex + 2);
mainIndices.push_back(currentVertex + 3);
currentVertex += 4;
}
}
@ -455,7 +439,7 @@ void Chunk::Render(Shader* mainShader, Shader* billboardShader)
if (generated)
{
// Solid
numTrianglesMain = mianIndices.size();
numTrianglesMain = mainIndices.size();
glGenVertexArrays(1, &mainVAO);
glGenBuffers(1, &mainVBO);
@ -467,7 +451,7 @@ void Chunk::Render(Shader* mainShader, Shader* billboardShader)
glBufferData(GL_ARRAY_BUFFER, mainVertices.size() * sizeof(Vertex), mainVertices.data(), GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mainEBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, mianIndices.size() * sizeof(unsigned int), mianIndices.data(), GL_STATIC_DRAW);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, mainIndices.size() * sizeof(unsigned int), mainIndices.data(), GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_BYTE, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, posX));
glEnableVertexAttribArray(0);
@ -572,11 +556,128 @@ void Chunk::RenderWater(Shader* shader)
glDrawElements(GL_TRIANGLES, numTrianglesWater, GL_UNSIGNED_INT, 0);
}
unsigned int Chunk::GetBlockAtPos(int x, int y, int z)
uint16_t Chunk::GetBlockAtPos(int x, int y, int z)
{
if (!ready)
return 0;
int index = x * chunkSize * chunkSize + z * chunkSize + y;
return chunkData[index];
return chunkData->GetBlock(x, y, z);
}
void Chunk::UpdateBlock(int x, int y, int z, uint16_t newBlock)
{
chunkData->SetBlock(x, y, z, newBlock);
GenerateChunkMesh();
// Main
numTrianglesMain = mainIndices.size();
glBindVertexArray(mainVAO);
glBindBuffer(GL_ARRAY_BUFFER, mainVBO);
glBufferData(GL_ARRAY_BUFFER, mainVertices.size() * sizeof(Vertex), mainVertices.data(), GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mainEBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, mainIndices.size() * sizeof(unsigned int), mainIndices.data(), GL_STATIC_DRAW);
// Water
numTrianglesWater = waterIndices.size();
glBindVertexArray(waterVAO);
glBindBuffer(GL_ARRAY_BUFFER, waterVBO);
glBufferData(GL_ARRAY_BUFFER, waterVertices.size() * sizeof(WaterVertex), waterVertices.data(), GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, waterEBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, waterIndices.size() * sizeof(unsigned int), waterIndices.data(), GL_STATIC_DRAW);
// Billboard
numTrianglesBillboard = billboardIndices.size();;
glBindVertexArray(billboardVAO);
glBindBuffer(GL_ARRAY_BUFFER, billboardVBO);
glBufferData(GL_ARRAY_BUFFER, billboardVertices.size() * sizeof(BillboardVertex), billboardVertices.data(), GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, billboardEBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, billboardIndices.size() * sizeof(unsigned int), billboardIndices.data(), GL_STATIC_DRAW);
if (x == 0)
{
Chunk* westChunk = Planet::planet->GetChunk({ chunkPos.x - 1, chunkPos.y, chunkPos.z });
if (westChunk != nullptr)
westChunk->UpdateChunk();
}
else if (x == CHUNK_SIZE - 1)
{
Chunk* eastChunk = Planet::planet->GetChunk({ chunkPos.x + 1, chunkPos.y, chunkPos.z });
if (eastChunk != nullptr)
eastChunk->UpdateChunk();
}
if (y == 0)
{
Chunk* downChunk = Planet::planet->GetChunk({ chunkPos.x, chunkPos.y - 1, chunkPos.z });
if (downChunk != nullptr)
downChunk->UpdateChunk();
}
else if (y == CHUNK_SIZE - 1)
{
Chunk* upChunk = Planet::planet->GetChunk({ chunkPos.x, chunkPos.y + 1, chunkPos.z });
if (upChunk != nullptr)
upChunk->UpdateChunk();
}
if (z == 0)
{
Chunk* northChunk = Planet::planet->GetChunk({ chunkPos.x, chunkPos.y, chunkPos.z - 1 });
if (northChunk != nullptr)
northChunk->UpdateChunk();
}
else if (z == CHUNK_SIZE - 1)
{
Chunk* southChunk = Planet::planet->GetChunk({ chunkPos.x, chunkPos.y, chunkPos.z + 1 });
if (southChunk != nullptr)
southChunk->UpdateChunk();
}
}
void Chunk::UpdateChunk()
{
GenerateChunkMesh();
// Main
numTrianglesMain = mainIndices.size();
glBindVertexArray(mainVAO);
glBindBuffer(GL_ARRAY_BUFFER, mainVBO);
glBufferData(GL_ARRAY_BUFFER, mainVertices.size() * sizeof(Vertex), mainVertices.data(), GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mainEBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, mainIndices.size() * sizeof(unsigned int), mainIndices.data(), GL_STATIC_DRAW);
// Water
numTrianglesWater = waterIndices.size();
glBindVertexArray(waterVAO);
glBindBuffer(GL_ARRAY_BUFFER, waterVBO);
glBufferData(GL_ARRAY_BUFFER, waterVertices.size() * sizeof(WaterVertex), waterVertices.data(), GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, waterEBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, waterIndices.size() * sizeof(unsigned int), waterIndices.data(), GL_STATIC_DRAW);
// Billboard
numTrianglesBillboard = billboardIndices.size();
glBindVertexArray(billboardVAO);
glBindBuffer(GL_ARRAY_BUFFER, billboardVBO);
glBufferData(GL_ARRAY_BUFFER, billboardVertices.size() * sizeof(BillboardVertex), billboardVertices.data(), GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, billboardEBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, billboardIndices.size() * sizeof(unsigned int), billboardIndices.data(), GL_STATIC_DRAW);
}

View File

@ -6,31 +6,40 @@
#include "Shader.h"
#include "Vertex.h"
#include "ChunkPos.h"
#include "ChunkData.h"
class Chunk
{
public:
Chunk(unsigned int chunkSize, glm::vec3 chunkPos, Shader* shader, Shader* waterShader);
Chunk(ChunkPos chunkPos, Shader* shader, Shader* waterShader);
~Chunk();
void GenerateChunk();
void GenerateChunkMesh();
void Render(Shader* mainShader, Shader* billboardShader);
void RenderWater(Shader* shader);
unsigned int GetBlockAtPos(int x, int y, int z);
uint16_t GetBlockAtPos(int x, int y, int z);
void UpdateBlock(int x, int y, int z, uint16_t newBlock);
void UpdateChunk();
public:
std::vector<unsigned int> chunkData;
glm::vec3 chunkPos;
ChunkData* chunkData;
ChunkData* northData;
ChunkData* southData;
ChunkData* upData;
ChunkData* downData;
ChunkData* eastData;
ChunkData* westData;
ChunkPos chunkPos;
bool ready;
bool generated;
private:
unsigned int chunkSize;
glm::vec3 worldPos;
std::thread chunkThread;
std::vector<Vertex> mainVertices;
std::vector<unsigned int> mianIndices;
std::vector<unsigned int> mainIndices;
std::vector<WaterVertex> waterVertices;
std::vector<unsigned int> waterIndices;
std::vector<BillboardVertex> billboardVertices;

View File

@ -0,0 +1,39 @@
#include "ChunkData.h"
#include "Planet.h"
ChunkData::ChunkData(uint16_t* data)
: data(data)
{
}
ChunkData::~ChunkData()
{
delete[] data;
}
inline int ChunkData::GetIndex(int x, int y, int z) const
{
return x * CHUNK_SIZE * CHUNK_SIZE + z * CHUNK_SIZE + y;
}
inline int ChunkData::GetIndex(ChunkPos localBlockPos) const
{
return localBlockPos.x * CHUNK_SIZE * CHUNK_SIZE + localBlockPos.z * CHUNK_SIZE + localBlockPos.y;
}
uint16_t ChunkData::GetBlock(ChunkPos blockPos)
{
return data[GetIndex(blockPos)];
}
uint16_t ChunkData::GetBlock(int x, int y, int z)
{
return data[GetIndex(x, y, z)];
}
void ChunkData::SetBlock(int x, int y, int z, uint16_t block)
{
data[GetIndex(x, y, z)] = block;
}

View File

@ -0,0 +1,20 @@
#pragma once
#include <cstdint>
#include "ChunkPos.h"
struct ChunkData
{
uint16_t* data;
ChunkData(uint16_t* data);
~ChunkData();
inline int GetIndex(int x, int y, int z) const;
inline int GetIndex(ChunkPos localBlockPos) const;
uint16_t GetBlock(ChunkPos blockPos);
uint16_t GetBlock(int x, int y, int z);
void SetBlock(int x, int y, int z, uint16_t block);
};

View File

@ -0,0 +1,18 @@
#include "ChunkPos.h"
ChunkPos::ChunkPos()
: x(0), y(0), z(0)
{
}
ChunkPos::ChunkPos(int x, int y, int z)
: x(x), y(y), z(z)
{
}
bool ChunkPos::operator==(const ChunkPos& other) const
{
return other.x == x && other.y == y && other.z == z;
}

View File

@ -0,0 +1,13 @@
#pragma once
struct ChunkPos
{
int x;
int y;
int z;
ChunkPos();
ChunkPos(int x, int y, int z);
bool operator==(const ChunkPos& other) const;
};

View File

@ -0,0 +1,15 @@
#include "ChunkPos.h"
#include <unordered_map>
struct ChunkPosHash
{
std::size_t operator()(const ChunkPos& key) const
{
std::size_t hx = std::hash<int>()(key.x);
std::size_t hy = std::hash<int>()(key.y);
std::size_t hz = std::hash<int>()(key.z);
// Combine the hashes using bitwise XOR and shifting
return hx ^ (hy << 1) ^ (hz << 2);
}
};

View File

@ -0,0 +1,47 @@
#include "Physics.h"
#include <iostream>
#include "Blocks.h"
Physics::RaycastResult Physics::Raycast(const glm::vec3 startPos, const glm::vec3 direction, const float maxDistance)
{
float currentDistance = 0;
while (currentDistance < maxDistance)
{
currentDistance += Physics::RAY_STEP;
if (currentDistance > maxDistance)
currentDistance = maxDistance;
// Get chunk
glm::vec3 resultPos = startPos + direction * currentDistance;
int chunkX = resultPos.x >= 0 ? resultPos.x / CHUNK_SIZE : resultPos.x / CHUNK_SIZE - 1;
int chunkY = resultPos.y >= 0 ? resultPos.y / CHUNK_SIZE : resultPos.y / CHUNK_SIZE - 1;
int chunkZ = resultPos.z >= 0 ? resultPos.z / CHUNK_SIZE : resultPos.z / CHUNK_SIZE - 1;
Chunk* chunk = Planet::planet->GetChunk(ChunkPos(chunkX, chunkY, chunkZ));
if (chunk == nullptr)
continue;
// Get block pos
int localBlockX = (int)floor(resultPos.x) % CHUNK_SIZE;
int localBlockZ = (int)floor(resultPos.z) % CHUNK_SIZE;
int localBlockY = (int)floor(resultPos.y) % CHUNK_SIZE;
// Get block from chunk
unsigned int block = chunk->GetBlockAtPos(localBlockX, localBlockY, localBlockZ);
// Get result pos
int blockX = resultPos.x >= 0 ? (int)resultPos.x : (int)resultPos.x - 1;
int blockY = resultPos.y >= 0 ? (int)resultPos.y : (int)resultPos.y - 1;
int blockZ = resultPos.z >= 0 ? (int)resultPos.z : (int)resultPos.z - 1;
// Return true if it hit a block
if (block != 0 && Blocks::blocks[block].blockType != Block::LIQUID)
return { true, resultPos, chunk,
blockX, blockY, blockZ,
localBlockX, localBlockY, localBlockZ};
}
return { false, glm::vec3(0), nullptr,
0, 0, 0,
0, 0, 0};
}

View File

@ -0,0 +1,30 @@
#pragma once
#include "glm/glm.hpp"
#include "Planet.h"
namespace Physics
{
struct RaycastResult
{
bool hit;
glm::vec3 hitPos;
Chunk* chunk;
int blockX;
int blockY;
int blockZ;
int localBlockX;
int localBlockY;
int localBlockZ;
RaycastResult(bool hit, glm::vec3 hitPos, Chunk* chunk, int blockX, int blockY, int blockZ, int localBlockX, int localBlockY, int localBlockZ)
: hit(hit), hitPos(hitPos), chunk(chunk), blockX(blockX), blockY(blockY), blockZ(blockZ), localBlockX(localBlockX), localBlockY(localBlockY), localBlockZ(localBlockZ)
{
}
};
RaycastResult Raycast(glm::vec3 startPos, glm::vec3 direction, float maxDistance);
static constexpr float RAY_STEP = 0.01f;
}

View File

@ -4,43 +4,109 @@
#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include "WorldGen.h"
Planet* Planet::planet = nullptr;
const unsigned int Planet::chunkSize = 32;
//static const unsigned int CHUNK_SIZE = 32;
// Public
Planet::Planet(Shader* solidShader, Shader* waterShader, Shader* billboardShader)
: solidShader(solidShader), waterShader(waterShader), billboardShader(billboardShader)
{
chunkThread = std::thread(&Planet::ChunkThreadUpdate, this);
}
Planet::~Planet()
{
shouldEnd = true;
chunkThread.join();
}
std::vector<unsigned int> Planet::GetChunkData(int chunkX, int chunkY, int chunkZ)
void Planet::Update(glm::vec3 cameraPos)
{
std::tuple<int, int, int> chunkTuple{ chunkX, chunkY, chunkZ };
camChunkX = cameraPos.x < 0 ? floor(cameraPos.x / CHUNK_SIZE) : cameraPos.x / CHUNK_SIZE;
camChunkY = cameraPos.y < 0 ? floor(cameraPos.y / CHUNK_SIZE) : cameraPos.y / CHUNK_SIZE;
camChunkZ = cameraPos.z < 0 ? floor(cameraPos.z / CHUNK_SIZE) : cameraPos.z / CHUNK_SIZE;
if (chunks.find(chunkTuple) == chunks.end())
glDisable(GL_BLEND);
chunksLoading = 0;
numChunks = 0;
numChunksRendered = 0;
chunkMutex.lock();
for (auto it = chunks.begin(); it != chunks.end(); )
{
return std::vector<unsigned int>{};
//return GenerateChunkData(chunkX, chunkY, chunkZ);
numChunks++;
if (!(*it->second).ready)
chunksLoading++;
int chunkX = (*it->second).chunkPos.x;
int chunkY = (*it->second).chunkPos.y;
int chunkZ = (*it->second).chunkPos.z;
if ((*it->second).ready && (abs(chunkX - camChunkX) > renderDistance ||
abs(chunkY - camChunkY) > renderDistance ||
abs(chunkZ - camChunkZ) > renderDistance))
{
// Out of range
// Add chunk data to delete queue
chunkDataDeleteQueue.push({ chunkX, chunkY, chunkZ });
chunkDataDeleteQueue.push({ chunkX + 1, chunkY, chunkZ });
chunkDataDeleteQueue.push({ chunkX - 1, chunkY, chunkZ });
chunkDataDeleteQueue.push({ chunkX, chunkY + 1, chunkZ });
chunkDataDeleteQueue.push({ chunkX, chunkY - 1, chunkZ });
chunkDataDeleteQueue.push({ chunkX, chunkY, chunkZ + 1 });
chunkDataDeleteQueue.push({ chunkX, chunkY, chunkZ - 1 });
// Delete chunk
delete it->second;
it = chunks.erase(it);
}
else
{
return std::vector<unsigned int>{};
//return chunks.at(chunkTuple).chunkData;
numChunksRendered++;
(*it->second).Render(solidShader, billboardShader);
++it;
}
}
void Planet::Update(float camX, float camY, float camZ)
glEnable(GL_BLEND);
waterShader->use();
for (auto it = chunks.begin(); it != chunks.end(); )
{
int camChunkX = camX < 0 ? floor(camX / chunkSize) : camX / chunkSize;
int camChunkY = camY < 0 ? floor(camY / chunkSize) : camY / chunkSize;
int camChunkZ = camZ < 0 ? floor(camZ / chunkSize) : camZ / chunkSize;
int chunkX = (*it->second).chunkPos.x;
int chunkY = (*it->second).chunkPos.y;
int chunkZ = (*it->second).chunkPos.z;
(*it->second).RenderWater(waterShader);
++it;
}
chunkMutex.unlock();
}
void Planet::ChunkThreadUpdate()
{
while (!shouldEnd)
{
for (auto it = chunkData.begin(); it != chunkData.end(); )
{
ChunkPos pos = it->first;
if (chunks.find(pos) == chunks.end() &&
chunks.find({ pos.x + 1, pos.y, pos.z }) == chunks.end() &&
chunks.find({ pos.x - 1, pos.y, pos.z }) == chunks.end() &&
chunks.find({ pos.x, pos.y + 1, pos.z }) == chunks.end() &&
chunks.find({ pos.x, pos.y - 1, pos.z }) == chunks.end() &&
chunks.find({ pos.x, pos.y, pos.z + 1 }) == chunks.end() &&
chunks.find({ pos.x, pos.y, pos.z - 1 }) == chunks.end())
{
delete chunkData.at(pos);
chunkData.erase(pos);
}
++it;
}
// Check if camera moved to new chunk
if (camChunkX != lastCamX || camChunkY != lastCamY || camChunkZ != lastCamZ)
@ -51,6 +117,7 @@ void Planet::Update(float camX, float camY, float camZ)
lastCamZ = camChunkZ;
// Current chunk
chunkMutex.lock();
chunkQueue = {};
if (chunks.find({ camChunkX, camChunkY, camChunkZ }) == chunks.end())
chunkQueue.push({ camChunkX, camChunkY, camChunkZ });
@ -125,75 +192,270 @@ void Planet::Update(float camX, float camY, float camZ)
}
}
}
}
else if (chunksLoading == 0 && !chunkQueue.empty())
{
// Queue is not empty. Process front item in queue
glm::vec3 next = chunkQueue.front();
chunkQueue.pop();
std::tuple<int, int, int> chunkTuple{ next.x, next.y, next.z };
if (chunks.find(chunkTuple) == chunks.end())
{
chunks.try_emplace(chunkTuple,
chunkSize, next, solidShader, waterShader
);
}
}
glDisable(GL_BLEND);
chunksLoading = 0;
numChunks = 0;
numChunksRendered = 0;
for (auto it = chunks.begin(); it != chunks.end(); )
{
numChunks++;
if (!it->second.ready)
chunksLoading++;
int chunkX = it->second.chunkPos.x;
int chunkY = it->second.chunkPos.y;
int chunkZ = it->second.chunkPos.z;
if (it->second.ready && (abs(chunkX - camChunkX) > renderDistance ||
abs(chunkY - camChunkY) > renderDistance ||
abs(chunkZ - camChunkZ) > renderDistance))
{
it = chunks.erase(it);
chunkMutex.unlock();
}
else
{
numChunksRendered++;
it->second.Render(solidShader, billboardShader);
++it;
}
}
glEnable(GL_BLEND);
waterShader->use();
for (auto it = chunks.begin(); it != chunks.end(); )
chunkMutex.lock();
if (!chunkDataQueue.empty())
{
int chunkX = it->second.chunkPos.x;
int chunkY = it->second.chunkPos.y;
int chunkZ = it->second.chunkPos.z;
ChunkPos chunkPos = chunkDataQueue.front();
it->second.RenderWater(waterShader);
++it;
if (chunkData.find(chunkPos) != chunkData.end())
{
chunkDataQueue.pop();
chunkMutex.unlock();
continue;
}
chunkMutex.unlock();
uint16_t* d = new uint16_t[CHUNK_SIZE * CHUNK_SIZE * CHUNK_SIZE];
ChunkData* data = new ChunkData(d);
WorldGen::GenerateChunkData(chunkPos, d);
chunkMutex.lock();
chunkData[chunkPos] = data;
chunkDataQueue.pop();
chunkMutex.unlock();
}
else
{
if (!chunkQueue.empty())
{
// Check if chunk exists
ChunkPos chunkPos = chunkQueue.front();
if (chunks.find(chunkPos) != chunks.end())
{
chunkQueue.pop();
chunkMutex.unlock();
continue;
}
chunkMutex.unlock();
// Create chunk object
Chunk* chunk = new Chunk(chunkPos, solidShader, waterShader);
// Set chunk data
{
chunkMutex.lock();
if (chunkData.find(chunkPos) == chunkData.end())
{
chunkMutex.unlock();
uint16_t* d = new uint16_t[CHUNK_SIZE * CHUNK_SIZE * CHUNK_SIZE];
WorldGen::GenerateChunkData(chunkPos, d);
ChunkData* data = new ChunkData(d);
chunk->chunkData = data;
chunkMutex.lock();
chunkData[chunkPos] = data;
chunkMutex.unlock();
}
else
{
chunk->chunkData = chunkData.at(chunkPos);
chunkMutex.unlock();
}
}
Chunk* Planet::GetChunk(int chunkX, int chunkY, int chunkZ)
// Set top data
{
std::tuple<int, int, int> chunkTuple{ chunkX, chunkY, chunkZ };
ChunkPos topPos(chunkPos.x, chunkPos.y + 1, chunkPos.z);
chunkMutex.lock();
if (chunkData.find(topPos) == chunkData.end())
{
chunkMutex.unlock();
uint16_t* d = new uint16_t[CHUNK_SIZE * CHUNK_SIZE * CHUNK_SIZE];
if (chunks.find(chunkTuple) == chunks.end())
WorldGen::GenerateChunkData(topPos, d);
ChunkData* data = new ChunkData(d);
chunk->upData = data;
chunkMutex.lock();
chunkData[topPos] = data;
chunkMutex.unlock();
}
else
{
chunk->upData = chunkData.at(topPos);
chunkMutex.unlock();
}
}
// Set bottom data
{
ChunkPos bottomPos(chunkPos.x, chunkPos.y - 1, chunkPos.z);
chunkMutex.lock();
if (chunkData.find(bottomPos) == chunkData.end())
{
chunkMutex.unlock();
uint16_t* d = new uint16_t[CHUNK_SIZE * CHUNK_SIZE * CHUNK_SIZE];
WorldGen::GenerateChunkData(bottomPos, d);
ChunkData* data = new ChunkData(d);
chunk->downData = data;
chunkMutex.lock();
chunkData[bottomPos] = data;
chunkMutex.unlock();
}
else
{
chunk->downData = chunkData.at(bottomPos);
chunkMutex.unlock();
}
}
// Set north data
{
ChunkPos northPos(chunkPos.x, chunkPos.y, chunkPos.z - 1);
chunkMutex.lock();
if (chunkData.find(northPos) == chunkData.end())
{
chunkMutex.unlock();
uint16_t* d = new uint16_t[CHUNK_SIZE * CHUNK_SIZE * CHUNK_SIZE];
WorldGen::GenerateChunkData(northPos, d);
ChunkData* data = new ChunkData(d);
chunk->northData = data;
chunkMutex.lock();
chunkData[northPos] = data;
chunkMutex.unlock();
}
else
{
chunk->northData = chunkData.at(northPos);
chunkMutex.unlock();
}
}
// Set south data
{
ChunkPos southPos(chunkPos.x, chunkPos.y, chunkPos.z + 1);
chunkMutex.lock();
if (chunkData.find(southPos) == chunkData.end())
{
chunkMutex.unlock();
uint16_t* d = new uint16_t[CHUNK_SIZE * CHUNK_SIZE * CHUNK_SIZE];
WorldGen::GenerateChunkData(southPos, d);
ChunkData* data = new ChunkData(d);
chunk->southData = data;
chunkMutex.lock();
chunkData[southPos] = data;
chunkMutex.unlock();
}
else
{
chunk->southData = chunkData.at(southPos);
chunkMutex.unlock();
}
}
// Set east data
{
ChunkPos eastPos(chunkPos.x + 1, chunkPos.y, chunkPos.z);
chunkMutex.lock();
if (chunkData.find(eastPos) == chunkData.end())
{
chunkMutex.unlock();
uint16_t* d = new uint16_t[CHUNK_SIZE * CHUNK_SIZE * CHUNK_SIZE];
WorldGen::GenerateChunkData(eastPos, d);
ChunkData* data = new ChunkData(d);
chunk->eastData = data;
chunkMutex.lock();
chunkData[eastPos] = data;
chunkMutex.unlock();
}
else
{
chunk->eastData = chunkData.at(eastPos);
chunkMutex.unlock();
}
}
// Set west data
{
ChunkPos westPos(chunkPos.x - 1, chunkPos.y, chunkPos.z);
chunkMutex.lock();
if (chunkData.find(westPos) == chunkData.end())
{
chunkMutex.unlock();
uint16_t* d = new uint16_t[CHUNK_SIZE * CHUNK_SIZE * CHUNK_SIZE];
WorldGen::GenerateChunkData(westPos, d);
ChunkData* data = new ChunkData(d);
chunk->westData = data;
chunkMutex.lock();
chunkData[westPos] = data;
chunkMutex.unlock();
}
else
{
chunk->westData = chunkData.at(westPos);
chunkMutex.unlock();
}
}
// Generate chunk mesh
chunk->GenerateChunkMesh();
// Finish
chunkMutex.lock();
chunks[chunkPos] = chunk;
chunkQueue.pop();
chunkMutex.unlock();
}
else
{
chunkMutex.unlock();
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
}
}
}
}
}
Chunk* Planet::GetChunk(ChunkPos chunkPos)
{
chunkMutex.lock();
if (chunks.find(chunkPos) == chunks.end())
{
chunkMutex.unlock();
return nullptr;
}
else
{
return &chunks.at(chunkTuple);
chunkMutex.unlock();
return chunks.at(chunkPos);
}
}
void Planet::ClearChunkQueue()
{
lastCamX++;
}

View File

@ -5,9 +5,15 @@
#include <string>
#include <queue>
#include <glm/glm.hpp>
#include <thread>
#include <mutex>
#include "ChunkPos.h"
#include "ChunkData.h"
#include "Chunk.h"
#include "TupleHash.h"
#include "ChunkPosHash.h"
constexpr unsigned int CHUNK_SIZE = 32;
class Planet
{
@ -16,26 +22,38 @@ public:
Planet(Shader* solidShader, Shader* waterShader, Shader* billboardShader);
~Planet();
std::vector<unsigned int> GetChunkData(int chunkX, int chunkY, int chunkZ);
void Update(float camX, float camY, float camZ);
ChunkData* GetChunkData(ChunkPos chunkPos);
void Update(glm::vec3 cameraPos);
Chunk* GetChunk(int chunkX, int chunkY, int chunkZ);
Chunk* GetChunk(ChunkPos chunkPos);
void ClearChunkQueue();
private:
void ChunkThreadUpdate();
// Variables
public:
static Planet* planet;
unsigned int numChunks = 0, numChunksRendered = 0;
static const unsigned int chunkSize;
int renderDistance = 10;
int renderHeight = 3;
private:
std::unordered_map<std::tuple<int, int, int>, Chunk> chunks;
std::queue<glm::vec3> chunkQueue;
int renderDistance = 3;
int renderHeight = 1;
std::unordered_map<ChunkPos, Chunk*, ChunkPosHash> chunks;
std::unordered_map<ChunkPos, ChunkData*, ChunkPosHash> chunkData;
std::queue<ChunkPos> chunkQueue;
std::queue<ChunkPos> chunkDataQueue;
std::queue<ChunkPos> chunkDataDeleteQueue;
unsigned int chunksLoading = 0;
int lastCamX = -100, lastCamY = -100, lastCamZ = -100;
int camChunkX = -100, camChunkY = -100, camChunkZ = -100;
Shader* solidShader;
Shader* waterShader;
Shader* billboardShader;
std::thread chunkThread;
std::mutex chunkMutex;
bool shouldEnd = false;
};

View File

@ -1,53 +0,0 @@
#include <tuple>
// function has to live in the std namespace
// so that it is picked up by argument-dependent name lookup (ADL).
namespace std {
namespace
{
// Code from boost
// Reciprocal of the golden ratio helps spread entropy
// and handles duplicates.
// See Mike Seymour in magic-numbers-in-boosthash-combine:
// https://stackoverflow.com/questions/4948780
template <class T>
inline void hash_combine(std::size_t& seed, T const& v)
{
seed ^= hash<T>()(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
}
// Recursive template code derived from Matthieu M.
template <class Tuple, size_t Index = std::tuple_size<Tuple>::value - 1>
struct HashValueImpl
{
static void apply(size_t& seed, Tuple const& tuple)
{
HashValueImpl<Tuple, Index - 1>::apply(seed, tuple);
hash_combine(seed, get<Index>(tuple));
}
};
template <class Tuple>
struct HashValueImpl<Tuple, 0>
{
static void apply(size_t& seed, Tuple const& tuple)
{
hash_combine(seed, get<0>(tuple));
}
};
}
template <typename ... TT>
struct hash<std::tuple<TT...>>
{
size_t
operator()(std::tuple<TT...> const& tt) const
{
size_t seed = 0;
HashValueImpl<std::tuple<TT...> >::apply(seed, tt);
return seed;
}
};
}

View File

@ -5,9 +5,12 @@
#include <OpenSimplexNoise.hh>
#include "Blocks.h"
#include "Planet.h"
void WorldGen::GenerateChunkData(int chunkX, int chunkY, int chunkZ, int chunkSize, std::vector<unsigned int>* chunkData)
void WorldGen::GenerateChunkData(ChunkPos chunkPos, uint16_t* chunkData)
{
static int chunkSize = CHUNK_SIZE;
// Init noise
static OSN::Noise<2> noise2D;
static OSN::Noise<3> noise3D;
@ -284,14 +287,12 @@ void WorldGen::GenerateChunkData(int chunkX, int chunkY, int chunkZ, int chunkSi
static int waterLevel = 20;
// Set vector size
chunkData->reserve(chunkSize * chunkSize * chunkSize);
// Account for chunk position
int startX = chunkX * chunkSize;
int startY = chunkY * chunkSize;
int startZ = chunkZ * chunkSize;
int startX = chunkPos.x * chunkSize;
int startY = chunkPos.y * chunkSize;
int startZ = chunkPos.z * chunkSize;
int currentIndex = 0;
for (int x = 0; x < chunkSize; x++)
{
for (int z = 0; z < chunkSize; z++)
@ -334,12 +335,12 @@ void WorldGen::GenerateChunkData(int chunkX, int chunkY, int chunkZ, int chunkSi
if (y + startY > noiseY)
{
if (y + startY <= waterLevel)
chunkData->push_back(Blocks::WATER);
chunkData[currentIndex] = Blocks::WATER;
else
chunkData->push_back(Blocks::AIR);
chunkData[currentIndex] = Blocks::AIR;
}
else if (cave)
chunkData->push_back(Blocks::AIR);
chunkData[currentIndex] = Blocks::AIR;
// Ground
else
{
@ -357,7 +358,7 @@ void WorldGen::GenerateChunkData(int chunkX, int chunkY, int chunkZ, int chunkSi
if (noiseOre > oreSettings[i].chance)
{
chunkData->push_back(oreSettings[i].block);
chunkData[currentIndex] = oreSettings[i].block;
blockSet = true;
break;
}
@ -366,13 +367,21 @@ void WorldGen::GenerateChunkData(int chunkX, int chunkY, int chunkZ, int chunkSi
if (!blockSet)
{
if (y + startY == noiseY)
chunkData->push_back(Blocks::GRASS_BLOCK);
else if (y + startY > 10)
chunkData->push_back(Blocks::DIRT_BLOCK);
if (noiseY > waterLevel + 1)
chunkData[currentIndex] = Blocks::GRASS_BLOCK;
else
chunkData->push_back(Blocks::STONE_BLOCK);
chunkData[currentIndex] = Blocks::SAND;
else if (y + startY > 10)
if (noiseY > waterLevel + 1)
chunkData[currentIndex] = Blocks::DIRT_BLOCK;
else
chunkData[currentIndex] = Blocks::SAND;
else
chunkData[currentIndex] = Blocks::STONE_BLOCK;
}
}
currentIndex++;
}
}
}
@ -393,11 +402,11 @@ void WorldGen::GenerateChunkData(int chunkX, int chunkY, int chunkZ, int chunkSi
* surfaceSettings[s].amplitude;
}
if (noiseY + surfaceFeatures[i].offsetY > startY + 32 || noiseY + surfaceFeatures[i].sizeY + surfaceFeatures[i].offsetY < startY)
if (noiseY + surfaceFeatures[i].offsetY > startY + chunkSize || noiseY + surfaceFeatures[i].sizeY + surfaceFeatures[i].offsetY < startY)
continue;
// Check if it's in water
if (noiseY < waterLevel)
// Check if it's in water or on sand
if (noiseY < waterLevel + 2)
continue;
// Check if it's in a cave
@ -446,11 +455,11 @@ void WorldGen::GenerateChunkData(int chunkX, int chunkY, int chunkZ, int chunkSi
int localZ = featureZ + fZ + surfaceFeatures[i].offsetZ - startZ;
//std::cout << "FeatureZ: " << featureZ << ", fZ: " << fZ << ", startZ: " << startZ << ", localZ: " << localZ << '\n';
if (localX >= 32 || localX < 0)
if (localX >= chunkSize || localX < 0)
continue;
if (localY >= 32 || localY < 0)
if (localY >= chunkSize || localY < 0)
continue;
if (localZ >= 32 || localZ < 0)
if (localZ >= chunkSize || localZ < 0)
continue;
int featureIndex = fY * surfaceFeatures[i].sizeX * surfaceFeatures[i].sizeZ +
@ -460,8 +469,8 @@ void WorldGen::GenerateChunkData(int chunkX, int chunkY, int chunkZ, int chunkSi
int localIndex = localX * chunkSize * chunkSize + localZ * chunkSize + localY;
//std::cout << "Local Index: " << localIndex << ", Max Index: " << chunkData->size() << '\n';
if (surfaceFeatures[i].replaceBlock[featureIndex] || chunkData->at(localIndex) == 0)
chunkData->at(localIndex) = surfaceFeatures[i].blocks[featureIndex];
if (surfaceFeatures[i].replaceBlock[featureIndex] || chunkData[localIndex] == 0)
chunkData[localIndex] = surfaceFeatures[i].blocks[featureIndex];
}
}
}

View File

@ -3,9 +3,10 @@
#include <vector>
#include "NoiseSettings.h"
#include "SurfaceFeature.h"
#include "ChunkData.h"
#include "glm/glm.hpp"
namespace WorldGen
{
void GenerateChunkData(int chunkX, int chunkY, int chunkZ, int chunkSize, std::vector<unsigned int>* chunkData);
void GenerateChunkData(ChunkPos chunkPos, uint16_t* chunkData);
}