Zepha Voxel Modeller

master
Auri 2020-11-01 14:09:40 -08:00
parent 7e731cb6e9
commit 9100a853e6
59 changed files with 739 additions and 100 deletions

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
lib
.idea

0
.idea/.gitignore vendored Normal file → Executable file
View File

0
.idea/.name Normal file → Executable file
View File

0
.idea/Voxel Modeller.iml Normal file → Executable file
View File

0
.idea/dictionaries/aurailus.xml Normal file → Executable file
View File

0
.idea/discord.xml Normal file → Executable file
View File

0
.idea/inspectionProfiles/Project_Default.xml Normal file → Executable file
View File

0
.idea/misc.xml Normal file → Executable file
View File

0
.idea/modules.xml Normal file → Executable file
View File

0
.idea/vcs.xml Normal file → Executable file
View File

0
CMakeLists.txt Normal file → Executable file
View File

5
LICENSE.md Executable file
View File

@ -0,0 +1,5 @@
(c) 2018-2019 Nicole Collings, All rights reserved.
You do not have permission to redistribute, copy, or share this work without my explicit written permission.
You may download the repository and compile it for personal use or potential contributions.
Please contact me if you have any questions or special requests.

21
README.md Executable file
View File

@ -0,0 +1,21 @@
# Zepha Voxel Game
[![Codacy Rating](https://img.shields.io/codacy/grade/666016450e2645f7a88a2baea1a9f7fd.svg?logo=codacy)](https://app.codacy.com/app/Aurailus/Zepha?utm_source=github.com&utm_medium=referral&utm_content=Aurailus/Zeus_cpp&utm_campaign=Badge_Grade_Settings)
[![Discord Badge](https://img.shields.io/discord/416379773976051712.svg?color=7289DA&label=discord&logo=discord&logoColor=white)](https://auri.xyz/discord.php)
[![GitHub Commit](https://img.shields.io/github/commit-activity/m/aurailus/zepha.svg?logo=github&label=commit%20activity)](https://github.com/Aurailus/Zepha/commits/master)
### About
Zepha is a powerful, extensible C++ Voxel Game with immense modding possibilities. The API provided allows everybody with even a basic knowledge of Lua to create any subgame imaginable. Though other Voxel Games like Zepha exist, none of them can match it's superior performance, graphical capabilities, and raw modding capability.
Zepha is very early in developement, however it already has several strengths over alternative games / engines. Infinite-sized worlds, client side scripting, a well-designed game selection menu, and more. For those interested in trying out the modding API, a seperate repository containing the documentation for the game is available [here](https://github.com/Aurailus/Zepha-docs).
Zepha's full source code is currently available on this repository for viewing and personal use, however it is important to note that this project is *not* free nor open source. Unfortunately, as my dream is to make a living off of game development this is not a viable strategy for me. Learning from the source code or exploring the source is allowed and encouraged, though. Feel free to use this repository as a reference for similar works until the repository eventually becomes private.
### License
**(c) 2018-2020 Nicole Collings, All Rights Reserved.**
You do not have permission to redistribute, copy, or share this work without my explicit written permission.
You may download the repository and compile it for personal use or potential contributions.
Please contact me if you have any questions or special requests.

33
assets/shader/ortho/hud.fs Executable file
View File

@ -0,0 +1,33 @@
#version 330 core
in vec4 colorData;
in vec3 colorBlend;
in float normalShading;
in float useTex;
out vec4 fragColor;
uniform sampler2D tex;
uniform vec4 uClipBounds;
void main() {
// Overflow clipping
if (uClipBounds.z != 0 && uClipBounds.w != 0
&&(gl_FragCoord.x < uClipBounds.x || gl_FragCoord.y < uClipBounds.y
|| gl_FragCoord.x > uClipBounds.z || gl_FragCoord.y > uClipBounds.w)) discard;
vec4 color = vec4(1, 1, 1, 1);
if (useTex > 0.5) {
vec4 spec = texture(tex, colorData.xy) * vec4(colorBlend, colorData.w);
if (spec.a <= 0) discard;
color = spec;
}
else {
if (colorData.a <= 0) discard;
color = colorData * vec4(colorBlend, 1);
}
color *= vec4(vec3(normalShading), 1);
fragColor = color;
}

42
assets/shader/ortho/hud.vs Executable file
View File

@ -0,0 +1,42 @@
#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec4 aColorData;
layout (location = 2) in vec3 aColorBlend;
layout (location = 3) in float aUseTex;
layout (location = 4) in vec3 aNormal;
layout (location = 5) in ivec4 aBoneIDs;
layout (location = 6) in vec4 aBoneWeights;
uniform mat4 model;
uniform mat4 ortho;
const int MAX_BONES = 100;
uniform mat4 uBones[MAX_BONES];
out vec4 colorData;
out vec3 colorBlend;
out float normalShading;
out float useTex;
void main() {
mat4 boneTransform = uBones[aBoneIDs[0]] * aBoneWeights[0];
boneTransform += uBones[aBoneIDs[1]] * aBoneWeights[1];
boneTransform += uBones[aBoneIDs[2]] * aBoneWeights[2];
boneTransform += uBones[aBoneIDs[3]] * aBoneWeights[3];
float totalWeight = aBoneWeights[0] + aBoneWeights[1] + aBoneWeights[2] + aBoneWeights[3];
boneTransform = (boneTransform * totalWeight) + (mat4(1.0) * (1 - totalWeight));
if (aNormal == vec3(0, 0, 0)) normalShading = 1;
else {
vec3 normal = normalize(transpose(inverse(mat3(model))) * (boneTransform * vec4(normalize(aNormal), 0.0)).xyz);
normalShading = 1 + (normal.x * -normal.z * 0.15) - (normal.y * 0.18);
}
gl_Position = ortho * model * boneTransform * vec4(aPos, 1);
colorData = aColorData;
colorBlend = aColorBlend;
useTex = aUseTex;
}

View File

@ -0,0 +1,50 @@
#version 330 core
#define NEAR_FOG vec3(0.40, 0.56, 0.72)
#define FAR_FOG vec3(0.58, 0.76, 0.94)
out vec4 outColor;
in vec2 texCoords;
//uniform sampler2D gPosition;
uniform sampler2D gNormal;
uniform sampler2D gColorSpec;
uniform sampler2D ssaoSampler;
uniform vec3 camPosition;
void main() {
vec3 normal = texture(gNormal, texCoords).rgb;
vec3 color = texture(gColorSpec, texCoords).rgb;
float ssao = texture(ssaoSampler, texCoords).r;
//Shade based on Normals
float shading = (0.8 + abs(normal.x) * 0.15) + (normal.y * 0.15) + 0.2;
color *= vec3(shading);
vec3 lighting = color;
//Apply Lighting
// lighting *= 0.1;
//
// float radius = 16;
//
// float lightDist = length(camPosition - fragPos);
// if (lightDist < radius) {
// vec3 lightDir = normalize(camPosition - fragPos);
// vec3 diffuse = max(dot(normal, lightDir) * 0.6 + 0.4, 0.0) * color * vec3(1, 1, 1);
// diffuse *= 1 - min(lightDist / radius, 1);
// lighting += diffuse;
// }
//Apply fog color based on distance from camera
// float dist = distance(vec3(0, 0, 0), vec3(fragPos));
// float nearFog = min(max(dist - 200, 0) / 100, 1);
// float farFog = min(max(dist - 250, 0) / 100, 1);
// color = mix(mix(vec3(lighting), NEAR_FOG, nearFog), FAR_FOG, farFog);
color = lighting * ssao;
outColor = vec4(color, 1);
}

View File

@ -0,0 +1,14 @@
#version 330 core
//Just translate the coordinates directly into screen space.
//For rendering the data onto a quad.
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec2 aTexCoords;
out vec2 texCoords;
void main() {
texCoords = aTexCoords;
gl_Position = vec4(aPos, 1.0);
}

26
assets/shader/post/ssaoBlur.fs Executable file
View File

@ -0,0 +1,26 @@
#version 440 core
#define RAD 2
#define DIVIDEBY ((RAD * 2) * (RAD * 2))
out float outColor;
in vec2 texCoords;
layout (binding = 0) uniform sampler2D ssaoInput;
uniform float sampleScale;
void main() {
vec2 texelSize = 1.0 / vec2(textureSize(ssaoInput, 0));
float result = 0.0;
for (int x = -RAD; x < RAD; x++) {
for (int y = -RAD; y < RAD; y++) {
vec2 offset = vec2(float(x), float(y)) * texelSize;
result += texture(ssaoInput, (texCoords * sampleScale) + offset).r;
}
}
outColor = result / DIVIDEBY;
}

60
assets/shader/post/ssaoCalc.fs Executable file
View File

@ -0,0 +1,60 @@
#version 440 core
#define RADIUS 1.0
#define RANGE 0.50
#define BIAS 0.08
out float outColor;
in vec2 texCoords;
layout (binding = 0) uniform sampler2D gPosition;
layout (binding = 1) uniform sampler2D gNormal;
layout (binding = 2) uniform sampler2D texNoise;
uniform uint kernels;
uniform vec3 samples[64]; //Must be a constant, setting to 64 because it's unlikely to go higher
uniform mat4 projection;
uniform mat4 view;
uniform float sampleScale;
const vec2 noiseScale = vec2(1920.0/4.0, 1004.0/4.0);
void main() {
vec3 fragPos = vec3(vec4(texture(gPosition, texCoords * sampleScale).xyz, 1.0f));
vec3 normal = normalize(mat3(view) * texture(gNormal, texCoords * sampleScale).xyz);
vec3 randomVec = normalize(texture(texNoise, texCoords * sampleScale * noiseScale).xyz);
if (normal == vec3(0)) discard;
vec3 tangent = normalize(randomVec - normal * dot(randomVec, normal));
vec3 bitangent = cross(normal, tangent);
mat3 tbn = mat3(tangent, bitangent, normal);
vec4 fragSample = vec4(fragPos, 1.0);
fragSample = projection * fragSample;
fragSample.xyz /= fragSample.w;
fragSample.xyz = fragSample.xyz * 0.5 + 0.5;
float fragDepth = vec3(texture(gPosition, fragSample.xy)).z;
float occlusion = 0.0;
for (int i = 0; i < kernels; ++i) {
vec3 smpl = tbn * samples[i]; // From tangent to view-space
smpl = fragPos + smpl * RADIUS;
vec4 offset = vec4(smpl, 1.0);
offset = projection * offset;
offset.xyz /= offset.w;
offset.xyz = offset.xyz * 0.5 + 0.5;
float sampleDepth = vec3(texture(gPosition, offset.xy)).z;
float rangeCheck = smoothstep(0.0, 1.0, RANGE / abs(fragDepth - sampleDepth));
occlusion += (sampleDepth >= fragDepth + BIAS ? 1.0 : 0.0) * rangeCheck;
}
outColor = 1.0 - (occlusion / kernels / 2);
}

2
assets/shader/world.fs Normal file → Executable file
View File

@ -15,6 +15,8 @@ void main() {
if (spec.a < 0.1) discard;
vec3 color = spec.xyz;
if (!gl_FrontFacing) color *= vec3(1, 0, 0);
if (highlight) {
color *= 1.25;
color += 0.05;

0
assets/shader/world.vs Normal file → Executable file
View File

View File

@ -0,0 +1,27 @@
#version 330 core
layout (location = 0) out vec4 gPosition;
layout (location = 1) out vec4 gNormal;
layout (location = 2) out vec4 gSpecular;
in vec3 fragPos;
in vec4 colorData;
in vec3 colorBlend;
in float useTex;
in vec3 normal;
uniform sampler2D tex;
void main() {
if (useTex > 0.5) {
vec4 spec = texture(tex, colorData.xy) * vec4(colorBlend, colorData.w);
if (spec.a < 0.1) discard;
gSpecular = spec;
}
else {
if (colorData.a < 0.1) discard;
gSpecular = colorData * vec4(colorBlend, 1);
}
gPosition = vec4(fragPos, 1);
gNormal = vec4(normalize(normal), 1);
}

View File

@ -0,0 +1,43 @@
#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec4 aColorData;
layout (location = 2) in vec3 aColorBlend;
layout (location = 3) in float aUseTex;
layout (location = 4) in vec3 aNormal;
layout (location = 5) in ivec4 aBoneIDs;
layout (location = 6) in vec4 aBoneWeights;
uniform mat4 model;
uniform mat4 projection;
uniform mat4 view;
const int MAX_BONES = 100;
uniform mat4 uBones[MAX_BONES];
out vec3 fragPos;
out vec4 colorData;
out vec3 colorBlend;
out float useTex;
out vec3 normal;
void main() {
mat4 boneTransform = uBones[aBoneIDs[0]] * aBoneWeights[0];
boneTransform += uBones[aBoneIDs[1]] * aBoneWeights[1];
boneTransform += uBones[aBoneIDs[2]] * aBoneWeights[2];
boneTransform += uBones[aBoneIDs[3]] * aBoneWeights[3];
float totalWeight = aBoneWeights[0] + aBoneWeights[1] + aBoneWeights[2] + aBoneWeights[3];
boneTransform = (boneTransform * totalWeight) + (mat4(1.0) * (1 - totalWeight));
vec4 worldPos = model * boneTransform * vec4(aPos, 1.0);
normal = transpose(inverse(mat3(model))) * (boneTransform * vec4(normalize(aNormal), 0.0)).xyz;
fragPos = (view * worldPos).xyz;
colorData = aColorData;
colorBlend = aColorBlend;
useTex = aUseTex;
gl_Position = projection * view * worldPos;
}

View File

@ -0,0 +1,36 @@
#version 330 core
layout (location = 0) out vec4 gPosition;
layout (location = 1) out vec4 gNormal;
layout (location = 2) out vec4 gSpecular;
in vec2 texCoords;
in vec2 blendMaskCoords;
in vec3 blend;
in vec3 fragPos;
in vec3 normal;
in vec3 light;
uniform float time;
uniform sampler2D tex;
void main() {
float blendMaskMult = -1;
if (blendMaskCoords.x >= 0 && blendMaskCoords.y >= 0) blendMaskMult = texture(tex, blendMaskCoords).r;
vec4 spec = texture(tex, texCoords);
vec3 blendCol = blend;
if (blendMaskMult >= 0) {
blendCol = (vec3(1, 1, 1) * (1 - blendMaskMult)) + (blendCol * blendMaskMult);
}
spec = vec4(spec.xyz * blendCol * light, spec.a);
if (spec.a < 0.1) discard;
gSpecular = spec;
gPosition = vec4(fragPos, 1);
gNormal = vec4(normal, 1);
}

View File

@ -0,0 +1,112 @@
#version 330 core
#define TAU 6.28318530718
#define MAX_BLOCKLIGHT 31
#define MAX_SUNLIGHT 15
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec2 aTexCoords;
layout (location = 2) in vec3 aBlend;
layout (location = 3) in vec2 aBlendMaskCoords;
layout (location = 4) in float aNormal;
layout (location = 5) in vec4 aLight;
layout (location = 6) in float aShaderMod;
layout (location = 7) in vec3 aModValues;
uniform mat4 model;
uniform mat4 projection;
uniform mat4 view;
uniform sampler2D swayTex;
uniform float time;
out vec2 texCoords;
out vec2 blendMaskCoords;
out vec3 blend;
out vec3 fragPos;
out vec3 normal;
out vec3 light;
vec3 unpackFloat(float src) {
return vec3(fract(src) * 2.0f - 1.0f, fract(src * 256.f) * 2.0f - 1.0f, fract(src * 65536.f) * 2.0f - 1.0f);
}
vec4 rotateX(vec4 vertex, vec4 offset, float radians) {
vertex -= offset;
mat2 m = mat2(cos(radians), -sin(radians), sin(radians), cos(radians));
return vec4(m * vertex.zy, vertex.xw).zyxw + offset;
}
vec4 rotateY(vec4 vertex, vec4 offset, float radians) {
vertex -= offset;
mat2 m = mat2(cos(radians), -sin(radians), sin(radians), cos(radians));
return vec4(m * vertex.xz, vertex.yw).xzyw + offset;
}
vec4 rotateZ(vec4 vertex, vec4 offset, float radians) {
vertex -= offset;
mat2 m = mat2(cos(radians), -sin(radians), sin(radians), cos(radians));
return vec4(m * vertex.xy, vertex.zw).xyzw + offset;
}
void main() {
vec4 pos = vec4(aPos, 1);
vec4 nml = vec4(unpackFloat(aNormal), 1);
switch (int(aShaderMod)) {
default: break;
case 1: { // Rotate X
vec4 origin = vec4(round(unpackFloat(aModValues.x) * 8 + 8) + 0.5, 1);
pos = rotateX(pos, origin, time * TAU * aModValues.y);
nml = rotateX(nml, vec4(0), time * TAU * aModValues.y);
break;
}
case 2: { // Rotate Y
vec4 origin = vec4(round(unpackFloat(aModValues.x) * 8 + 8) + 0.5, 1);
pos = rotateY(pos, origin, time * TAU * aModValues.y);
nml = rotateY(nml, vec4(0), time * TAU * aModValues.y);
break;
}
case 3: { // Rotate Z
vec4 origin = vec4(round(unpackFloat(aModValues.x) * 8 + 8) + 0.5, 1);
pos = rotateZ(pos, origin, time * TAU * aModValues.y);
nml = rotateZ(nml, vec4(0), time * TAU * aModValues.y);
break;
}
case 4: { //Sway Grounded
vec4 origin = vec4(round(unpackFloat(aModValues.x) * 8 + 8), 1);
vec3 bsp = vec3(pos - origin);
vec3 worldPos = (model * pos).xyz;
if (bsp.x*bsp.y*bsp.z != 0 && bsp.x*bsp.y*bsp.z != 1) {
vec3 sway = (texture(swayTex, worldPos.xz * (worldPos.y / 16.f) / 16.f).xyz - .5f) * vec3(aModValues.y, aModValues.y / 2, aModValues.y);
pos += vec4(sway, 0);
}
break;
}
case 5: { //Sway Full Block
vec3 worldPos = (model * pos).xyz;
vec3 sway = (texture(swayTex, worldPos.xz * (worldPos.y / 16.f) / 16.f).xyz - .5f) * vec3(aModValues.y, aModValues.y / 2, aModValues.y);
pos += vec4(sway, 0);
break;
}
}
float sunlightIntensity = 1;
// float sunlightIntensity = aLight.w * clamp(sin(time / 2.5) + 0.25, 0, 1) / MAX_SUNLIGHT;
vec3 blockLightColor = (aLight.xyz / MAX_BLOCKLIGHT) * vec3(1 + sunlightIntensity / 4);
vec3 sunlightColor = clamp(sunlightIntensity * 1.25 * vec3(1, 1, 1) * (aLight.w / 15.0), 0, 1);
vec3 resultantLight = vec3(max(sunlightColor.x, blockLightColor.x), max(sunlightColor.y, blockLightColor.y), max(sunlightColor.z, blockLightColor.z));
vec4 worldPos = model * pos;
// worldPos.y -= pow(length(view * worldPos * 0.125) - 0.125, 2);
worldPos.y -= pow(length(view * worldPos * 0.025) - 0, 2);
fragPos = (view * worldPos).xyz;
texCoords = aTexCoords;
blendMaskCoords = aBlendMaskCoords;
blend = aBlend;
normal = nml.xyz;
light = resultantLight;
gl_Position = projection * view * worldPos;
}

0
assets/textures/dirt.png Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 2.4 KiB

8
src/App.cpp Normal file → Executable file
View File

@ -8,10 +8,11 @@ App::App() :
window(),
camera(&window),
renderer(&window, &camera),
input(window.getInput()),
controller(input, camera),
blockManager(&camera, &window) {
blockManager(&camera, &window),
input(window.getInput()),
controller(input, window, camera, blockManager) {
while (!window.shouldEnd()) {
update();
@ -22,7 +23,6 @@ App::App() :
void App::update() {
window.update();
controller.update();
blockManager.update(input, controller);
}
void App::render() {

7
src/App.h Normal file → Executable file
View File

@ -8,8 +8,8 @@
#include "graph/Camera.h"
#include "graph/Renderer.h"
#include "input/ViewportControl.h"
#include "model/BlockModelManager.h"
#include "input/Controller.h"
class App {
public:
@ -22,8 +22,9 @@ private:
Window window;
Camera camera;
Renderer renderer;
Input& input;
ViewportControl controller;
BlockModelManager blockManager;
Input& input;
Controller controller;
};

2
src/CMakeLists.txt Normal file → Executable file
View File

@ -1,3 +1,3 @@
set(MODELLER_SRC
graph/Renderer.cpp graph/Renderer.h App.cpp App.h graph/Window.cpp graph/Window.h graph/Shader.cpp graph/Shader.h graph/Camera.h graph/Camera.cpp graph/Mesh.h graph/Vertex.h graph/Texture.h graph/Texture.cpp input/ViewportControl.cpp input/ViewportControl.h input/Input.cpp input/Input.h model/BlockModelManager.cpp model/BlockModelManager.h model/BlockModelInstance.cpp model/BlockModelInstance.h model/BlockFace.cpp model/BlockFace.h model/BlockModel.cpp model/BlockModel.h model/EditingBlockModel.cpp model/EditingBlockModel.h input/Ray.h)
graph/Renderer.cpp graph/Renderer.h App.cpp App.h graph/Window.cpp graph/Window.h graph/Shader.cpp graph/Shader.h graph/Camera.h graph/Camera.cpp graph/Mesh.h graph/Vertex.h graph/Texture.h graph/Texture.cpp input/ViewportController.cpp input/ViewportController.h input/Input.cpp input/Input.h model/BlockModelManager.cpp model/BlockModelManager.h model/BlockModelInstance.cpp model/BlockModelInstance.h model/BlockFace.cpp model/BlockFace.h model/BlockModel.cpp model/BlockModel.h model/EditingBlockModel.cpp model/EditingBlockModel.h util/Ray.h input/Controller.cpp input/Controller.h)
add_library(${MAIN_LIB_NAME} ${MODELLER_SRC})

0
src/Main.cpp Normal file → Executable file
View File

0
src/graph/Camera.cpp Normal file → Executable file
View File

0
src/graph/Camera.h Normal file → Executable file
View File

0
src/graph/Mesh.h Normal file → Executable file
View File

2
src/graph/Renderer.cpp Normal file → Executable file
View File

@ -36,7 +36,7 @@ void Renderer::setClearColor(glm::vec4 color) {
void Renderer::reset() {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_CULL_FACE);
// glEnable(GL_CULL_FACE);
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LESS);
glDisable(GL_BLEND);

0
src/graph/Renderer.h Normal file → Executable file
View File

0
src/graph/Shader.cpp Normal file → Executable file
View File

0
src/graph/Shader.h Normal file → Executable file
View File

0
src/graph/Texture.cpp Normal file → Executable file
View File

0
src/graph/Texture.h Normal file → Executable file
View File

0
src/graph/Vertex.h Normal file → Executable file
View File

0
src/graph/Window.cpp Normal file → Executable file
View File

0
src/graph/Window.h Normal file → Executable file
View File

53
src/input/Controller.cpp Executable file
View File

@ -0,0 +1,53 @@
//
// Created by aurailus on 2020-07-05.
//
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include "Controller.h"
#include "Input.h"
#include "../model/BlockModelManager.h"
#include "../util/Ray.h"
Controller::Controller(Input& input, Window& window, Camera& camera, BlockModelManager& blockManager) :
input(input),
window(window),
camera(camera),
viewport(input, camera),
blockManager(blockManager) {
}
void Controller::update() {
viewport.update();
if (!blockManager.getEditingModel()) modelSelect();
else modelEdit();
}
void Controller::modelSelect() {
glm::vec3 dir = Ray::worldRayFromCursor(window, camera);
glm::vec3 ray = camera.getPos();
float dis = 0.05f;
while (dis < 20) {
glm::vec3 end = ray + (dir * dis);
glm::ivec3 pos = glm::floor(end + glm::vec3(0.5));
if (blockManager.highlightInstanceAtPos(pos)) {
if (input.keyPressed(GLFW_MOUSE_BUTTON_LEFT)) {
blockManager.setEditingInstance(pos);
viewport.setViewFocus(pos);
}
break;
}
dis += 0.05;
}
}
void Controller::modelEdit() {
}

30
src/input/Controller.h Executable file
View File

@ -0,0 +1,30 @@
//
// Created by aurailus on 2020-07-05.
//
#pragma once
#include "ViewportController.h"
class Input;
class Camera;
class Window;
class BlockModelManager;
class Controller {
public:
Controller(Input& input, Window& window, Camera& camera, BlockModelManager& blockManager);
void update();
private:
void modelSelect();
void modelEdit();
ViewportController viewport;
Input& input;
Window& window;
Camera& camera;
BlockModelManager& blockManager;
};

0
src/input/Input.cpp Normal file → Executable file
View File

0
src/input/Input.h Normal file → Executable file
View File

View File

@ -8,19 +8,19 @@
#include <glm/glm.hpp>
#include <iostream>
#include "ViewportControl.h"
#include "ViewportController.h"
#include "../graph/Camera.h"
#include "Input.h"
ViewportControl::ViewportControl(Input &input, Camera &camera) :
ViewportController::ViewportController(Input &input, Camera &camera) :
input(input),
camera(camera) {
this->cb = input.addScrollCallback([&](int delta) { distance = fmin(fmax(distance - delta * (distance / 6), 1.1), 20); });
}
void ViewportControl::update() {
void ViewportController::update() {
if (input.keyDown(GLFW_MOUSE_BUTTON_MIDDLE)) {
input.setMouseLocked(true);
yaw += -input.mouseDelta().x * panFactor;
@ -29,6 +29,15 @@ void ViewportControl::update() {
}
else input.setMouseLocked(false);
if (input.keyDown(GLFW_KEY_RIGHT))
yaw += arrowFactor;
if (input.keyDown(GLFW_KEY_LEFT))
yaw -= arrowFactor;
if (input.keyDown(GLFW_KEY_UP))
pitch = fmin(fmax(pitch - arrowFactor, -1.55), 1.55);
if (input.keyDown(GLFW_KEY_DOWN))
pitch = fmin(fmax(pitch + arrowFactor, -1.55), 1.55);
glm::vec3 camPos = {
distance * -sinf(yaw) * cosf(pitch),
distance * -sinf(pitch),
@ -51,6 +60,6 @@ void ViewportControl::update() {
camera.setYaw(lookYaw);
}
void ViewportControl::setViewFocus(glm::vec3 focus) {
void ViewportController::setViewFocus(glm::vec3 focus) {
this->focus = focus;
}

View File

@ -6,13 +6,14 @@
#include <memory>
#include <functional>
#include <glm/vec3.hpp>
class Input;
class Camera;
class ViewportControl {
class ViewportController {
public:
ViewportControl(Input& input, Camera& camera);
ViewportController(Input& input, Camera& camera);
void update();
void setViewFocus(glm::vec3 focus);
@ -22,6 +23,7 @@ private:
Camera& camera;
double panFactor = 0.0075;
double arrowFactor = 0.05;
double distance = 4;
glm::vec3 focus;

0
src/model/BlockFace.cpp Normal file → Executable file
View File

0
src/model/BlockFace.h Normal file → Executable file
View File

0
src/model/BlockModel.cpp Normal file → Executable file
View File

0
src/model/BlockModel.h Normal file → Executable file
View File

0
src/model/BlockModelInstance.cpp Normal file → Executable file
View File

0
src/model/BlockModelInstance.h Normal file → Executable file
View File

84
src/model/BlockModelManager.cpp Normal file → Executable file
View File

@ -3,8 +3,6 @@
//
#include <glm/glm.hpp>
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include "BlockModel.h"
#include "BlockModelManager.h"
@ -13,8 +11,7 @@
#include "../graph/Camera.h"
#include "../graph/Window.h"
#include "../graph/Renderer.h"
#include "../input/ViewportControl.h"
#include "../input/Ray.h"
#include "../input/ViewportController.h"
BlockModelManager::BlockModelManager(Camera* camera, Window* window) :
dirt("../assets/textures/dirt.png"),
@ -22,66 +19,39 @@ BlockModelManager::BlockModelManager(Camera* camera, Window* window) :
window(window) {
models.emplace_back(std::make_shared<BlockModel>());
instances.emplace_back(models[0]);
instances.emplace_back(models[0]);
instances.emplace_back(models[0]);
// instances.emplace_back(models[0]);
// instances.emplace_back(models[0]);
// instances.emplace_back(models[0]);
// instances.emplace_back(models[0]);
instances[1].setPos({1, 0, 0});
instances[2].setPos({-1, 0, 0});
// instances[3].setPos({0, 0, 1});
// instances[4].setPos({0, 0, -1});
// instances[5].setPos({0, 1, 0});
// instances[6].setPos({0, -1, 0});
}
void BlockModelManager::update(Input& input, ViewportControl& viewport) {
for (auto& instance : instances) instance.setHighlighted(false);
if (!editingModel) {
glm::vec3 dir = Ray::worldRayFromCursor(*window, *camera);
glm::vec3 ray = camera->getPos();
bool found = false;
float dis = 0.05f;
while (dis < 20) {
glm::vec3 end = ray + (dir * dis);
glm::ivec3 blockSpace = glm::floor(end + glm::vec3(0.5));
for (auto& instance : instances) {
if (instance.getPos() == blockSpace) {
instance.setHighlighted(true);
if (input.keyPressed(GLFW_MOUSE_BUTTON_LEFT)) {
viewport.setViewFocus(instance.getPos());
setEditingModel(instance);
}
found = true;
break;
}
}
if (found) break;
dis += 0.05;
}
}
else editingInstance->update(viewport, *window, *camera);
}
void BlockModelManager::render(Renderer &renderer) {
dirt.use();
for (auto& instance : instances)
if (!editingModel || editingPos != instance.getPos()) instance.render(renderer);
if (!editingModel || editingPos != instance.getPos())
instance.render(renderer);
if (editingInstance) editingInstance->render(renderer);
}
void BlockModelManager::setEditingModel(BlockModelInstance& instance) {
editingPos = instance.getPos();
editingModel = instance.getModel();
editingInstance = std::make_shared<EditingBlockModel>(editingPos, editingModel);
std::shared_ptr<BlockModel> BlockModelManager::getEditingModel() {
return editingModel;
}
void BlockModelManager::setEditingInstance(glm::ivec3 pos) {
for (auto& instance : instances) {
if (instance.getPos() != pos) continue;
editingPos = instance.getPos();
editingModel = instance.getModel();
editingInstance = std::make_shared<EditingBlockModel>(editingPos, editingModel);
break;
}
}
bool BlockModelManager::highlightInstanceAtPos(glm::ivec3 pos) {
for (auto& instance : instances) {
instance.setHighlighted(instance.getPos() == pos);
if (instance.getPos() == pos) return true;
}
return false;
}

7
src/model/BlockModelManager.h Normal file → Executable file
View File

@ -12,17 +12,18 @@ class Input;
class Camera;
class Window;
class Renderer;
class ViewportControl;
class ViewportController;
class EditingBlockModel;
class BlockModelManager {
public:
BlockModelManager(Camera* camera, Window* window);
void update(Input& input, ViewportControl& viewport);
void render(Renderer& renderer);
void setEditingModel(BlockModelInstance& instance);
bool highlightInstanceAtPos(glm::ivec3 pos);
std::shared_ptr<BlockModel> getEditingModel();
void setEditingInstance(glm::ivec3 pos);
std::vector<std::shared_ptr<BlockModel>> models;
std::vector<BlockModelInstance> instances;

94
src/model/EditingBlockModel.cpp Normal file → Executable file
View File

@ -4,11 +4,13 @@
#include <glm/mat4x4.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include "EditingBlockModel.h"
#include "BlockModel.h"
#include "../input/Ray.h"
#include "../util/Ray.h"
#include "../graph/Renderer.h"
EditingBlockModel::EditingBlockModel(glm::vec3 pos, std::shared_ptr<BlockModel> model) :
@ -17,21 +19,11 @@ EditingBlockModel::EditingBlockModel(glm::vec3 pos, std::shared_ptr<BlockModel>
updateFaces();
}
void EditingBlockModel::update(ViewportControl &viewport, Window &window, Camera &camera) {
glm::vec3 dir = Ray::worldRayFromCursor(window, camera);
glm::vec3 ray = camera.getPos();
int ind = -1;
float smallestDistance = 1000;
for (int i = 0; i < faces.size(); i++) {
facesHighlighted[i] = false;
float dist = Ray::rayInterceptsRect(ray, dir, this->model->faces[i].points, pos);
if (dist != 0 && dist < smallestDistance) {
smallestDistance = dist;
ind = i;
}
}
if (ind != -1) facesHighlighted[ind] = true;
void EditingBlockModel::update(ViewportController &viewport, Window &window, Camera &camera) {
if (!highlightedFace || !window.getInput().keyDown(GLFW_MOUSE_BUTTON_LEFT))
holdOrigin = findHoveredFace(viewport, window, camera);
else if (highlightedFace)
manipulateFace(viewport, window, camera);
}
void EditingBlockModel::render(Renderer &renderer) {
@ -45,6 +37,75 @@ void EditingBlockModel::render(Renderer &renderer) {
}
}
glm::vec3 EditingBlockModel::findHoveredFace(ViewportController &viewport, Window &window, Camera &camera) {
glm::vec3 dir = Ray::worldRayFromCursor(window, camera);
glm::vec3 ray = camera.getPos();
int ind = -1;
float smallestDistance = 1000;
glm::vec3 targetPos;
for (int i = 0; i < faces.size(); i++) {
facesHighlighted[i] = false;
float dist;
glm::vec3 intPos;
Ray::rayInterceptsRect(ray, dir, this->model->faces[i].points, pos, dist, intPos);
if (dist != 0 && dist < smallestDistance) {
smallestDistance = dist;
targetPos = intPos;
ind = i;
}
}
if (ind != -1) {
highlightedFace = &this->model->faces[ind];
this->facesHighlighted[ind] = true;
}
else highlightedFace = nullptr;
return targetPos;
}
void EditingBlockModel::manipulateFace(ViewportController &viewport, Window &window, Camera &camera) {
if (window.getInput().keyDown(GLFW_MOUSE_BUTTON_LEFT)) {
glm::vec3 ray = camera.getPos();
glm::vec3 dir = Ray::worldRayFromCursor(window, camera);
glm::vec3 nml = glm::normalize(glm::cross(highlightedFace->points[1] - highlightedFace->points[0],
highlightedFace->points[3] - highlightedFace->points[0]));
// Get ray to be on plane determined by the camera view-angle.
auto lookVec = glm::abs(Ray::lookVecFromCamera(camera));
float b = lookVec.x > lookVec.y ? lookVec.x > lookVec.z ? 0 : 2 : lookVec.y > lookVec.z ? 1 : 2;
// Looking head-on at face, use a different lock value.
if (nml[b] != 0) b = b == 1 ? 0 : 1;
if (ray[b] < holdOrigin[b]) {
while (ray[b] < holdOrigin[b]) ray += dir;
while (ray[b] > holdOrigin[b]) ray -= dir / 20.f;
}
else {
while (ray[b] > holdOrigin[b]) ray += dir;
while (ray[b] < holdOrigin[b]) ray -= dir / 20.f;
}
ray[b] = holdOrigin[b];
for (auto& point : highlightedFace->points) {
glm::vec3 diff = ray - point - pos;
if (true) diff = glm::vec3(glm::ivec3(diff * 16.f)) / 16.f;
point += diff * glm::abs(nml);
}
std::cout << nml.x << ", " << nml.y << ", " << nml.z << std::endl;
std::cout << b << std::endl;
updateFaces();
}
}
void EditingBlockModel::updateFaces() {
faces.clear();
facesHighlighted.clear();
@ -59,4 +120,5 @@ void EditingBlockModel::updateFaces() {
faces.push_back(mesh);
facesHighlighted.push_back(false);
}
model->updateMesh();
}

11
src/model/EditingBlockModel.h Normal file → Executable file
View File

@ -8,26 +8,33 @@
#include <vector>
#include "../graph/Mesh.h"
#include "BlockFace.h"
class Window;
class Camera;
class Renderer;
class BlockModel;
class ViewportControl;
class ViewportController;
class EditingBlockModel {
public:
EditingBlockModel(glm::vec3 pos, std::shared_ptr<BlockModel> model);
void update(ViewportControl &viewport, Window &window, Camera &camera);
void update(ViewportController &viewport, Window &window, Camera &camera);
void render(Renderer& renderer);
private:
glm::vec3 findHoveredFace(ViewportController &viewport, Window &window, Camera &camera);
void manipulateFace(ViewportController &viewport, Window &window, Camera &camera);
void updateFaces();
glm::vec3 pos;
std::shared_ptr<BlockModel> model;
BlockFace* highlightedFace = nullptr;
glm::vec3 holdOrigin;
std::vector<BlockMesh> faces;
std::vector<bool> facesHighlighted;
};

45
src/input/Ray.h → src/util/Ray.h Normal file → Executable file
View File

@ -10,6 +10,14 @@
#include "../graph/Camera.h"
namespace Ray {
static glm::vec3 lookVecFromCamera(Camera& camera) {
return glm::normalize(glm::vec3 {
cos(camera.getYaw()) * cos(camera.getPitch()),
sin(camera.getPitch()),
sin(camera.getYaw()) * cos(camera.getPitch()),
});
}
static glm::vec3 worldRayFromCursor(Window &window, Camera &camera) {
return glm::vec3(glm::inverse(camera.getViewMatrix()) *
glm::vec4(glm::vec2(glm::inverse(camera.getProjectionMatrix()) * glm::vec4 {
@ -17,7 +25,9 @@ namespace Ray {
1.f - (2.f * window.getInput().mousePos().y) / window.getSize().y, -1.f, 1.f }), -1.0, 0.0));
}
static float rayInterceptsRect(glm::vec3 rayOrigin, glm::vec3 rayDir, std::array<glm::vec3, 4> p, glm::vec3 pO = {}) {
static void rayInterceptsRect(glm::vec3 rayOrigin, glm::vec3 rayDir,
std::array<glm::vec3, 4> p, glm::vec3 pO, float& intDist, glm::vec3& intPos) {
rayDir = glm::normalize(rayDir);
rayOrigin -= pO;
glm::vec3 v1 = p[1] - p[0];
@ -27,7 +37,11 @@ namespace Ray {
float D = -glm::dot(n, p[0]);
float t = -(glm::dot(n, rayOrigin) + D) / (glm::dot(n, rayDir));
if (t < 0) return 0;
if (t < 0) {
intDist = 0;
intPos = {};
return;
}
glm::vec3 intercepts = rayOrigin + rayDir * t;
// First pass
@ -36,21 +50,38 @@ namespace Ray {
glm::vec3 v4 = glm::normalize(intercepts - p[0]);
glm::vec3 v5 = glm::normalize(intercepts - p[2]);
if (!(glm::dot(v1, v4) >= 0 && glm::dot(v3, v5) >= 0)) return 0;
if (!(glm::dot(v1, v4) >= 0 && glm::dot(v3, v5) >= 0)) {
intDist = 0;
intPos = {};
return;
}
// Second pass
v2 = glm::normalize(v2);
glm::vec3 v6 = glm::normalize(p[0] - p[3]);
glm::vec3 v7 = glm::normalize(intercepts - p[1]);
glm::vec3 v8 = glm::normalize(intercepts - p[3]);
glm::vec3 v8 = intercepts - p[3];
if (!(glm::dot(v2, v7) >= 0 && glm::dot(v6, v8) >= 0)) return 0;
return t;
if (!(glm::dot(v2, v7) >= 0 && glm::dot(v6, v8) >= 0)) {
intDist = 0;
intPos = {};
return;
};
intDist = t;
intPos = intercepts;
}
static float rayInterceptsRectDist(glm::vec3 rayOrigin, glm::vec3 rayDir, std::array<glm::vec3, 4> p, glm::vec3 pO = {}) {
float dist;
glm::vec3 pos;
rayInterceptsRect(rayOrigin, rayDir, p, pO, dist, pos);
return dist;
}
static bool rayInterceptsRects(glm::vec3 rayOrigin, glm::vec3 rayDir, std::vector<std::array<glm::vec3, 4>> pointsVec, glm::vec3 pO = {}) {
for (auto& p : pointsVec)
if (rayInterceptsRect(rayOrigin, rayDir, p, pO)) return true;
if (rayInterceptsRectDist(rayOrigin, rayDir, p, pO)) return true;
return false;
}
}