Compare commits

...

23 Commits

Author SHA1 Message Date
WSAL Evan
ccacb3088f
Merge pull request #20 from StillGreen-san/fix-selected-block-text
fix "Selected Block" text display
2024-11-02 12:09:55 -04:00
StillGreen-san
93897037b8
fix "Selected Block" text display 2024-11-02 11:23:17 +01:00
WSAL Evan
90f1cc59d5
Merge pull request #19 from FoxMoss/main
Update CMake for new files
2024-11-01 21:00:53 -04:00
FoxMoss
b4e22d076b
Update CMake for new files 2024-11-01 16:28:08 -05:00
WSAL Evan
41e3abe45e Episode 5 2024-11-01 13:41:23 -04:00
WSAL Evan
70157a4f7f
Merge pull request #14 from Just-Random-Dev/main
fix camera up and down movement and ignore missing pdb warning
2024-10-23 07:58:51 -04:00
WSAL Evan
a34f2fd9a3
Merge pull request #10 from FoxMoss/main
feat: allow cmake built executable to be run anywhere
2024-10-20 10:52:23 -04:00
WSAL Evan
28cc58d2c6
Merge pull request #15 from fintmc/main
fix framebuffer resize
2024-10-20 10:48:49 -04:00
fintmc
7d074585c1 resize framebuffer textures 2024-10-20 17:01:06 +03:00
Just-Random-Dev
bffb488446 Make camera go up and down properly and ignore missing pdb warning 2024-10-20 12:41:02 +02:00
FoxMoss
cced9a2b95
feat: provide reasonable response to a lack of asset directory 2024-10-19 18:42:28 -05:00
FoxMoss
ec70bb48ac
feat: allow cmake built executable to be run anywhere 2024-10-19 13:22:55 -05:00
WSAL Evan
7788b5f6be
Merge pull request #7 from williamistGitHub/fix-cmake
Fix cmake
2024-10-18 18:58:58 -04:00
williamistGitHub
734030edcb fix weird gcc thing (i dont even know) 2024-10-18 18:24:58 -04:00
williamistGitHub
6c3f2ddd84 fix linking glfw on linux 2024-10-18 18:17:23 -04:00
williamistGitHub
34ba20188f fix running from vs 2024-10-18 17:19:44 -04:00
williamistGitHub
f58173649b fix cmake building 2024-10-18 17:05:31 -04:00
WSAL Evan
4e1c4fe98a Episode 4 - Water 2024-10-18 10:07:14 -04:00
WSAL Evan
117e2c321d
Merge pull request #6 from fintmc/main
Fix CMake Support
2024-10-06 18:29:02 -04:00
fintmc
e7dd7d13d3 Add CMake build instructions 2024-10-06 14:05:21 +03:00
fintmc
d8aaa00f1a fix cmake support 2024-10-06 14:04:55 +03:00
WSAL Evan
8b26492b78
Merge pull request #4 from FoxMoss/main
Add CMake Support
2024-10-04 18:24:25 -04:00
FoxMoss
5d485b21a5
Add cmake support 2024-10-04 17:16:59 -05:00
43 changed files with 2259 additions and 566 deletions

2
.gitignore vendored
View File

@ -410,3 +410,5 @@ FodyWeavers.xsd
*.sln.iml
imgui.ini
build/

View File

@ -3,3 +3,29 @@ A Minecraft clone made in C++ and OpenGL
## How to Run
To run the game, download the ScuffedMinecraft zip file from the [latest release](https://github.com/EvanatorM/ScuffedMinecraft/releases/latest), unzip the file, and run ScuffedMinecraft.exe. The assets folder must be in the same place as the exe file.
## Building
### Building with Visual Studio
Import the project in Visual Studio 17 or higher and build it.
### Building with CMake
In the project root directory:
Create CMake files:
```sh
mkdir -p build
cd build
cmake ../ScuffedMinecraft
```
After that you can build the project using:
```sh
cmake --build ./build
```
Run the build command in the project root directory.
The final executable can be found at `(project root)/ScuffedMinecraft/bin`
#### Note for building with CMake
If you're running from a command line, make sure to run
the executable in the same directory as it is located
to ensure all resources are loaded properly.

View File

@ -0,0 +1,26 @@
cmake_minimum_required(VERSION 3.10)
set(CMAKE_CXX_STANDARD 20)
project(ScuffedMinecraft)
# output directories
set(CMAKE_BINARY_DIR ${CMAKE_SOURCE_DIR}/bin)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
# copy assets
add_custom_target(copy_assets ALL
COMMAND ${CMAKE_COMMAND} -E copy_directory
${CMAKE_SOURCE_DIR}/assets
${CMAKE_BINARY_DIR}/assets
COMMENT "Copying assets")
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
# global dependency directories
include_directories(../Dependencies/include/)
link_directories(../Dependencies/lib/)
add_subdirectory(vendor/imgui)
add_subdirectory(src)

View File

@ -130,6 +130,7 @@
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>glfw3.lib;opengl32.lib;$(CoreLibraryDependencies);%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalOptions>/ignore:4099 %(AdditionalOptions)</AdditionalOptions>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
@ -148,6 +149,7 @@
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>glfw3.lib;opengl32.lib;$(CoreLibraryDependencies);%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalOptions>/ignore:4099 %(AdditionalOptions)</AdditionalOptions>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
@ -155,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" />
@ -176,10 +181,14 @@
<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" />
<ClInclude Include="src\Vertex.h" />
<ClInclude Include="vendor\imgui\imconfig.h" />
<ClInclude Include="vendor\imgui\imgui.h" />
<ClInclude Include="vendor\imgui\imgui_impl_glfw.h" />
@ -193,11 +202,22 @@
<ClInclude Include="vendor\stb_image.h" />
</ItemGroup>
<ItemGroup>
<None Include="assets\shaders\fragment_shader.glsl" />
<None Include="assets\shaders\vertex_shader.glsl" />
<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" />
<None Include="assets\shaders\main_vert.glsl" />
<None Include="assets\shaders\water_frag.glsl" />
<None Include="assets\shaders\water_vert.glsl" />
</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">
@ -131,15 +140,40 @@
<ClInclude Include="src\SurfaceFeature.h">
<Filter>Header Files</Filter>
</ClInclude>
<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\vertex_shader.glsl" />
<None Include="assets\shaders\fragment_shader.glsl" />
<None Include="assets\shaders\main_vert.glsl" />
<None Include="assets\shaders\main_frag.glsl" />
<None Include="assets\shaders\water_frag.glsl" />
<None Include="assets\shaders\water_vert.glsl" />
<None Include="assets\shaders\billboard_vert.glsl" />
<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,27 @@
#version 330 core
in vec2 TexCoord;
out vec4 FragColor;
uniform sampler2D tex;
const vec3 ambient = vec3(.5);
const vec3 lightDirection = vec3(0.8, 1, 0.7);
const vec3 normal = vec3( 0, -1, 0);
void main()
{
vec3 lightDir = normalize(-lightDirection);
float diff = max(dot(normal, lightDir), 0.0);
vec3 diffuse = diff * vec3(1);
vec4 result = vec4(ambient + diffuse, 1.0);
vec4 texResult = texture(tex, TexCoord);
if (texResult.a == 0)
discard;
FragColor = texResult * result;
}

View File

@ -0,0 +1,19 @@
#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec2 aTexCoord;
out vec2 TexCoord;
out vec3 Normal;
uniform float texMultiplier;
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
void main()
{
gl_Position = projection * view * model * vec4(aPos, 1.0);
TexCoord = aTexCoord * texMultiplier;
}

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;
}

View File

@ -0,0 +1,32 @@
#version 330 core
out vec4 FragColor;
in vec2 TexCoords;
uniform sampler2D screenTexture;
uniform sampler2D depthTexture;
uniform bool underwater;
const vec3 fogColor = vec3(0, 0, 0.25);
const float fogNear = 0.9;
const float fogFar = 1.0;
void main()
{
vec3 color = texture(screenTexture, TexCoords).rgb;
float depth = texture(depthTexture, TexCoords).r;
vec3 finalColor = color;
// Calculate fog
if (underwater)
{
float fogFactor = (fogFar - depth) / (fogFar - fogNear);
fogFactor = clamp(fogFactor, 0.0, 1.0);
finalColor = mix(fogColor, color, fogFactor);
}
FragColor = vec4(vec3(finalColor), 1.0);
}

View File

@ -0,0 +1,12 @@
#version 330 core
layout (location = 0) in vec2 inPos;
layout (location = 1) in vec2 inTexCoords;
out vec2 TexCoords;
void main()
{
gl_Position = vec4(inPos.x, inPos.y, 0.0, 1.0);
TexCoords = inTexCoords;
}

View File

@ -1,6 +1,5 @@
#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec2 aTexCoord;
layout (location = 2) in int aDirection;
@ -13,6 +12,7 @@ uniform float texMultiplier;
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
uniform float time;
// Array of possible normals based on direction
const vec3 normals[] = vec3[](

View File

@ -0,0 +1,26 @@
#version 330 core
in vec2 TexCoord;
in vec3 Normal;
out vec4 FragColor;
uniform sampler2D tex;
vec3 ambient = vec3(.5);
vec3 lightDirection = vec3(0.8, 1, 0.7);
void main()
{
vec3 lightDir = normalize(-lightDirection);
float diff = max(dot(Normal, lightDir), 0.0);
vec3 diffuse = diff * vec3(1);
vec4 result = vec4(ambient + diffuse, 1.0);
vec4 texResult = texture(tex, TexCoord);
if (texResult.a == 0)
discard;
FragColor = texResult * result;
}

View File

@ -0,0 +1,47 @@
#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec2 aTexCoord;
layout (location = 2) in int aDirection;
layout (location = 3) in int aTop;
out vec2 TexCoord;
out vec3 Normal;
uniform float texMultiplier;
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
uniform float time;
// Array of possible normals based on direction
const vec3 normals[] = vec3[](
vec3( 0, 0, 1), // 0
vec3( 0, 0, -1), // 1
vec3( 1, 0, 0), // 2
vec3(-1, 0, 0), // 3
vec3( 0, 1, 0), // 4
vec3( 0, -1, 0), // 5
vec3( 0, -1, 0) // 6
);
const int aFrames = 32;
const float animationTime = 5;
const int texNum = 16;
void main()
{
vec3 pos = aPos;
if (aTop == 1)
{
pos.y -= .1;
pos.y += (sin(pos.x * 3.1415926535 / 2 + time) + sin(pos.z * 3.1415926535 / 2 + time * 1.5)) * .05;
}
gl_Position = projection * view * model * vec4(pos, 1.0);
vec2 currentTex = aTexCoord;
currentTex.x += mod(floor(mod(time / animationTime, 1) * aFrames), texNum);
currentTex.y += floor(floor(mod(time / animationTime, 1) * aFrames) / texNum);
TexCoord = currentTex * texMultiplier;
Normal = normals[aDirection];
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.4 KiB

After

Width:  |  Height:  |  Size: 9.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 246 B

View File

@ -2,6 +2,13 @@
#include "imgui_impl_glfw.h"
#include "imgui_impl_opengl3.h"
#ifdef LINUX
#include <cstdlib>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#endif
#include <glad/glad.h>
#include <GLFW/glfw3.h>
#define STB_IMAGE_IMPLEMENTATION
@ -16,11 +23,14 @@
#include "Shader.h"
#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;
@ -34,17 +44,94 @@ 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;
// Window options
#define VSYNC 1 // 0 for off, 1 for on
GLuint framebufferTexture;
GLuint depthTexture;
int main()
float rectangleVertices[] =
{
// Coords // TexCoords
1.0f, -1.0f, 1.0f, 0.0f,
-1.0f, -1.0f, 0.0f, 0.0f,
-1.0f, 1.0f, 0.0f, 1.0f,
1.0f, 1.0f, 1.0f, 1.0f,
1.0f, -1.0f, 1.0f, 0.0f,
-1.0f, 1.0f, 0.0f, 1.0f
};
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) {
printf("%s: Please do not place binary in PATH\n", argv[0]);
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) {
resolved_path[i + 1] = 0;
resolved_length = i;
break;
}
}
char* assets_path = (char*)malloc(resolved_length + strlen("assets") + 2);
strcpy(assets_path, resolved_path);
strcpy(assets_path + resolved_length + 1, "assets");
struct stat path_stat;
if (stat(assets_path, &path_stat) == -1 || !S_ISDIR(path_stat.st_mode)) {
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);
@ -60,7 +147,7 @@ int main()
return -1;
}
glfwMakeContextCurrent(window);
glfwSwapInterval(VSYNC);
glfwSwapInterval(vsync ? 1 : 0);
// Initialize GLAD
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
@ -74,6 +161,7 @@ int main()
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);
@ -84,13 +172,93 @@ int main()
glEnable(GL_DEPTH_TEST);
// Create shader
Shader shader("assets/shaders/vertex_shader.glsl", "assets/shaders/fragment_shader.glsl");
// Create shaders
Shader shader("assets/shaders/main_vert.glsl", "assets/shaders/main_frag.glsl");
shader.use();
shader.setFloat("texMultiplier", .25f);
shader.setFloat("texMultiplier", 0.0625f);
// Create texture
Shader waterShader("assets/shaders/water_vert.glsl", "assets/shaders/water_frag.glsl");
waterShader.use();
waterShader.setFloat("texMultiplier", 0.0625f);
Shader billboardShader("assets/shaders/billboard_vert.glsl", "assets/shaders/billboard_frag.glsl");
billboardShader.use();
billboardShader.setFloat("texMultiplier", 0.0625f);
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);
glBindFramebuffer(GL_FRAMEBUFFER, FBO);
glGenTextures(1, &framebufferTexture);
glBindTexture(GL_TEXTURE_2D, framebufferTexture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, windowX, windowY, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, framebufferTexture, 0);
glGenTextures(1, &depthTexture);
glBindTexture(GL_TEXTURE_2D, depthTexture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, windowX, windowY, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depthTexture, 0);
auto fboStatus = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if (fboStatus != GL_FRAMEBUFFER_COMPLETE)
std::cout << "Framebuffer error: " << fboStatus << '\n';
unsigned int rectVAO, rectVBO;
glGenVertexArrays(1, &rectVAO);
glGenBuffers(1, &rectVBO);
glBindVertexArray(rectVAO);
glBindBuffer(GL_ARRAY_BUFFER, rectVBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(rectangleVertices), &rectangleVertices, 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)));
framebufferShader.use();
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
unsigned int texture;
glGenTextures(1, &texture);
glActiveTexture(GL_TEXTURE0);
@ -117,12 +285,38 @@ int main()
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));
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
Planet::planet = new Planet();
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();
@ -149,7 +343,7 @@ int main()
highestFps = fps;
fpsCount++;
std::chrono::steady_clock::time_point currentTimePoint = std::chrono::steady_clock::now();
if (std::chrono::duration_cast<std::chrono::milliseconds>(currentTimePoint - fpsStartTime).count() > 1000)
if (std::chrono::duration_cast<std::chrono::seconds>(currentTimePoint - fpsStartTime).count() >= 1)
{
avgFps = fpsCount;
lowestFps = -1;
@ -158,11 +352,21 @@ int main()
fpsStartTime = currentTimePoint;
}
waterShader.use();
waterShader.setFloat("time", currentFrame);
outlineShader.use();
outlineShader.setFloat("time", currentFrame);
// Input
processInput(window);
// Rendering
glEnable(GL_DEPTH_TEST);
glBindFramebuffer(GL_FRAMEBUFFER, FBO);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture);
// New ImGui frame
ImGui_ImplOpenGL3_NewFrame();
@ -173,25 +377,151 @@ int main()
glm::mat4 view = camera.GetViewMatrix();
glm::mat4 projection;
projection = glm::perspective(glm::radians(camera.Zoom), windowX / windowY, 0.1f, 100.0f);
projection = glm::perspective(glm::radians(camera.Zoom), windowX / windowY, 0.1f, 1000.0f);
shader.use();
unsigned int viewLoc = glGetUniformLocation(shader.ID, "view");
glUniformMatrix4fv(viewLoc, 1, GL_FALSE, glm::value_ptr(view));
unsigned int projectionLoc = glGetUniformLocation(shader.ID, "projection");
glUniformMatrix4fv(projectionLoc, 1, GL_FALSE, glm::value_ptr(projection));
unsigned int modelLoc = glGetUniformLocation(shader.ID, "model");
waterShader.use();
viewLoc = glGetUniformLocation(waterShader.ID, "view");
glUniformMatrix4fv(viewLoc, 1, GL_FALSE, glm::value_ptr(view));
projectionLoc = glGetUniformLocation(waterShader.ID, "projection");
glUniformMatrix4fv(projectionLoc, 1, GL_FALSE, glm::value_ptr(projection));
Planet::planet->Update(camera.Position.x, camera.Position.y, camera.Position.z, modelLoc);
billboardShader.use();
viewLoc = glGetUniformLocation(billboardShader.ID, "view");
glUniformMatrix4fv(viewLoc, 1, GL_FALSE, glm::value_ptr(view));
projectionLoc = glGetUniformLocation(billboardShader.ID, "projection");
glUniformMatrix4fv(projectionLoc, 1, GL_FALSE, glm::value_ptr(projection));
// Draw ImGui UI
ImGui::Begin("Test");
ImGui::Text("FPS: %f (Avg: %f, Min: %f, Max: %f)", fps, avgFps, lowestFps, highestFps);
ImGui::Text("MS: %f", deltaTime * 100.0f);
ImGui::Text("Chunks: %d (%d rendered)", Planet::planet->numChunks, Planet::planet->numChunksRendered);
ImGui::End();
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));
ImGui::Render();
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
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)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));
if (chunk != nullptr)
{
unsigned int blockType = chunk->GetBlockAtPos(
localBlockX,
localBlockY,
localBlockZ);
if (Blocks::blocks[blockType].blockType == Block::LIQUID)
{
framebufferShader.setBool("underwater", true);
}
else
{
framebufferShader.setBool("underwater", false);
}
}
// Post Processing
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glBindVertexArray(rectVAO);
glDisable(GL_DEPTH_TEST);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, framebufferTexture);
glActiveTexture(GL_TEXTURE1);
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: %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.c_str());
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);
@ -200,6 +530,8 @@ int main()
//std::cout << camera.Position.x << ", " << camera.Position.y << ", " << camera.Position.z << '\n';
}
delete Planet::planet;
ImGui_ImplOpenGL3_Shutdown();
ImGui_ImplGlfw_Shutdown();
ImGui::DestroyContext();
@ -212,10 +544,18 @@ void framebufferSizeCallback(GLFWwindow* window, int width, int height)
windowX = width;
windowY = height;
glViewport(0, 0, width, 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);
}
void processInput(GLFWwindow* window)
{
// Pause
if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
{
if (escapeDown)
@ -230,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)
@ -249,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, bool transparent, bool billboard)
: transparent(transparent), billboard(billboard)
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, bool transparent, bool
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, bool transparent, bool billboard)
: transparent(transparent), billboard(billboard)
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,16 +1,28 @@
#pragma once
#include <string>
struct Block
{
public:
enum BLOCK_TYPE
{
SOLID,
TRANSPARENT,
LEAVES,
BILLBOARD,
LIQUID
};
char topMinX, topMinY, topMaxX, topMaxY;
char bottomMinX, bottomMinY, bottomMaxX, bottomMaxY;
char sideMinX, sideMinY, sideMaxX, sideMaxY;
bool transparent;
bool billboard;
BLOCK_TYPE blockType;
std::string blockName;
Block(char minX, char minY, char maxX, char maxY, bool transparent = false, bool billboard = false);
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, bool transparent = false, bool billboard = false);
char sideMinX, char sideMinY, char sideMaxX, char sideMaxY, BLOCK_TYPE blockType, std::string blockName);
};

View File

@ -1,33 +1,36 @@
#pragma once
#include <vector>
#include <array>
#include "Block.h"
namespace Blocks
{
const std::vector<Block> blocks{
Block(0, 0, 0, 0, true), // Air block
Block(0, 0, 1, 1), // 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
Block(1, 1, 2, 2, // Grass block
0, 0, 1, 1,
1, 0, 2, 1),
1, 0, 2, 1, Block::SOLID, "Grass Block"),
Block(0, 1, 1, 2), // Stone block
Block(0, 1, 1, 2, Block::SOLID, "Stone"), // Stone block
Block(2, 1, 3, 2, // Log
Block(2, 1, 3, 2, // Log
2, 1, 3, 2,
2, 0, 3, 1),
2, 0, 3, 1, Block::SOLID, "Log"),
Block(0, 2, 1, 3, true), // Leaves
Block(1, 2, 2, 3, true, true), // Grass
Block(3, 0, 4, 1, true, true), // Tall Grass Bottom
Block(3, 1, 4, 2, true, true), // Tall Grass Top
Block(0, 3, 1, 4, true, true), // Poppy
Block(2, 2, 3, 3, true, true), // White Tulip
Block(3, 2, 4, 3, true, true), // Pink Tulip
Block(1, 3, 2, 4, true, true), // Orange Tulip
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 Bottom"), // 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
@ -45,5 +48,7 @@ namespace Blocks
WHITE_TULIP = 10,
PINK_TULIP = 11,
ORANGE_TULIP = 12,
WATER = 13,
SAND = 14,
};
}

View File

@ -0,0 +1,15 @@
add_executable(scuffed_mc
Application.cpp Chunk.cpp Shader.cpp
Block.cpp NoiseSettings.cpp SurfaceFeature.cpp
ChunkData.cpp ChunkPos.cpp Physics.cpp
Camera.cpp Planet.cpp WorldGen.cpp ../vendor/glad.c
)
if(LINUX)
add_compile_definitions(LINUX)
endif()
# make sure the program runs in the right place from visual studio
set_target_properties(scuffed_mc PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}/bin")
target_link_libraries(scuffed_mc imgui $<IF:$<PLATFORM_ID:Windows>,glfw3,glfw>)

View File

@ -38,9 +38,9 @@ void Camera::ProcessKeyboard(Camera_Movement direction, float deltaTime)
if (direction == RIGHT)
Position += Right * velocity;
if (direction == UP)
Position += Up * velocity;
Position += (absoluteVerticalMovement ? glm::vec3(0, 1, 0) : Up) * velocity;
if (direction == DOWN)
Position -= Up * 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

@ -2,23 +2,21 @@
#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include <iostream>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <iostream>
#include "Planet.h"
#include "Blocks.h"
#include "WorldGen.h"
Chunk::Chunk(unsigned int chunkSize, glm::vec3 chunkPos)
Chunk::Chunk(ChunkPos chunkPos, Shader* shader, Shader* waterShader)
: chunkPos(chunkPos)
{
this->chunkSize = chunkSize;
this->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()
@ -26,93 +24,86 @@ Chunk::~Chunk()
if (chunkThread.joinable())
chunkThread.join();
glDeleteBuffers(1, &vbo);
glDeleteBuffers(1, &ebo);
glDeleteVertexArrays(1, &vertexArrayObject);
glDeleteBuffers(1, &mainVBO);
glDeleteBuffers(1, &mainEBO);
glDeleteVertexArrays(1, &mainVAO);
glDeleteBuffers(1, &waterVBO);
glDeleteBuffers(1, &waterEBO);
glDeleteVertexArrays(1, &waterVAO);
glDeleteBuffers(1, &billboardVBO);
glDeleteBuffers(1, &billboardEBO);
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;
for (char x = 0; x < chunkSize; x++)
unsigned int currentLiquidVertex = 0;
unsigned int currentBillboardVertex = 0;
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)];
if (block->billboard)
int topBlock;
if (y < CHUNK_SIZE - 1)
{
vertices.push_back(Vertex(x + .85355f, y + 0, z + .85355f, block->sideMinX, block->sideMinY, 6));
vertices.push_back(Vertex(x + .14645f, y + 0, z + .14645f, block->sideMaxX, block->sideMinY, 6));
vertices.push_back(Vertex(x + .85355f, y + 1, z + .85355f, block->sideMinX, block->sideMaxY, 6));
vertices.push_back(Vertex(x + .14645f, y + 1, z + .14645f, block->sideMaxX, block->sideMaxY, 6));
topBlock = chunkData->GetBlock(x, y + 1, z);
}
else
{
int blockIndex = x * CHUNK_SIZE * CHUNK_SIZE + z * CHUNK_SIZE + 0;
topBlock = upData->GetBlock(x, 0, z);
}
indices.push_back(currentVertex + 0);
indices.push_back(currentVertex + 3);
indices.push_back(currentVertex + 1);
indices.push_back(currentVertex + 0);
indices.push_back(currentVertex + 2);
indices.push_back(currentVertex + 3);
currentVertex += 4;
const Block* topBlockType = &Blocks::blocks[topBlock];
char waterTopValue = topBlockType->blockType == Block::TRANSPARENT ? 1 : 0;
vertices.push_back(Vertex(x + .14645f, y + 0, z + .14645f, block->sideMinX, block->sideMinY, 6));
vertices.push_back(Vertex(x + .85355f, y + 0, z + .85355f, block->sideMaxX, block->sideMinY, 6));
vertices.push_back(Vertex(x + .14645f, y + 1, z + .14645f, block->sideMinX, block->sideMaxY, 6));
vertices.push_back(Vertex(x + .85355f, y + 1, z + .85355f, block->sideMaxX, block->sideMaxY, 6));
if (block->blockType == Block::BILLBOARD)
{
billboardVertices.push_back(BillboardVertex(x + .85355f, y + 0, z + .85355f, block->sideMinX, block->sideMinY));
billboardVertices.push_back(BillboardVertex(x + .14645f, y + 0, z + .14645f, block->sideMaxX, block->sideMinY));
billboardVertices.push_back(BillboardVertex(x + .85355f, y + 1, z + .85355f, block->sideMinX, block->sideMaxY));
billboardVertices.push_back(BillboardVertex(x + .14645f, y + 1, z + .14645f, block->sideMaxX, block->sideMaxY));
indices.push_back(currentVertex + 0);
indices.push_back(currentVertex + 3);
indices.push_back(currentVertex + 1);
indices.push_back(currentVertex + 0);
indices.push_back(currentVertex + 2);
indices.push_back(currentVertex + 3);
currentVertex += 4;
billboardIndices.push_back(currentBillboardVertex + 0);
billboardIndices.push_back(currentBillboardVertex + 3);
billboardIndices.push_back(currentBillboardVertex + 1);
billboardIndices.push_back(currentBillboardVertex + 0);
billboardIndices.push_back(currentBillboardVertex + 2);
billboardIndices.push_back(currentBillboardVertex + 3);
currentBillboardVertex += 4;
vertices.push_back(Vertex(x + .14645f, y + 0, z + .85355f, block->sideMinX, block->sideMinY, 6));
vertices.push_back(Vertex(x + .85355f, y + 0, z + .14645f, block->sideMaxX, block->sideMinY, 6));
vertices.push_back(Vertex(x + .14645f, y + 1, z + .85355f, block->sideMinX, block->sideMaxY, 6));
vertices.push_back(Vertex(x + .85355f, y + 1, z + .14645f, block->sideMaxX, block->sideMaxY, 6));
billboardVertices.push_back(BillboardVertex(x + .14645f, y + 0, z + .85355f, block->sideMinX, block->sideMinY));
billboardVertices.push_back(BillboardVertex(x + .85355f, y + 0, z + .14645f, block->sideMaxX, block->sideMinY));
billboardVertices.push_back(BillboardVertex(x + .14645f, y + 1, z + .85355f, block->sideMinX, block->sideMaxY));
billboardVertices.push_back(BillboardVertex(x + .85355f, y + 1, z + .14645f, block->sideMaxX, block->sideMaxY));
indices.push_back(currentVertex + 0);
indices.push_back(currentVertex + 3);
indices.push_back(currentVertex + 1);
indices.push_back(currentVertex + 0);
indices.push_back(currentVertex + 2);
indices.push_back(currentVertex + 3);
currentVertex += 4;
vertices.push_back(Vertex(x + .85355f, y + 0, z + .14645f, block->sideMinX, block->sideMinY, 6));
vertices.push_back(Vertex(x + .14645f, y + 0, z + .85355f, block->sideMaxX, block->sideMinY, 6));
vertices.push_back(Vertex(x + .85355f, y + 1, z + .14645f, block->sideMinX, block->sideMaxY, 6));
vertices.push_back(Vertex(x + .14645f, y + 1, z + .85355f, block->sideMaxX, block->sideMaxY, 6));
indices.push_back(currentVertex + 0);
indices.push_back(currentVertex + 3);
indices.push_back(currentVertex + 1);
indices.push_back(currentVertex + 0);
indices.push_back(currentVertex + 2);
indices.push_back(currentVertex + 3);
currentVertex += 4;
billboardIndices.push_back(currentBillboardVertex + 0);
billboardIndices.push_back(currentBillboardVertex + 3);
billboardIndices.push_back(currentBillboardVertex + 1);
billboardIndices.push_back(currentBillboardVertex + 0);
billboardIndices.push_back(currentBillboardVertex + 2);
billboardIndices.push_back(currentBillboardVertex + 3);
currentBillboardVertex += 4;
}
else
{
@ -121,64 +112,102 @@ 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];
if (northBlockType->transparent)
if (northBlockType->blockType == Block::LEAVES
|| northBlockType->blockType == Block::TRANSPARENT
|| northBlockType->blockType == Block::BILLBOARD
|| (northBlockType->blockType == Block::LIQUID && block->blockType != Block::LIQUID))
{
vertices.push_back(Vertex(x + 1, y + 0, z + 0, block->sideMinX, block->sideMinY, 0));
vertices.push_back(Vertex(x + 0, y + 0, z + 0, block->sideMaxX, block->sideMinY, 0));
vertices.push_back(Vertex(x + 1, y + 1, z + 0, block->sideMinX, block->sideMaxY, 0));
vertices.push_back(Vertex(x + 0, y + 1, z + 0, block->sideMaxX, block->sideMaxY, 0));
if (block->blockType == Block::LIQUID)
{
waterVertices.push_back(WaterVertex(x + 1, y + 0, z + 0, block->sideMinX, block->sideMinY, 0, 0));
waterVertices.push_back(WaterVertex(x + 0, y + 0, z + 0, block->sideMaxX, block->sideMinY, 0, 0));
waterVertices.push_back(WaterVertex(x + 1, y + 1, z + 0, block->sideMinX, block->sideMaxY, 0, waterTopValue));
waterVertices.push_back(WaterVertex(x + 0, y + 1, z + 0, block->sideMaxX, block->sideMaxY, 0, waterTopValue));
indices.push_back(currentVertex + 0);
indices.push_back(currentVertex + 3);
indices.push_back(currentVertex + 1);
indices.push_back(currentVertex + 0);
indices.push_back(currentVertex + 2);
indices.push_back(currentVertex + 3);
currentVertex += 4;
waterIndices.push_back(currentLiquidVertex + 0);
waterIndices.push_back(currentLiquidVertex + 3);
waterIndices.push_back(currentLiquidVertex + 1);
waterIndices.push_back(currentLiquidVertex + 0);
waterIndices.push_back(currentLiquidVertex + 2);
waterIndices.push_back(currentLiquidVertex + 3);
currentLiquidVertex += 4;
}
else
{
mainVertices.push_back(Vertex(x + 1, y + 0, z + 0, block->sideMinX, block->sideMinY, 0));
mainVertices.push_back(Vertex(x + 0, y + 0, z + 0, block->sideMaxX, block->sideMinY, 0));
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));
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;
}
}
}
// 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];
if (southBlockType->transparent)
if (southBlockType->blockType == Block::LEAVES
|| southBlockType->blockType == Block::TRANSPARENT
|| southBlockType->blockType == Block::BILLBOARD
|| (southBlockType->blockType == Block::LIQUID && block->blockType != Block::LIQUID))
{
vertices.push_back(Vertex(x + 0, y + 0, z + 1, block->sideMinX, block->sideMinY, 1));
vertices.push_back(Vertex(x + 1, y + 0, z + 1, block->sideMaxX, block->sideMinY, 1));
vertices.push_back(Vertex(x + 0, y + 1, z + 1, block->sideMinX, block->sideMaxY, 1));
vertices.push_back(Vertex(x + 1, y + 1, z + 1, block->sideMaxX, block->sideMaxY, 1));
if (block->blockType == Block::LIQUID)
{
waterVertices.push_back(WaterVertex(x + 0, y + 0, z + 1, block->sideMinX, block->sideMinY, 1, 0));
waterVertices.push_back(WaterVertex(x + 1, y + 0, z + 1, block->sideMaxX, block->sideMinY, 1, 0));
waterVertices.push_back(WaterVertex(x + 0, y + 1, z + 1, block->sideMinX, block->sideMaxY, 1, waterTopValue));
waterVertices.push_back(WaterVertex(x + 1, y + 1, z + 1, block->sideMaxX, block->sideMaxY, 1, waterTopValue));
indices.push_back(currentVertex + 0);
indices.push_back(currentVertex + 3);
indices.push_back(currentVertex + 1);
indices.push_back(currentVertex + 0);
indices.push_back(currentVertex + 2);
indices.push_back(currentVertex + 3);
currentVertex += 4;
waterIndices.push_back(currentLiquidVertex + 0);
waterIndices.push_back(currentLiquidVertex + 3);
waterIndices.push_back(currentLiquidVertex + 1);
waterIndices.push_back(currentLiquidVertex + 0);
waterIndices.push_back(currentLiquidVertex + 2);
waterIndices.push_back(currentLiquidVertex + 3);
currentLiquidVertex += 4;
}
else
{
mainVertices.push_back(Vertex(x + 0, y + 0, z + 1, block->sideMinX, block->sideMinY, 1));
mainVertices.push_back(Vertex(x + 1, y + 0, z + 1, block->sideMaxX, block->sideMinY, 1));
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));
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;
}
}
}
@ -187,64 +216,102 @@ 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];
if (westBlockType->transparent)
if (westBlockType->blockType == Block::LEAVES
|| westBlockType->blockType == Block::TRANSPARENT
|| westBlockType->blockType == Block::BILLBOARD
|| (westBlockType->blockType == Block::LIQUID && block->blockType != Block::LIQUID))
{
vertices.push_back(Vertex(x + 0, y + 0, z + 0, block->sideMinX, block->sideMinY, 2));
vertices.push_back(Vertex(x + 0, y + 0, z + 1, block->sideMaxX, block->sideMinY, 2));
vertices.push_back(Vertex(x + 0, y + 1, z + 0, block->sideMinX, block->sideMaxY, 2));
vertices.push_back(Vertex(x + 0, y + 1, z + 1, block->sideMaxX, block->sideMaxY, 2));
if (block->blockType == Block::LIQUID)
{
waterVertices.push_back(WaterVertex(x + 0, y + 0, z + 0, block->sideMinX, block->sideMinY, 2, 0));
waterVertices.push_back(WaterVertex(x + 0, y + 0, z + 1, block->sideMaxX, block->sideMinY, 2, 0));
waterVertices.push_back(WaterVertex(x + 0, y + 1, z + 0, block->sideMinX, block->sideMaxY, 2, waterTopValue));
waterVertices.push_back(WaterVertex(x + 0, y + 1, z + 1, block->sideMaxX, block->sideMaxY, 2, waterTopValue));
indices.push_back(currentVertex + 0);
indices.push_back(currentVertex + 3);
indices.push_back(currentVertex + 1);
indices.push_back(currentVertex + 0);
indices.push_back(currentVertex + 2);
indices.push_back(currentVertex + 3);
currentVertex += 4;
waterIndices.push_back(currentLiquidVertex + 0);
waterIndices.push_back(currentLiquidVertex + 3);
waterIndices.push_back(currentLiquidVertex + 1);
waterIndices.push_back(currentLiquidVertex + 0);
waterIndices.push_back(currentLiquidVertex + 2);
waterIndices.push_back(currentLiquidVertex + 3);
currentLiquidVertex += 4;
}
else
{
mainVertices.push_back(Vertex(x + 0, y + 0, z + 0, block->sideMinX, block->sideMinY, 2));
mainVertices.push_back(Vertex(x + 0, y + 0, z + 1, block->sideMaxX, block->sideMinY, 2));
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));
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;
}
}
}
// 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];
if (eastBlockType->transparent)
if (eastBlockType->blockType == Block::LEAVES
|| eastBlockType->blockType == Block::TRANSPARENT
|| eastBlockType->blockType == Block::BILLBOARD
|| (eastBlockType->blockType == Block::LIQUID && block->blockType != Block::LIQUID))
{
vertices.push_back(Vertex(x + 1, y + 0, z + 1, block->sideMinX, block->sideMinY, 3));
vertices.push_back(Vertex(x + 1, y + 0, z + 0, block->sideMaxX, block->sideMinY, 3));
vertices.push_back(Vertex(x + 1, y + 1, z + 1, block->sideMinX, block->sideMaxY, 3));
vertices.push_back(Vertex(x + 1, y + 1, z + 0, block->sideMaxX, block->sideMaxY, 3));
if (block->blockType == Block::LIQUID)
{
waterVertices.push_back(WaterVertex(x + 1, y + 0, z + 1, block->sideMinX, block->sideMinY, 3, 0));
waterVertices.push_back(WaterVertex(x + 1, y + 0, z + 0, block->sideMaxX, block->sideMinY, 3, 0));
waterVertices.push_back(WaterVertex(x + 1, y + 1, z + 1, block->sideMinX, block->sideMaxY, 3, waterTopValue));
waterVertices.push_back(WaterVertex(x + 1, y + 1, z + 0, block->sideMaxX, block->sideMaxY, 3, waterTopValue));
indices.push_back(currentVertex + 0);
indices.push_back(currentVertex + 3);
indices.push_back(currentVertex + 1);
indices.push_back(currentVertex + 0);
indices.push_back(currentVertex + 2);
indices.push_back(currentVertex + 3);
currentVertex += 4;
waterIndices.push_back(currentLiquidVertex + 0);
waterIndices.push_back(currentLiquidVertex + 3);
waterIndices.push_back(currentLiquidVertex + 1);
waterIndices.push_back(currentLiquidVertex + 0);
waterIndices.push_back(currentLiquidVertex + 2);
waterIndices.push_back(currentLiquidVertex + 3);
currentLiquidVertex += 4;
}
else
{
mainVertices.push_back(Vertex(x + 1, y + 0, z + 1, block->sideMinX, block->sideMinY, 3));
mainVertices.push_back(Vertex(x + 1, y + 0, z + 0, block->sideMaxX, block->sideMinY, 3));
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));
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;
}
}
}
@ -253,63 +320,103 @@ 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];
if (bottomBlockType->transparent)
if (bottomBlockType->blockType == Block::LEAVES
|| bottomBlockType->blockType == Block::TRANSPARENT
|| bottomBlockType->blockType == Block::BILLBOARD
|| (bottomBlockType->blockType == Block::LIQUID && block->blockType != Block::LIQUID))
{
vertices.push_back(Vertex(x + 1, y + 0, z + 1, block->bottomMinX, block->bottomMinY, 4));
vertices.push_back(Vertex(x + 0, y + 0, z + 1, block->bottomMaxX, block->bottomMinY, 4));
vertices.push_back(Vertex(x + 1, y + 0, z + 0, block->bottomMinX, block->bottomMaxY, 4));
vertices.push_back(Vertex(x + 0, y + 0, z + 0, block->bottomMaxX, block->bottomMaxY, 4));
if (block->blockType == Block::LIQUID)
{
waterVertices.push_back(WaterVertex(x + 1, y + 0, z + 1, block->bottomMinX, block->bottomMinY, 4, 0));
waterVertices.push_back(WaterVertex(x + 0, y + 0, z + 1, block->bottomMaxX, block->bottomMinY, 4, 0));
waterVertices.push_back(WaterVertex(x + 1, y + 0, z + 0, block->bottomMinX, block->bottomMaxY, 4, 0));
waterVertices.push_back(WaterVertex(x + 0, y + 0, z + 0, block->bottomMaxX, block->bottomMaxY, 4, 0));
indices.push_back(currentVertex + 0);
indices.push_back(currentVertex + 3);
indices.push_back(currentVertex + 1);
indices.push_back(currentVertex + 0);
indices.push_back(currentVertex + 2);
indices.push_back(currentVertex + 3);
currentVertex += 4;
waterIndices.push_back(currentLiquidVertex + 0);
waterIndices.push_back(currentLiquidVertex + 3);
waterIndices.push_back(currentLiquidVertex + 1);
waterIndices.push_back(currentLiquidVertex + 0);
waterIndices.push_back(currentLiquidVertex + 2);
waterIndices.push_back(currentLiquidVertex + 3);
currentLiquidVertex += 4;
}
else
{
mainVertices.push_back(Vertex(x + 1, y + 0, z + 1, block->bottomMinX, block->bottomMinY, 4));
mainVertices.push_back(Vertex(x + 0, y + 0, z + 1, block->bottomMaxX, block->bottomMinY, 4));
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));
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;
}
}
}
// Top
{
int topBlock;
if (y < chunkSize - 1)
if (block->blockType == Block::LIQUID)
{
int blockIndex = x * chunkSize * chunkSize + z * chunkSize + (y + 1);
topBlock = chunkData[blockIndex];
if (topBlockType->blockType != Block::LIQUID)
{
waterVertices.push_back(WaterVertex(x + 0, y + 1, z + 1, block->topMinX, block->topMinY, 5, 1));
waterVertices.push_back(WaterVertex(x + 1, y + 1, z + 1, block->topMaxX, block->topMinY, 5, 1));
waterVertices.push_back(WaterVertex(x + 0, y + 1, z + 0, block->topMinX, block->topMaxY, 5, 1));
waterVertices.push_back(WaterVertex(x + 1, y + 1, z + 0, block->topMaxX, block->topMaxY, 5, 1));
waterIndices.push_back(currentLiquidVertex + 0);
waterIndices.push_back(currentLiquidVertex + 3);
waterIndices.push_back(currentLiquidVertex + 1);
waterIndices.push_back(currentLiquidVertex + 0);
waterIndices.push_back(currentLiquidVertex + 2);
waterIndices.push_back(currentLiquidVertex + 3);
currentLiquidVertex += 4;
waterVertices.push_back(WaterVertex(x + 1, y + 1, z + 1, block->topMinX, block->topMinY, 5, 1));
waterVertices.push_back(WaterVertex(x + 0, y + 1, z + 1, block->topMaxX, block->topMinY, 5, 1));
waterVertices.push_back(WaterVertex(x + 1, y + 1, z + 0, block->topMinX, block->topMaxY, 5, 1));
waterVertices.push_back(WaterVertex(x + 0, y + 1, z + 0, block->topMaxX, block->topMaxY, 5, 1));
waterIndices.push_back(currentLiquidVertex + 0);
waterIndices.push_back(currentLiquidVertex + 3);
waterIndices.push_back(currentLiquidVertex + 1);
waterIndices.push_back(currentLiquidVertex + 0);
waterIndices.push_back(currentLiquidVertex + 2);
waterIndices.push_back(currentLiquidVertex + 3);
currentLiquidVertex += 4;
}
}
else
else if (topBlockType->blockType == Block::LEAVES
|| topBlockType->blockType == Block::TRANSPARENT
|| topBlockType->blockType == Block::BILLBOARD
|| topBlockType->blockType == Block::LIQUID)
{
int blockIndex = x * chunkSize * chunkSize + z * chunkSize + 0;
topBlock = upData[blockIndex];
}
mainVertices.push_back(Vertex(x + 0, y + 1, z + 1, block->topMinX, block->topMinY, 5));
mainVertices.push_back(Vertex(x + 1, y + 1, z + 1, block->topMaxX, block->topMinY, 5));
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));
const Block* topBlockType = &Blocks::blocks[topBlock];
if (topBlockType->transparent)
{
vertices.push_back(Vertex(x + 0, y + 1, z + 1, block->topMinX, block->topMinY, 5));
vertices.push_back(Vertex(x + 1, y + 1, z + 1, block->topMaxX, block->topMinY, 5));
vertices.push_back(Vertex(x + 0, y + 1, z + 0, block->topMinX, block->topMaxY, 5));
vertices.push_back(Vertex(x + 1, y + 1, z + 0, block->topMaxX, block->topMaxY, 5));
indices.push_back(currentVertex + 0);
indices.push_back(currentVertex + 3);
indices.push_back(currentVertex + 1);
indices.push_back(currentVertex + 0);
indices.push_back(currentVertex + 2);
indices.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;
}
}
@ -325,31 +432,78 @@ void Chunk::GenerateChunk()
//std::cout << "Generated: " << generated << '\n';
}
void Chunk::Render(unsigned int modelLoc)
void Chunk::Render(Shader* mainShader, Shader* billboardShader)
{
if (!ready)
{
if (generated)
{
numTriangles = indices.size();
// Solid
numTrianglesMain = mainIndices.size();
glGenVertexArrays(1, &vertexArrayObject);
glBindVertexArray(vertexArrayObject);
glGenVertexArrays(1, &mainVAO);
glGenBuffers(1, &mainVBO);
glGenBuffers(1, &mainEBO);
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(Vertex), vertices.data(), GL_STATIC_DRAW);
glBindVertexArray(mainVAO);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, posX));
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);
glVertexAttribPointer(0, 3, GL_BYTE, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, posX));
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, 2, GL_BYTE, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, texGridX));
glEnableVertexAttribArray(1);
glVertexAttribIPointer(2, 1, GL_BYTE, sizeof(Vertex), (void*)offsetof(Vertex, direction));
glEnableVertexAttribArray(2);
glGenBuffers(1, &ebo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(unsigned int), indices.data(), GL_STATIC_DRAW);
// Water
numTrianglesWater = waterIndices.size();
glGenVertexArrays(1, &waterVAO);
glGenBuffers(1, &waterVBO);
glGenBuffers(1, &waterEBO);
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);
glVertexAttribPointer(0, 3, GL_BYTE, GL_FALSE, sizeof(WaterVertex), (void*)offsetof(WaterVertex, posX));
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, 2, GL_BYTE, GL_FALSE, sizeof(WaterVertex), (void*)offsetof(WaterVertex, texGridX));
glEnableVertexAttribArray(1);
glVertexAttribIPointer(2, 1, GL_BYTE, sizeof(WaterVertex), (void*)offsetof(WaterVertex, direction));
glEnableVertexAttribArray(2);
glVertexAttribIPointer(3, 1, GL_BYTE, sizeof(WaterVertex), (void*)offsetof(WaterVertex, top));
glEnableVertexAttribArray(3);
ready = true;
// Billboard
numTrianglesBillboard = billboardIndices.size();
glGenVertexArrays(1, &billboardVAO);
glGenBuffers(1, &billboardVBO);
glGenBuffers(1, &billboardEBO);
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);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(BillboardVertex), (void*)offsetof(BillboardVertex, posX));
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, 2, GL_BYTE, GL_FALSE, sizeof(BillboardVertex), (void*)offsetof(BillboardVertex, texGridX));
glEnableVertexAttribArray(1);
ready = true;
}
@ -359,11 +513,171 @@ void Chunk::Render(unsigned int modelLoc)
//std::cout << "Rendering chunk " << chunkPos.x << ", " << chunkPos.y << ", " << chunkPos.z << '\n'
// << "Chunk VAO: " << vertexArrayObject << '\n' << "Triangles: " << numTriangles << '\n';
glBindVertexArray(vertexArrayObject);
// Calculate model matrix
glm::mat4 model = glm::mat4(1.0f);
model = glm::translate(model, worldPos);
// Render main mesh
mainShader->use();
modelLoc = glGetUniformLocation(mainShader->ID, "model");
glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model));
glBindVertexArray(mainVAO);
glDrawElements(GL_TRIANGLES, numTrianglesMain, GL_UNSIGNED_INT, 0);
// Render billboard mesh
billboardShader->use();
modelLoc = glGetUniformLocation(billboardShader->ID, "model");
glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model));
glDisable(GL_CULL_FACE);
glBindVertexArray(billboardVAO);
glDrawElements(GL_TRIANGLES, numTrianglesBillboard, GL_UNSIGNED_INT, 0);
glEnable(GL_CULL_FACE);
}
void Chunk::RenderWater(Shader* shader)
{
if (!ready)
return;
//std::cout << "Rendering chunk " << chunkPos.x << ", " << chunkPos.y << ", " << chunkPos.z << '\n'
// << "Chunk VAO: " << vertexArrayObject << '\n' << "Triangles: " << numTriangles << '\n';
modelLoc = glGetUniformLocation(shader->ID, "model");
glBindVertexArray(waterVAO);
glm::mat4 model = glm::mat4(1.0f);
model = glm::translate(model, worldPos);
glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model));
glDrawElements(GL_TRIANGLES, numTriangles, GL_UNSIGNED_INT, 0);
glDrawElements(GL_TRIANGLES, numTrianglesWater, GL_UNSIGNED_INT, 0);
}
uint16_t Chunk::GetBlockAtPos(int x, int y, int z)
{
if (!ready)
return 0;
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

@ -4,48 +4,49 @@
#include <thread>
#include <glm/glm.hpp>
struct Vertex
{
float posX, posY, posZ;
char texGridX, texGridY;
char direction;
Vertex(float _posX, float _posY, float _posZ, char _texGridX, char _texGridY, char _direction)
{
posX = _posX;
posY = _posY;
posZ = _posZ;
texGridX = _texGridX;
texGridY = _texGridY;
direction = _direction;
}
};
#include "Shader.h"
#include "Vertex.h"
#include "ChunkPos.h"
#include "ChunkData.h"
class Chunk
{
public:
Chunk(unsigned int chunkSize, glm::vec3 chunkPos);
Chunk(ChunkPos chunkPos, Shader* shader, Shader* waterShader);
~Chunk();
void GenerateChunk();
void Render(unsigned int modelLoc);
void GenerateChunkMesh();
void Render(Shader* mainShader, Shader* billboardShader);
void RenderWater(Shader* shader);
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 vertexArrayObject;
unsigned int vbo, ebo;
unsigned int chunkSize;
unsigned int numTriangles;
glm::vec3 worldPos;
std::thread chunkThread;
std::vector<Vertex> vertices;
std::vector<unsigned int> indices;
std::vector<Vertex> mainVertices;
std::vector<unsigned int> mainIndices;
std::vector<WaterVertex> waterVertices;
std::vector<unsigned int> waterIndices;
std::vector<BillboardVertex> billboardVertices;
std::vector<unsigned int> billboardIndices;
unsigned int mainVAO, waterVAO, billboardVAO;
unsigned int mainVBO, mainEBO, waterVBO, waterEBO, billboardVBO, billboardEBO;
unsigned int numTrianglesMain, numTrianglesWater, numTrianglesBillboard;
unsigned int modelLoc;
};

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

@ -1,167 +1,461 @@
#include "Planet.h"
#include <iostream>
#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include "WorldGen.h"
Planet* Planet::planet = nullptr;
// Public
Planet::Planet()
{
//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())
{
return std::vector<unsigned int>{};
//return GenerateChunkData(chunkX, chunkY, chunkZ);
}
else
{
return std::vector<unsigned int>{};
//return chunks.at(chunkTuple).chunkData;
}
}
void Planet::Update(float camX, float camY, float camZ, unsigned int modelLoc)
{
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;
// Check if camera moved to new chunk
if (camChunkX != lastCamX || camChunkY != lastCamY || camChunkZ != lastCamZ)
{
// Player moved chunks, start new chunk queue
lastCamX = camChunkX;
lastCamY = camChunkY;
lastCamZ = camChunkZ;
// Current chunk
chunkQueue = {};
if (chunks.find({ camChunkX, camChunkY, camChunkZ }) == chunks.end())
chunkQueue.push({ camChunkX, camChunkY, camChunkZ });
for (int r = 0; r < renderDistance; r++)
{
// Add middle chunks
for (int y = 0; y <= renderHeight; y++)
{
chunkQueue.push({ camChunkX, camChunkY + y, camChunkZ + r });
chunkQueue.push({ camChunkX + r, camChunkY + y, camChunkZ });
chunkQueue.push({ camChunkX, camChunkY + y, camChunkZ - r });
chunkQueue.push({ camChunkX - r, camChunkY + y, camChunkZ });
if (y > 0)
{
chunkQueue.push({ camChunkX, camChunkY - y, camChunkZ + r });
chunkQueue.push({ camChunkX + r, camChunkY - y, camChunkZ });
chunkQueue.push({ camChunkX, camChunkY - y, camChunkZ - r });
chunkQueue.push({ camChunkX - r, camChunkY - y, camChunkZ });
}
}
// Add edges
for (int e = 1; e < r; e++)
{
for (int y = 0; y <= renderHeight; y++)
{
chunkQueue.push({ camChunkX + e, camChunkY + y, camChunkZ + r });
chunkQueue.push({ camChunkX - e, camChunkY + y, camChunkZ + r });
chunkQueue.push({ camChunkX + r, camChunkY + y, camChunkZ + e });
chunkQueue.push({ camChunkX + r, camChunkY + y, camChunkZ - e });
chunkQueue.push({ camChunkX + e, camChunkY + y, camChunkZ - r });
chunkQueue.push({ camChunkX - e, camChunkY + y, camChunkZ - r });
chunkQueue.push({ camChunkX - r, camChunkY + y, camChunkZ + e });
chunkQueue.push({ camChunkX - r, camChunkY + y, camChunkZ - e });
if (y > 0)
{
chunkQueue.push({ camChunkX + e, camChunkY - y, camChunkZ + r });
chunkQueue.push({ camChunkX - e, camChunkY - y, camChunkZ + r });
chunkQueue.push({ camChunkX + r, camChunkY - y, camChunkZ + e });
chunkQueue.push({ camChunkX + r, camChunkY - y, camChunkZ - e });
chunkQueue.push({ camChunkX + e, camChunkY - y, camChunkZ - r });
chunkQueue.push({ camChunkX - e, camChunkY - y, camChunkZ - r });
chunkQueue.push({ camChunkX - r, camChunkY - y, camChunkZ + e });
chunkQueue.push({ camChunkX - r, camChunkY - y, camChunkZ - e });
}
}
}
// Add corners
for (int y = 0; y <= renderHeight; y++)
{
chunkQueue.push({ camChunkX + r, camChunkY + y, camChunkZ + r });
chunkQueue.push({ camChunkX + r, camChunkY + y, camChunkZ - r });
chunkQueue.push({ camChunkX - r, camChunkY + y, camChunkZ + r });
chunkQueue.push({ camChunkX - r, camChunkY + y, camChunkZ - r });
if (y > 0)
{
chunkQueue.push({ camChunkX + r, camChunkY - y, camChunkZ + r });
chunkQueue.push({ camChunkX + r, camChunkY - y, camChunkZ - r });
chunkQueue.push({ camChunkX - r, camChunkY - y, camChunkZ + r });
chunkQueue.push({ camChunkX - r, camChunkY - y, camChunkZ - r });
}
}
}
}
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
);
}
}
glDisable(GL_BLEND);
chunksLoading = 0;
numChunks = 0;
numChunksRendered = 0;
chunkMutex.lock();
for (auto it = chunks.begin(); it != chunks.end(); )
{
numChunks++;
if (!it->second.ready)
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 ||
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->second.~Chunk();
// 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
{
numChunksRendered++;
it->second.Render(modelLoc);
(*it->second).Render(solidShader, billboardShader);
++it;
}
}
glEnable(GL_BLEND);
waterShader->use();
for (auto it = chunks.begin(); it != chunks.end(); )
{
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)
{
// Player moved chunks, start new chunk queue
lastCamX = camChunkX;
lastCamY = camChunkY;
lastCamZ = camChunkZ;
// Current chunk
chunkMutex.lock();
chunkQueue = {};
if (chunks.find({ camChunkX, camChunkY, camChunkZ }) == chunks.end())
chunkQueue.push({ camChunkX, camChunkY, camChunkZ });
for (int r = 0; r < renderDistance; r++)
{
// Add middle chunks
for (int y = 0; y <= renderHeight; y++)
{
chunkQueue.push({ camChunkX, camChunkY + y, camChunkZ + r });
chunkQueue.push({ camChunkX + r, camChunkY + y, camChunkZ });
chunkQueue.push({ camChunkX, camChunkY + y, camChunkZ - r });
chunkQueue.push({ camChunkX - r, camChunkY + y, camChunkZ });
if (y > 0)
{
chunkQueue.push({ camChunkX, camChunkY - y, camChunkZ + r });
chunkQueue.push({ camChunkX + r, camChunkY - y, camChunkZ });
chunkQueue.push({ camChunkX, camChunkY - y, camChunkZ - r });
chunkQueue.push({ camChunkX - r, camChunkY - y, camChunkZ });
}
}
// Add edges
for (int e = 1; e < r; e++)
{
for (int y = 0; y <= renderHeight; y++)
{
chunkQueue.push({ camChunkX + e, camChunkY + y, camChunkZ + r });
chunkQueue.push({ camChunkX - e, camChunkY + y, camChunkZ + r });
chunkQueue.push({ camChunkX + r, camChunkY + y, camChunkZ + e });
chunkQueue.push({ camChunkX + r, camChunkY + y, camChunkZ - e });
chunkQueue.push({ camChunkX + e, camChunkY + y, camChunkZ - r });
chunkQueue.push({ camChunkX - e, camChunkY + y, camChunkZ - r });
chunkQueue.push({ camChunkX - r, camChunkY + y, camChunkZ + e });
chunkQueue.push({ camChunkX - r, camChunkY + y, camChunkZ - e });
if (y > 0)
{
chunkQueue.push({ camChunkX + e, camChunkY - y, camChunkZ + r });
chunkQueue.push({ camChunkX - e, camChunkY - y, camChunkZ + r });
chunkQueue.push({ camChunkX + r, camChunkY - y, camChunkZ + e });
chunkQueue.push({ camChunkX + r, camChunkY - y, camChunkZ - e });
chunkQueue.push({ camChunkX + e, camChunkY - y, camChunkZ - r });
chunkQueue.push({ camChunkX - e, camChunkY - y, camChunkZ - r });
chunkQueue.push({ camChunkX - r, camChunkY - y, camChunkZ + e });
chunkQueue.push({ camChunkX - r, camChunkY - y, camChunkZ - e });
}
}
}
// Add corners
for (int y = 0; y <= renderHeight; y++)
{
chunkQueue.push({ camChunkX + r, camChunkY + y, camChunkZ + r });
chunkQueue.push({ camChunkX + r, camChunkY + y, camChunkZ - r });
chunkQueue.push({ camChunkX - r, camChunkY + y, camChunkZ + r });
chunkQueue.push({ camChunkX - r, camChunkY + y, camChunkZ - r });
if (y > 0)
{
chunkQueue.push({ camChunkX + r, camChunkY - y, camChunkZ + r });
chunkQueue.push({ camChunkX + r, camChunkY - y, camChunkZ - r });
chunkQueue.push({ camChunkX - r, camChunkY - y, camChunkZ + r });
chunkQueue.push({ camChunkX - r, camChunkY - y, camChunkZ - r });
}
}
}
chunkMutex.unlock();
}
else
{
chunkMutex.lock();
if (!chunkDataQueue.empty())
{
ChunkPos chunkPos = chunkDataQueue.front();
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();
}
}
// Set top data
{
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];
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
{
chunkMutex.unlock();
return chunks.at(chunkPos);
}
}
void Planet::ClearChunkQueue()
{
lastCamX++;
}

View File

@ -5,31 +5,55 @@
#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
{
// Methods
public:
Planet();
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, unsigned int modelLoc);
ChunkData* GetChunkData(ChunkPos chunkPos);
void Update(glm::vec3 cameraPos);
Chunk* GetChunk(ChunkPos chunkPos);
void ClearChunkQueue();
private:
void ChunkThreadUpdate();
// Variables
public:
static Planet* planet;
unsigned int numChunks = 0, numChunksRendered = 0;
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;
unsigned int chunkSize = 32;
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

@ -0,0 +1,58 @@
#pragma once
struct Vertex
{
char posX, posY, posZ;
char texGridX, texGridY;
char direction;
Vertex(char _posX, char _posY, char _posZ, char _texGridX, char _texGridY, char _direction)
{
posX = _posX;
posY = _posY;
posZ = _posZ;
texGridX = _texGridX;
texGridY = _texGridY;
direction = _direction;
}
};
struct WaterVertex
{
char posX, posY, posZ;
char texGridX, texGridY;
char direction;
char top;
WaterVertex(char _posX, char _posY, char _posZ, char _texGridX, char _texGridY, char _direction, char _top)
{
posX = _posX;
posY = _posY;
posZ = _posZ;
texGridX = _texGridX;
texGridY = _texGridY;
direction = _direction;
top = _top;
}
};
struct BillboardVertex
{
float posX, posY, posZ;
char texGridX, texGridY;
BillboardVertex(float _posX, float _posY, float _posZ, char _texGridX, char _texGridY)
{
posX = _posX;
posY = _posY;
posZ = _posZ;
texGridX = _texGridX;
texGridY = _texGridY;
}
};

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;
@ -15,7 +18,7 @@ void WorldGen::GenerateChunkData(int chunkX, int chunkY, int chunkZ, int chunkSi
// Init noise settings
static NoiseSettings surfaceSettings[]{
{ 0.01f, 20.0f, 0 },
{ 0.1f, 3.0f, 0 }
{ 0.05f, 3.0f, 0 }
};
static int surfaceSettingsLength = sizeof(surfaceSettings) / sizeof(*surfaceSettings);
@ -30,70 +33,151 @@ void WorldGen::GenerateChunkData(int chunkX, int chunkY, int chunkZ, int chunkSi
static int oreSettingsLength = sizeof(oreSettings) / sizeof(*oreSettings);
static SurfaceFeature surfaceFeatures[]{
// Pond
{
{ 0.43f, 1.0f, 2.35f, .85f, 1, 0 }, // Noise
{ // Blocks
0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 13, 13, 0, 0,
0, 0, 13, 13, 13, 0, 0,
0, 0, 0, 13, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0,
0, 2, 13, 13, 2, 0, 0,
0, 2, 13, 13, 13, 2, 0,
2, 13, 13, 13, 13, 13, 2,
2, 13, 13, 13, 13, 13, 2,
2, 13, 13, 13, 13, 13, 2,
0, 2, 13, 13, 13, 2, 0,
0, 0, 2, 13, 2, 0, 0,
0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0,
},
{ // Replace?
false, false, false, false, false, false, false,
false, false, false, false, false, false, false,
false, false, false, true, true, false, false,
false, false, true, true, true, false, false,
false, false, false, true, false, false, false,
false, false, false, false, false, false, false,
false, false, false, false, false, false, false,
false, false, true, true, false, false, false,
false, false, true, true, true, false, false,
false, true, true, true, true, true, false,
false, true, true, true, true, true, false,
false, true, true, true, true, true, false,
false, false, true, true, true, false, false,
false, false, false, true, false, false, false,
false, false, true, true, false, false, false,
false, false, true, true, true, true, false,
false, true, true, true, true, true, false,
false, true, true, true, true, true, false,
false, true, true, true, true, true, false,
false, false, true, true, true, false, false,
false, false, false, true, false, false, false,
},
7, 3, 7, // Size
-3, -2, -3 // Offset
},
// Tree
{
{ 4.23f, 1.0f, 8.54f, .8f, 1, 0 },
{
0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 5, 5, 0, 0,
0, 0, 0, 5, 5, 0, 0,
0, 0, 0, 5, 5, 0, 0,
0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0,
0, 0, 0, 0, 0,
0, 0, 1, 0, 0,
0, 0, 0, 0, 0,
0, 0, 0, 0, 0,
0, 0, 0, 5, 5, 0, 0,
0, 0, 0, 5, 5, 5, 0,
0, 0, 0, 5, 5, 5, 5,
0, 0, 0, 5, 5, 5, 0,
0, 0, 0, 5, 5, 0, 0,
0, 0, 0, 0, 0,
0, 0, 0, 0, 0,
0, 0, 4, 0, 0,
0, 0, 0, 0, 0,
0, 0, 0, 0, 0,
0, 0, 0, 5, 5, 0, 0,
0, 0, 0, 5, 5, 5, 5,
1, 4, 4, 4, 4, 5, 5,
0, 0, 0, 5, 5, 5, 5,
0, 0, 0, 5, 5, 0, 0,
0, 0, 0, 0, 0,
0, 0, 0, 0, 0,
0, 0, 4, 0, 0,
0, 0, 0, 0, 0,
0, 0, 0, 0, 0,
0, 0, 0, 5, 5, 0, 0,
0, 0, 0, 5, 5, 5, 0,
0, 0, 0, 5, 5, 5, 5,
0, 0, 0, 5, 5, 5, 0,
0, 0, 0, 5, 5, 0, 0,
0, 5, 5, 5, 0,
5, 5, 5, 5, 5,
5, 5, 4, 5, 5,
5, 5, 5, 5, 5,
0, 5, 5, 5, 0,
0, 5, 5, 5, 0,
5, 5, 5, 5, 5,
5, 5, 4, 5, 5,
5, 5, 5, 5, 5,
0, 5, 5, 5, 0,
0, 0, 0, 0, 0,
0, 0, 5, 0, 0,
0, 5, 5, 5, 0,
0, 0, 5, 0, 0,
0, 0, 0, 0, 0,
0, 0, 0, 0, 0,
0, 0, 5, 0, 0,
0, 5, 5, 5, 0,
0, 0, 5, 0, 0,
0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 5, 5, 0, 0,
0, 0, 0, 5, 5, 0, 0,
0, 0, 0, 5, 5, 0, 0,
0, 0, 0, 0, 0, 0, 0,
},
{
false, false, false, false, false, false, false,
false, false, false, false, false, false, false,
false, false, false, false, false, false, false,
false, false, false, false, false, false, false,
false, false, false, false, false, false, false,
false, false, false, false, false,
false, false, false, false, false,
false, false, true, false, false,
false, false, false, false, false,
false, false, false, false, false,
false, false, false, false, false, false, false,
false, false, false, false, false, false, false,
false, false, false, false, false, false, false,
false, false, false, false, false, false, false,
false, false, false, false, false, false, false,
false, false, false, false, false,
false, false, false, false, false,
false, false, true, false, false,
false, false, false, false, false,
false, false, false, false, false,
false, false, false, false, false, false, false,
false, false, false, false, false, false, false,
true, true, true, true, true, false, false,
false, false, false, false, false, false, false,
false, false, false, false, false, false, false,
false, false, false, false, false,
false, false, false, false, false,
false, false, true, false, false,
false, false, false, false, false,
false, false, false, false, false,
false, false, false, false, false, false, false,
false, false, false, false, false, false, false,
false, false, false, false, false, false, false,
false, false, false, false, false, false, false,
false, false, false, false, false, false, false,
false, false, false, false, false,
false, false, false, false, false,
false, false, true, false, false,
false, false, false, false, false,
false, false, false, false, false,
false, false, false, false, false, false, false,
false, false, false, false, false, false, false,
false, false, false, false, false, false, false,
false, false, false, false, false, false, false,
false, false, false, false, false, false, false,
false, false, false, false, false,
false, false, false, false, false,
false, false, true, false, false,
false, false, false, false, false,
false, false, false, false, false,
false, false, false, false, false,
false, false, false, false, false,
false, false, false, false, false,
false, false, false, false, false,
false, false, false, false, false,
false, false, false, false, false,
false, false, false, false, false,
false, false, false, false, false,
false, false, false, false, false,
false, false, false, false, false,
},
5,
7,
@ -102,22 +186,6 @@ void WorldGen::GenerateChunkData(int chunkX, int chunkY, int chunkZ, int chunkSi
0,
-2
},
// Grass
{
{ 2.65f, 1.0f, 8.54f, .5f, 1, 0 },
{
2, 6
},
{
false, false
},
1,
2,
1,
0,
0,
0
},
// Tall Grass
{
{ 1.23f, 1.0f, 4.34f, .6f, 1, 0 },
@ -134,6 +202,22 @@ void WorldGen::GenerateChunkData(int chunkX, int chunkY, int chunkZ, int chunkSi
0,
0
},
// Grass
{
{ 2.65f, 1.0f, 8.54f, .5f, 1, 0 },
{
2, 6
},
{
false, false
},
1,
2,
1,
0,
0,
0
},
// Poppy
{
{ 5.32f, 1.0f, 3.67f, .8f, 1, 0 },
@ -201,14 +285,14 @@ void WorldGen::GenerateChunkData(int chunkX, int chunkY, int chunkZ, int chunkSi
};
static int surfaceFeaturesLength = sizeof(surfaceFeatures) / sizeof(*surfaceFeatures);
// Set vector size
chunkData->reserve(chunkSize * chunkSize * chunkSize);
static int waterLevel = 20;
// 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++)
@ -249,9 +333,14 @@ void WorldGen::GenerateChunkData(int chunkX, int chunkY, int chunkZ, int chunkSi
// Sky and Caves
if (y + startY > noiseY)
chunkData->push_back(0);
{
if (y + startY <= waterLevel)
chunkData[currentIndex] = Blocks::WATER;
else
chunkData[currentIndex] = Blocks::AIR;
}
else if (cave)
chunkData->push_back(0);
chunkData[currentIndex] = Blocks::AIR;
// Ground
else
{
@ -269,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;
}
@ -278,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);
if (noiseY > waterLevel + 1)
chunkData[currentIndex] = Blocks::GRASS_BLOCK;
else
chunkData[currentIndex] = Blocks::SAND;
else if (y + startY > 10)
chunkData->push_back(Blocks::DIRT_BLOCK);
if (noiseY > waterLevel + 1)
chunkData[currentIndex] = Blocks::DIRT_BLOCK;
else
chunkData[currentIndex] = Blocks::SAND;
else
chunkData->push_back(Blocks::STONE_BLOCK);
chunkData[currentIndex] = Blocks::STONE_BLOCK;
}
}
currentIndex++;
}
}
}
@ -305,7 +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 or on sand
if (noiseY < waterLevel + 2)
continue;
// Check if it's in a cave
@ -354,30 +455,25 @@ 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 = fX * surfaceFeatures[i].sizeZ * surfaceFeatures[i].sizeY +
fZ * surfaceFeatures[i].sizeY +
fY;
int featureIndex = fY * surfaceFeatures[i].sizeX * surfaceFeatures[i].sizeZ +
fX * surfaceFeatures[i].sizeZ +
fZ;
//std::cout << "Feature Index: " << featureIndex << '\n';
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];
}
}
}
//int index = x * chunkSize * chunkSize + z * chunkSize + noiseY;
//chunkData->at(index) = surfaceFeatures[i].block;
//index = x * chunkSize * chunkSize + z * chunkSize + noiseY + 1;
//chunkData->at(index) = surfaceFeatures[i].block;
}
}
}

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);
}

View File

@ -0,0 +1,11 @@
add_library(imgui
imgui.cpp
imgui_demo.cpp
imgui_draw.cpp
imgui_impl_glfw.cpp
imgui_impl_opengl3.cpp
imgui_tables.cpp
imgui_widgets.cpp
)
target_include_directories(imgui PUBLIC ./)