I have tried going back to C++ after long time of mainly doing C#. I realize that the code is far from perfect, however I would really appreciate if someone could point of what exactly is wrong and how to fix it, so I can learn how things should be done. (just for code design, not asking to fix any logic errors)
What it does, is generating a Mesh from noise data (minecraft like game terrain) and creating chunks on runtime through threading. It has basic lightning and texture arrays implemented.
Files that were not written by me and shouldn't be reviewed:
anything that starts with imgui
glsl.h/cpp
I will be very thankful on your opinions how to fix this codes design.
https://github.com/AleCie/NGine
Now, I don't know if it is allowed to ask for a review of code on github, but I hope this won't be an issue, since it is asking me to input at least three lines of code here, I will post Chunk.h file to give you some idea what you will be dealing with.
Edit: Including code for review over here as suggested with posting guidelines:
Chunk.h
#pragma once
#include <memory>
#include <glm/glm.hpp>
#include "Shader.h"
#include "Texture.h"
#include "Mesh.h"
#include <thread>
#include <future>
class Camera;
class Chunk
{
public:
Chunk();
~Chunk();
void Create(glm::vec3 position, std::shared_ptr<Shader> shader);
void Update(Camera* cam, float dt);
void Render(Camera *cam);
//void RebuildMesh();
glm::vec3 GetPosition();
glm::mat4 GetWorldMatrix();
static const int ChunkSize = 16;
float NoiseTreshold = 0.0f;
float NoiseScale = 1.0f;
static int GlobalChunkVertexCount;
bool ShouldBeDeleted = false;
int Data[ChunkSize][ChunkSize][ChunkSize];
std::weak_ptr<Chunk> TopChunk;
std::weak_ptr<Chunk> BottomChunk;
std::weak_ptr<Chunk> LeftChunk;
std::weak_ptr<Chunk> RightChunk;
std::weak_ptr<Chunk> FrontChunk;
std::weak_ptr<Chunk> BackChunk;
bool ShouldRebuild = false;
private:
void Create();
void CleanMesh();
void CreateVoxelData();
void CreateMesh();
void CreateOpenGLMesh();
void CreateChunkThreadFunc(bool& result, std::atomic<bool>& shouldTerminate, std::atomic<bool>& wasTerminated);
bool ShouldAddTop(int x, int y, int z);
bool ShouldAddBottom(int x, int y, int z);
bool ShouldAddLeft(int x, int y, int z);
bool ShouldAddRight(int x, int y, int z);
bool ShouldAddFront(int x, int y, int z);
bool ShouldAddBack(int x, int y, int z);
void AddTopFace(int x, int y, int z, int& idx);
void AddBottomFace(int x, int y, int z, int& idx);
void AddFrontFace(int x, int y, int z, int& idx);
void AddBackFace(int x, int y, int z, int& idx);
void AddLeftFace(int x, int y, int z, int& idx);
void AddRightFace(int x, int y, int z, int& idx);
std::unique_ptr<Mesh> ChunkMesh;
std::shared_ptr<Shader> ChunkShader;
glm::vec3 Position = glm::vec3(0);
bool IsChunkEmpty = true;
bool DidThreadFinish = false;
bool WasMeshCreated = false;
std::thread ChunkThread;
std::atomic<bool> ShouldTerminateThread = false;
std::atomic<bool> WasThreadTerminated = false;
};
Chunk.cpp
#include "Chunk.h"
#include <functional>
#include "Camera.h"
#include "ChunkManager.h"
#include "Filepath.h"
#include <glm/ext/matrix_transform.hpp>
#include "FastNoiseSIMD/FastNoiseSIMD.h"
//#include <pthread.h>
int Chunk::GlobalChunkVertexCount = 0;
Chunk::Chunk()
{
}
Chunk::~Chunk()
{
//pthread_cancel(ChunkThread);
}
void Chunk::CreateChunkThreadFunc(bool &result, std::atomic<bool>& shouldTerminate, std::atomic<bool>& wasTerminated)
{
if (ShouldTerminateThread == true)
{
wasTerminated = true;
return;
}
CreateVoxelData();
if (ShouldTerminateThread == true)
{
wasTerminated = true;
return;
}
CreateMesh();
if (ShouldTerminateThread == true)
{
wasTerminated = true;
return;
}
wasTerminated = true;
result = true;
}
void Chunk::Create(glm::vec3 position, std::shared_ptr<Shader> shader)
{
Position = position;
ChunkShader = shader;
/*auto f = [&](bool &b) {
CreateVoxelData();
CreateMesh();
b = true;
};*/
//std::thread t1(&Chunk::CreateChunkThreadFunc, std::ref(DidThreadFinish));
//std::thread t1([this, &DidThreadFinish]() { this->CreateChunkThreadFunc(DidThreadFinish); });
//std::thread t1(std::mem_fun(&Chunk::CreateChunkThreadFunc), this, std::ref(DidThreadFinish)));
ChunkThread = std::thread([this]() { this->CreateChunkThreadFunc(this->DidThreadFinish, this->ShouldTerminateThread, this->WasThreadTerminated); });
ChunkThread.detach();
//t1.join();
//ChunkShader = std::unique_ptr<Shader>(new Shader((fp::ShadersFolder + shaderName + fp::ExtVertex).c_str(), (fp::ShadersFolder + shaderName + fp::ExtFragment).c_str()));
}
void Chunk::Update(Camera *cam, float dt)
{
if (DidThreadFinish == true && WasMeshCreated == false)
{
CreateOpenGLMesh();
//std::cout << "Vertex count: " << Chunk::GlobalChunkVertexCount << std::endl;
WasMeshCreated = true;
}
// get distance
glm::vec3 distance = Position - cam->GetPosition();
bool shouldDelete = false;
if (distance.x > ChunkManager::ChunkGenRadius * Chunk::ChunkSize)
{
shouldDelete = true;
}
if (distance.y > ChunkManager::ChunkGenRadius * Chunk::ChunkSize)
{
shouldDelete = true;
}
if (distance.z > ChunkManager::ChunkGenRadius * Chunk::ChunkSize)
{
shouldDelete = true;
}
// flags for object deletion
// erase if too big (first terminate thread
if (shouldDelete)
{
//ShouldBeDeleted = true;
ShouldTerminateThread = true;
//ChunkThread.join();
}
if (WasThreadTerminated == true && shouldDelete)
{
ShouldBeDeleted = true;
}
//flags for mesh rebuild
if (ShouldRebuild)
{
if (WasThreadTerminated == false || DidThreadFinish == false)
{
//ShouldTerminateThread = true;
}
else
{
CleanMesh();
Create();
ShouldRebuild = false;
}
}
}
void Chunk::Render(Camera *cam)
{
if (IsChunkEmpty == false && DidThreadFinish == true && WasMeshCreated == true)
{
ChunkMesh->Render(ChunkShader.get(), cam);
}
}
/*void Chunk::RebuildMesh()
{
IsChunkEmpty = true;
ChunkMesh->Vertices.clear();
ChunkMesh->Indices.clear();
ChunkMesh->Normals.clear();
ChunkMesh->UVs.clear();
ChunkMesh.reset();
CreateVoxelData();
CreateMesh();
}*/
glm::vec3 Chunk::GetPosition()
{
return Position;
}
glm::mat4 Chunk::GetWorldMatrix()
{
return ChunkMesh->WorldMatrix;
}
void Chunk::Create()
{
ChunkThread = std::thread([this]() { this->CreateChunkThreadFunc(this->DidThreadFinish, this->ShouldTerminateThread, this->WasThreadTerminated); });
ChunkThread.detach();
}
void Chunk::CleanMesh()
{
IsChunkEmpty = true;
ChunkMesh->Vertices.clear();
ChunkMesh->Indices.clear();
ChunkMesh->Normals.clear();
ChunkMesh->UVs.clear();
ChunkMesh.reset();
}
void Chunk::CreateVoxelData()
{
FastNoiseSIMD* myNoise = FastNoiseSIMD::NewFastNoiseSIMD();
// Get a set of 16 x 16 x 16 Simplex Fractal noise
float* noiseSet = myNoise->GetSimplexFractalSet(Position.x, Position.y, Position.z, ChunkSize, ChunkSize, ChunkSize, NoiseScale);
int noiseIdx = 0;
for (int x = 0; x < ChunkSize; x++)
{
for (int y = 0; y < ChunkSize; y++)
{
for (int z = 0; z < ChunkSize; z++)
{
if (noiseSet[noiseIdx] > NoiseTreshold)
{
Data[x][y][z] = 0;
}
else
{
Data[x][y][z] = -1;
}
noiseIdx++;
/*if (y < 8)
{
if (x < 6 && z < 6)
{
Data[x][y][z] = 0;
}
else
{
Data[x][y][z] = 1;
}
}
else if ( y > 8)
{
Data[x][y][z] = -1;
}
if (y == 9 || y == 10)
{
if (x > 4 && x < 12 && z > 4 && z < 12)
{
Data[x][y][z] = 1;
}
}*/
}
}
}
FastNoiseSIMD::FreeNoiseSet(noiseSet);
}
void Chunk::CreateMesh()
{
ChunkMesh = std::unique_ptr<Mesh>(new Mesh());
ChunkMesh->IndicesEnabled = true;
ChunkMesh->UVsEnabled = true;
ChunkMesh->UVsAttribute = 1;
ChunkMesh->NormalsEnabled = true;
ChunkMesh->NormalsAttribute = 2;
ChunkMesh->TexIDEnabled = true;
ChunkMesh->TexIDAttribute = 3;
int idx = 0;
for (int x = 0; x < ChunkSize; x++)
{
for (int y = 0; y < ChunkSize; y++)
{
for (int z = 0; z < ChunkSize; z++)
{
if (Data[x][y][z] >= 0) // voxel exists
{
if (ShouldAddTop(x, y, z)) AddTopFace(x, y, z, idx);
if (ShouldAddBottom(x, y, z)) AddBottomFace(x, y, z, idx);
if (ShouldAddFront(x, y, z)) AddFrontFace(x, y, z, idx);
if (ShouldAddBack(x, y, z)) AddBackFace(x, y, z, idx);
if (ShouldAddLeft(x, y, z)) AddLeftFace(x, y, z, idx);
if (ShouldAddRight(x, y, z)) AddRightFace(x, y, z, idx);
}
//if (ShouldAddTop(x, y, z)) AddTopFace(x, y, z, idx);
}
}
}
}
void Chunk::CreateOpenGLMesh()
{
GlobalChunkVertexCount += ChunkMesh->Vertices.size();
if (ChunkMesh->Vertices.size() > 0)
{
ChunkMesh->Create(ChunkShader.get());
IsChunkEmpty = false;
}
else
{
IsChunkEmpty = true;
}
ChunkMesh->WorldMatrix = glm::translate(ChunkMesh->WorldMatrix, Position);
}
bool Chunk::ShouldAddTop(int x, int y, int z)
{
if (y + 1 >= ChunkSize)
{
// out of bounds, decide if should display quad, or fetch data from child chunk if exists
if (auto tch = TopChunk.lock()) //top chunk exist, check value from there
{
if (tch->Data[x][0][z] >= 0) // voxel in top chunk is full, dont display
{
return false;
}
else
{
return true;
}
}
else
{
return true;
}
}
if (Data[x][y + 1][z] >= 0) // if Data is greater than zero, means there is a voxel there, so should not add that face
{
return false;
}
else
{
return true;
}
}
bool Chunk::ShouldAddBottom(int x, int y, int z)
{
if (y - 1 < 0)
{
// out of bounds, decide if should display quad, or fetch data from child chunk if exists
if (auto bch = BottomChunk.lock()) //top chunk exist, check value from there
{
if (bch->Data[x][Chunk::ChunkSize - 1][z] >= 0) // voxel in top chunk is full, dont display
{
return false;
}
else
{
return true;
}
}
else
{
return true;
}
}
if (Data[x][y - 1][z] >= 0) // if Data is greater than zero, means there is a voxel to display
{
return false;
}
else
{
return true;
}
}
bool Chunk::ShouldAddLeft(int x, int y, int z)
{
if (x - 1 < 0)
{
// out of bounds, decide if should display quad, or fetch data from child chunk if exists
if (auto lch = LeftChunk.lock()) //top chunk exist, check value from there
{
if (lch->Data[Chunk::ChunkSize - 1][y][z] >= 0) // voxel in top chunk is full, dont display
{
return false;
}
else
{
return true;
}
}
else
{
return true;
}
}
if (Data[x - 1][y][z] >= 0) // if Data is greater than zero, means there is a voxel to display
{
return false;
}
else
{
return true;
}
}
bool Chunk::ShouldAddRight(int x, int y, int z)
{
if (x + 1 >= ChunkSize)
{
// out of bounds, decide if should display quad, or fetch data from child chunk if exists
if (auto rch = RightChunk.lock()) //top chunk exist, check value from there
{
if (rch->Data[0][y][z] >= 0) // voxel in top chunk is full, dont display
{
return false;
}
else
{
return true;
}
}
else
{
return true;
}
}
if (Data[x + 1][y][z] >= 0) // if Data is greater than zero, means there is a voxel to display
{
return false;
}
else
{
return true;
}
}
bool Chunk::ShouldAddFront(int x, int y, int z)
{
if (z + 1 >= ChunkSize)
{
// out of bounds, decide if should display quad, or fetch data from child chunk if exists
if (auto fch = FrontChunk.lock()) //top chunk exist, check value from there
{
if (fch->Data[x][y][Chunk::ChunkSize - 1] >= 0) // voxel in top chunk is full, dont display
{
return false;
}
else
{
return true;
}
}
else
{
return true;
}
}
if (Data[x][y][z + 1] >= 0) // if Data is greater than zero, means there is a voxel to display
{
return false;
}
else
{
return true;
}
}
bool Chunk::ShouldAddBack(int x, int y, int z)
{
if (z - 1 < 0)
{
// out of bounds, decide if should display quad, or fetch data from child chunk if exists
if (auto bch = BackChunk.lock()) //top chunk exist, check value from there
{
if (bch->Data[x][y][0] >= 0) // voxel in top chunk is full, dont display
{
return false;
}
else
{
return true;
}
}
else
{
return true;
}
}
if (Data[x][y][z - 1] >= 0) // if Data is greater than zero, means there is a voxel to display
{
return false;
}
else
{
return true;
}
}
void Chunk::AddTopFace(int x, int y, int z, int& idx)
{
// top face verts
ChunkMesh->Vertices.push_back(1 + x); ChunkMesh->Vertices.push_back(1 + y); ChunkMesh->Vertices.push_back(1 + z);
ChunkMesh->Vertices.push_back(1 + x); ChunkMesh->Vertices.push_back(1 + y); ChunkMesh->Vertices.push_back(0 + z);
ChunkMesh->Vertices.push_back(0 + x); ChunkMesh->Vertices.push_back(1 + y); ChunkMesh->Vertices.push_back(0 + z);
ChunkMesh->Vertices.push_back(0 + x); ChunkMesh->Vertices.push_back(1 + y); ChunkMesh->Vertices.push_back(1 + z);
// indices
ChunkMesh->Indices.push_back(idx + 0); ChunkMesh->Indices.push_back(idx + 1); ChunkMesh->Indices.push_back(idx + 3);
ChunkMesh->Indices.push_back(idx + 1); ChunkMesh->Indices.push_back(idx + 2); ChunkMesh->Indices.push_back(idx + 3);
idx += 4;
// normals
ChunkMesh->Normals.push_back(0); ChunkMesh->Normals.push_back(1); ChunkMesh->Normals.push_back(0);
ChunkMesh->Normals.push_back(0); ChunkMesh->Normals.push_back(1); ChunkMesh->Normals.push_back(0);
ChunkMesh->Normals.push_back(0); ChunkMesh->Normals.push_back(1); ChunkMesh->Normals.push_back(0);
ChunkMesh->Normals.push_back(0); ChunkMesh->Normals.push_back(1); ChunkMesh->Normals.push_back(0);
// uvs
ChunkMesh->UVs.push_back(0); ChunkMesh->UVs.push_back(0);
ChunkMesh->UVs.push_back(1); ChunkMesh->UVs.push_back(0);
ChunkMesh->UVs.push_back(1); ChunkMesh->UVs.push_back(1);
ChunkMesh->UVs.push_back(0); ChunkMesh->UVs.push_back(1);
// texid
ChunkMesh->TexIDs.push_back((float)Data[x][y][z]);
ChunkMesh->TexIDs.push_back((float)Data[x][y][z]);
ChunkMesh->TexIDs.push_back((float)Data[x][y][z]);
ChunkMesh->TexIDs.push_back((float)Data[x][y][z]);
}
void Chunk::AddBottomFace(int x, int y, int z, int& idx)
{
// bottom face
ChunkMesh->Vertices.push_back(1 + x); ChunkMesh->Vertices.push_back(y); ChunkMesh->Vertices.push_back(1 + z);
ChunkMesh->Vertices.push_back(1 + x); ChunkMesh->Vertices.push_back(y); ChunkMesh->Vertices.push_back(0 + z);
ChunkMesh->Vertices.push_back(0 + x); ChunkMesh->Vertices.push_back(y); ChunkMesh->Vertices.push_back(0 + z);
ChunkMesh->Vertices.push_back(0 + x); ChunkMesh->Vertices.push_back(y); ChunkMesh->Vertices.push_back(1 + z);
// bottom
ChunkMesh->Indices.push_back(idx + 3); ChunkMesh->Indices.push_back(idx + 1); ChunkMesh->Indices.push_back(idx + 0);
ChunkMesh->Indices.push_back(idx + 3); ChunkMesh->Indices.push_back(idx + 2); ChunkMesh->Indices.push_back(idx + 1);
idx += 4;
ChunkMesh->Normals.push_back(0); ChunkMesh->Normals.push_back(-1); ChunkMesh->Normals.push_back(0);
ChunkMesh->Normals.push_back(0); ChunkMesh->Normals.push_back(-1); ChunkMesh->Normals.push_back(0);
ChunkMesh->Normals.push_back(0); ChunkMesh->Normals.push_back(-1); ChunkMesh->Normals.push_back(0);
ChunkMesh->Normals.push_back(0); ChunkMesh->Normals.push_back(-1); ChunkMesh->Normals.push_back(0);
// uvs
ChunkMesh->UVs.push_back(0); ChunkMesh->UVs.push_back(0);
ChunkMesh->UVs.push_back(1); ChunkMesh->UVs.push_back(0);
ChunkMesh->UVs.push_back(1); ChunkMesh->UVs.push_back(1);
ChunkMesh->UVs.push_back(0); ChunkMesh->UVs.push_back(1);
// texid
ChunkMesh->TexIDs.push_back((float)Data[x][y][z]);
ChunkMesh->TexIDs.push_back((float)Data[x][y][z]);
ChunkMesh->TexIDs.push_back((float)Data[x][y][z]);
ChunkMesh->TexIDs.push_back((float)Data[x][y][z]);
}
void Chunk::AddFrontFace(int x, int y, int z, int& idx)
{
// front face verts
ChunkMesh->Vertices.push_back(1 + x); ChunkMesh->Vertices.push_back(1 + y); ChunkMesh->Vertices.push_back(z + 1);
ChunkMesh->Vertices.push_back(1 + x); ChunkMesh->Vertices.push_back(y); ChunkMesh->Vertices.push_back(z + 1);
ChunkMesh->Vertices.push_back(0 + x); ChunkMesh->Vertices.push_back(y); ChunkMesh->Vertices.push_back(z + 1);
ChunkMesh->Vertices.push_back(0 + x); ChunkMesh->Vertices.push_back(1 + y); ChunkMesh->Vertices.push_back(z + 1);
// indices
ChunkMesh->Indices.push_back(idx + 3); ChunkMesh->Indices.push_back(idx + 1); ChunkMesh->Indices.push_back(idx + 0);
ChunkMesh->Indices.push_back(idx + 3); ChunkMesh->Indices.push_back(idx + 2); ChunkMesh->Indices.push_back(idx + 1);
idx += 4;
// normals
ChunkMesh->Normals.push_back(0); ChunkMesh->Normals.push_back(0); ChunkMesh->Normals.push_back(1);
ChunkMesh->Normals.push_back(0); ChunkMesh->Normals.push_back(0); ChunkMesh->Normals.push_back(1);
ChunkMesh->Normals.push_back(0); ChunkMesh->Normals.push_back(0); ChunkMesh->Normals.push_back(1);
ChunkMesh->Normals.push_back(0); ChunkMesh->Normals.push_back(0); ChunkMesh->Normals.push_back(1);
// uvs
ChunkMesh->UVs.push_back(0); ChunkMesh->UVs.push_back(0);
ChunkMesh->UVs.push_back(1); ChunkMesh->UVs.push_back(0);
ChunkMesh->UVs.push_back(1); ChunkMesh->UVs.push_back(1);
ChunkMesh->UVs.push_back(0); ChunkMesh->UVs.push_back(1);
// texid
ChunkMesh->TexIDs.push_back((float)Data[x][y][z]);
ChunkMesh->TexIDs.push_back((float)Data[x][y][z]);
ChunkMesh->TexIDs.push_back((float)Data[x][y][z]);
ChunkMesh->TexIDs.push_back((float)Data[x][y][z]);
}
void Chunk::AddBackFace(int x, int y, int z, int& idx)
{
// back face
ChunkMesh->Vertices.push_back(1 + x); ChunkMesh->Vertices.push_back(1 + y); ChunkMesh->Vertices.push_back(z);
ChunkMesh->Vertices.push_back(1 + x); ChunkMesh->Vertices.push_back(y); ChunkMesh->Vertices.push_back(z);
ChunkMesh->Vertices.push_back(0 + x); ChunkMesh->Vertices.push_back(y); ChunkMesh->Vertices.push_back(z);
ChunkMesh->Vertices.push_back(0 + x); ChunkMesh->Vertices.push_back(1 + y); ChunkMesh->Vertices.push_back(z);
// back
ChunkMesh->Indices.push_back(idx + 0); ChunkMesh->Indices.push_back(idx + 1); ChunkMesh->Indices.push_back(idx + 3);
ChunkMesh->Indices.push_back(idx + 1); ChunkMesh->Indices.push_back(idx + 2); ChunkMesh->Indices.push_back(idx + 3);
idx += 4;
ChunkMesh->Normals.push_back(0); ChunkMesh->Normals.push_back(0); ChunkMesh->Normals.push_back(-1);
ChunkMesh->Normals.push_back(0); ChunkMesh->Normals.push_back(0); ChunkMesh->Normals.push_back(-1);
ChunkMesh->Normals.push_back(0); ChunkMesh->Normals.push_back(0); ChunkMesh->Normals.push_back(-1);
ChunkMesh->Normals.push_back(0); ChunkMesh->Normals.push_back(0); ChunkMesh->Normals.push_back(-1);
// uvs
ChunkMesh->UVs.push_back(0); ChunkMesh->UVs.push_back(0);
ChunkMesh->UVs.push_back(1); ChunkMesh->UVs.push_back(0);
ChunkMesh->UVs.push_back(1); ChunkMesh->UVs.push_back(1);
ChunkMesh->UVs.push_back(0); ChunkMesh->UVs.push_back(1);
// texid
ChunkMesh->TexIDs.push_back((float)Data[x][y][z]);
ChunkMesh->TexIDs.push_back((float)Data[x][y][z]);
ChunkMesh->TexIDs.push_back((float)Data[x][y][z]);
ChunkMesh->TexIDs.push_back((float)Data[x][y][z]);
}
void Chunk::AddLeftFace(int x, int y, int z, int& idx)
{
// left face
ChunkMesh->Vertices.push_back(x); ChunkMesh->Vertices.push_back(1 + y); ChunkMesh->Vertices.push_back(z + 1);
ChunkMesh->Vertices.push_back(x); ChunkMesh->Vertices.push_back(y); ChunkMesh->Vertices.push_back(z + 1);
ChunkMesh->Vertices.push_back(x); ChunkMesh->Vertices.push_back(y); ChunkMesh->Vertices.push_back(z);
ChunkMesh->Vertices.push_back(x); ChunkMesh->Vertices.push_back(1 + y); ChunkMesh->Vertices.push_back(z);
// left
ChunkMesh->Indices.push_back(idx + 3); ChunkMesh->Indices.push_back(idx + 1); ChunkMesh->Indices.push_back(idx + 0);
ChunkMesh->Indices.push_back(idx + 3); ChunkMesh->Indices.push_back(idx + 2); ChunkMesh->Indices.push_back(idx + 1);
idx += 4;
ChunkMesh->Normals.push_back(-1); ChunkMesh->Normals.push_back(0); ChunkMesh->Normals.push_back(0);
ChunkMesh->Normals.push_back(-1); ChunkMesh->Normals.push_back(0); ChunkMesh->Normals.push_back(0);
ChunkMesh->Normals.push_back(-1); ChunkMesh->Normals.push_back(0); ChunkMesh->Normals.push_back(0);
ChunkMesh->Normals.push_back(-1); ChunkMesh->Normals.push_back(0); ChunkMesh->Normals.push_back(0);
// uvs
ChunkMesh->UVs.push_back(0); ChunkMesh->UVs.push_back(0);
ChunkMesh->UVs.push_back(1); ChunkMesh->UVs.push_back(0);
ChunkMesh->UVs.push_back(1); ChunkMesh->UVs.push_back(1);
ChunkMesh->UVs.push_back(0); ChunkMesh->UVs.push_back(1);
// texid
ChunkMesh->TexIDs.push_back((float)Data[x][y][z]);
ChunkMesh->TexIDs.push_back((float)Data[x][y][z]);
ChunkMesh->TexIDs.push_back((float)Data[x][y][z]);
ChunkMesh->TexIDs.push_back((float)Data[x][y][z]);
}
void Chunk::AddRightFace(int x, int y, int z, int& idx)
{
// right face
ChunkMesh->Vertices.push_back(x + 1); ChunkMesh->Vertices.push_back(1 + y); ChunkMesh->Vertices.push_back(z + 1);
ChunkMesh->Vertices.push_back(x + 1); ChunkMesh->Vertices.push_back(y); ChunkMesh->Vertices.push_back(z + 1);
ChunkMesh->Vertices.push_back(x + 1); ChunkMesh->Vertices.push_back(y); ChunkMesh->Vertices.push_back(z);
ChunkMesh->Vertices.push_back(x + 1); ChunkMesh->Vertices.push_back(1 + y); ChunkMesh->Vertices.push_back(z);
// right
ChunkMesh->Indices.push_back(idx + 0); ChunkMesh->Indices.push_back(idx + 1); ChunkMesh->Indices.push_back(idx + 3);
ChunkMesh->Indices.push_back(idx + 1); ChunkMesh->Indices.push_back(idx + 2); ChunkMesh->Indices.push_back(idx + 3);
idx += 4;
ChunkMesh->Normals.push_back(1); ChunkMesh->Normals.push_back(0); ChunkMesh->Normals.push_back(0);
ChunkMesh->Normals.push_back(1); ChunkMesh->Normals.push_back(0); ChunkMesh->Normals.push_back(0);
ChunkMesh->Normals.push_back(1); ChunkMesh->Normals.push_back(0); ChunkMesh->Normals.push_back(0);
ChunkMesh->Normals.push_back(1); ChunkMesh->Normals.push_back(0); ChunkMesh->Normals.push_back(0);
// uvs
ChunkMesh->UVs.push_back(0); ChunkMesh->UVs.push_back(0);
ChunkMesh->UVs.push_back(1); ChunkMesh->UVs.push_back(0);
ChunkMesh->UVs.push_back(1); ChunkMesh->UVs.push_back(1);
ChunkMesh->UVs.push_back(0); ChunkMesh->UVs.push_back(1);
// texid
ChunkMesh->TexIDs.push_back((float)Data[x][y][z]);
ChunkMesh->TexIDs.push_back((float)Data[x][y][z]);
ChunkMesh->TexIDs.push_back((float)Data[x][y][z]);
ChunkMesh->TexIDs.push_back((float)Data[x][y][z]);
}
ChunkManager.h
#pragma once
/*template<typename T> struct matrix
{
matrix(unsigned m, unsigned n) : m(m), n(n), vs(m* n) {}
T& operator ()(unsigned i, unsigned j) {
return vs[i + m * j];
}
private:
unsigned m;
unsigned n;
std::vector<T> vs;
};
//column-major/opengl: vs[i + m * j], row-major/c++: vs[n * i + j]
*/
#include <memory>
#include <unordered_map>
#include <map>
#include "Chunk.h"
#include <glm/glm.hpp>
#include <glm/gtx/hash.hpp>
class Shader;
class Camera;
class ChunkManager
{
public:
ChunkManager();
~ChunkManager();
void CreateFixedWorld(int width, int height, int depth, std::shared_ptr<Shader> shader);
void Update(Camera* camera, float dt);
void Render(Camera* camera);
static int ChunkGenRadius;
private:
int Width = 0, Height = 0, Depth = 0;
Chunk* Chunks;
std::shared_ptr<Shader> ChunkShader;
std::unordered_map<glm::vec3, std::shared_ptr<Chunk>> ChunkMap;
};
ChunkManager.cpp
#include "ChunkManager.h"
#include "Shader.h"
#include "Camera.h"
#include <chrono>
#include <iostream>
int ChunkManager::ChunkGenRadius = 5;
ChunkManager::ChunkManager()
{
}
ChunkManager::~ChunkManager()
{
}
void ChunkManager::CreateFixedWorld(int width, int height, int depth, std::shared_ptr<Shader> shader)
{
Width = width;
Height = height;
Depth = depth;
ChunkShader = shader;
// Record start time
auto start = std::chrono::high_resolution_clock::now();
Chunks = new Chunk[width * height * depth];
for (int x = 0; x < width; x++)
{
for (int y = 0; y < height; y++)
{
for (int z = 0; z < depth; z++)
{
Chunks[x + width * (y + depth * z)].Create(glm::vec3(x * Chunk::ChunkSize, y * Chunk::ChunkSize, z * Chunk::ChunkSize), shader);
}
}
}
auto finish = std::chrono::high_resolution_clock::now();
std::chrono::duration<double> elapsed = finish - start;
std::cout << "Elapsed time: " << elapsed.count() << " s\n";
std::cout << "Vertex count: " << Chunk::GlobalChunkVertexCount << std::endl;
}
void ChunkManager::Update(Camera* camera, float dt)
{
//figure out chunk where camera is
glm::vec3 camChunkPos = camera->GetPosition() / glm::vec3(Chunk::ChunkSize, Chunk::ChunkSize, Chunk::ChunkSize);
camChunkPos = glm::vec3(floorf(camChunkPos.x) * Chunk::ChunkSize, floorf(camChunkPos.y) * Chunk::ChunkSize, floorf(camChunkPos.z) * Chunk::ChunkSize);
// loop for theoretical chunks around camera
for (int x = -ChunkGenRadius; x < ChunkGenRadius; x++)
{
for (int y = -ChunkGenRadius; y < ChunkGenRadius; y++)
{
for (int z = -ChunkGenRadius; z < ChunkGenRadius; z++)
{
// check if chunk exists
glm::vec3 posToCheck = camChunkPos + glm::vec3(x * Chunk::ChunkSize, y * Chunk::ChunkSize, z * Chunk::ChunkSize);
auto result = ChunkMap.find(posToCheck);
if (result == ChunkMap.end()) // if doesn't exist (iterator looped through everything)
{
//create chunk
std::shared_ptr<Chunk> newChunk = std::shared_ptr<Chunk>(new Chunk());
// check surrounding chunks;
auto topResult = ChunkMap.find(posToCheck + glm::vec3(0, Chunk::ChunkSize, 0));
if (topResult != ChunkMap.end())
{
newChunk->TopChunk = topResult->second;
topResult->second->BottomChunk = newChunk;
topResult->second->ShouldRebuild = true;
}
auto bottomResult = ChunkMap.find(posToCheck + glm::vec3(0, -Chunk::ChunkSize, 0));
if (bottomResult != ChunkMap.end())
{
newChunk->BottomChunk = bottomResult->second;
bottomResult->second->TopChunk = newChunk;
bottomResult->second->ShouldRebuild = true;
}
auto leftResult = ChunkMap.find(posToCheck + glm::vec3(-Chunk::ChunkSize, 0, 0));
if (leftResult != ChunkMap.end())
{
newChunk->LeftChunk = leftResult->second;
leftResult->second->RightChunk = newChunk;
leftResult->second->ShouldRebuild = true;
}
auto rightResult = ChunkMap.find(posToCheck + glm::vec3(Chunk::ChunkSize, 0, 0));
if (rightResult != ChunkMap.end())
{
newChunk->RightChunk = rightResult->second;
rightResult->second->LeftChunk = newChunk;
rightResult->second->ShouldRebuild = true;
}
auto frontResult = ChunkMap.find(posToCheck + glm::vec3(0, 0, Chunk::ChunkSize));
if (frontResult != ChunkMap.end())
{
newChunk->FrontChunk = frontResult->second;
frontResult->second->BackChunk = newChunk;
frontResult->second->ShouldRebuild = true;
}
auto backResult = ChunkMap.find(posToCheck + glm::vec3(0, 0, -Chunk::ChunkSize));
if (backResult != ChunkMap.end())
{
newChunk->BackChunk = backResult->second;
backResult->second->FrontChunk = newChunk;
backResult->second->ShouldRebuild = true;
}
//create and assign
newChunk->Create(posToCheck, ChunkShader);
//ChunkMap.insert(std::make_pair<glm::vec3, Chunk>(posToCheck, newChunk));
ChunkMap[posToCheck] = std::move(newChunk);
}
}
}
}
for (auto it = ChunkMap.begin(); it != ChunkMap.end(); )
{
if(it->second != nullptr)
if (it->second->ShouldBeDeleted)
{
it = ChunkMap.erase(it);
}
else
{
it->second->Update(camera, dt);
++it;
}
}
}
void ChunkManager::Render(Camera* camera)
{
for (auto& [key, val] : ChunkMap)
{
val->Render(camera);
}
}
Application.h
#pragma once
// third party
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include "imgui.h"
#include "imgui_impl_glfw.h"
#include "imgui_impl_opengl3.h"
// system
#include <memory>
// custom
#include "Color.h"
#include "Camera.h"
#include "Mesh.h"
#include "CoordsGizmo.h"
#include "Texture.h"
#include "Chunk.h"
#include "ChunkManager.h"
struct DestroyGLFWwnd {
void operator()(GLFWwindow* ptr) {
glfwDestroyWindow(ptr);
}
};
typedef std::unique_ptr<GLFWwindow, DestroyGLFWwnd> sptr_GLFWwindow;
class Shader;
class glShaderManager;
class Application
{
public:
Application(int windowWidth, int windowHeight);
~Application();
void Run();
private:
void Init();
void MainLoop();
void Release();
void ProcessInput();
void UpdateLogic();
void Render();
void RenderUI();
void InitGLFW();
void InitGLEW();
void InitOGL();
void InitIMGUI();
void GLFWFramebufferSizeCallback(GLFWwindow* window, int width, int height);
void GLFWKeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods);
void CalculateDeltaTime();
void SaveLastDeltaTime();
void ClearColor();
void SwapBuffersPollEvents();
void CloseOnEsc();
void EnableCursor();
void DisableCursor();
sptr_GLFWwindow Window;
Color BackgroundColor;
int WindowWidth;
int WindowHeight;
float DeltaTime;
float LastTime;
//test
void InitTestCode();
void RenderTestCode();
unsigned int VAO;
std::unique_ptr<Shader> Sh;
Camera MainCamera;
bool IsMouseLookEnabled = true;
bool IsWireframeEnabled = false;
std::unique_ptr<Shader> ColorShader;
std::unique_ptr<Shader> TextureArrayShader;
std::shared_ptr<Shader> TexArrLightShader;
std::unique_ptr<Texture> TestTexture;
std::unique_ptr<Texture> TestTexture2;
//Mesh coordsMesh;
CoordsGizmo CoordsObj;
GLuint TextureArray;
Chunk chunk, chunk2, chunk3, chunk4;
ChunkManager ChMgr;
};
Application.cpp
#include "Application.h"
#include <iostream>
#include "Shader.h"
#include "glsl.h"
#include <glm/gtx/transform.hpp>
#include <glm/gtc/type_ptr.hpp>
using namespace std;
Application::Application(int windowWidth, int windowHeight)
: MainCamera(60.0f, 4.0f / 3.0f, 0.1f, 1000.0f)
{
WindowWidth = windowWidth;
WindowHeight = windowHeight;
BackgroundColor = Color(0.25f, 0.5f, 1, 1);
DeltaTime = 0;
LastTime = 0;
}
Application::~Application()
{
glfwTerminate();
}
void Application::Run()
{
Init();
MainLoop();
Release();
}
void Application::Init()
{
InitGLFW();
InitGLEW();
InitOGL();
InitIMGUI();
InitTestCode();
}
void Application::MainLoop()
{
while (!glfwWindowShouldClose(Window.get()))
{
CalculateDeltaTime();
ProcessInput();
UpdateLogic();
Render();
SaveLastDeltaTime();
}
}
void Application::Release()
{
}
void Application::ProcessInput()
{
CloseOnEsc();
MainCamera.HandleInput(Window.get(), DeltaTime, WindowWidth, WindowHeight);
if (IsMouseLookEnabled)
{
MainCamera.MouseLook(Window.get(), DeltaTime, WindowWidth, WindowHeight);
}
}
void Application::UpdateLogic()
{
MainCamera.Update(DeltaTime);
}
void Application::Render()
{
RenderUI();
ClearColor();
RenderTestCode();
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
SwapBuffersPollEvents();
}
float cpos[3], tpos[3];
float noiseTreshold = 0;
float noiseScale = 1;
void Application::RenderUI()
{
// Start the Dear ImGui frame
ImGui_ImplOpenGL3_NewFrame();
ImGui_ImplGlfw_NewFrame();
ImGui::NewFrame();
/*ImGui::Begin("Terrain Gen");
ImGui::SliderFloat ("treshold", &noiseTreshold, -1.0f, 1.0f);
ImGui::SliderFloat("scale", &noiseScale, 0.0f, 100.0f);
if (ImGui::Button("generate")) // Buttons return true when clicked (most widgets return true when edited/activated)
{
chunk.NoiseTreshold = noiseTreshold;
chunk2.NoiseTreshold = noiseTreshold;
chunk3.NoiseTreshold = noiseTreshold;
chunk4.NoiseTreshold = noiseTreshold;
chunk.NoiseScale = noiseScale;
chunk2.NoiseScale = noiseScale;
chunk3.NoiseScale = noiseScale;
chunk4.NoiseScale = noiseScale;
chunk.RebuildMesh();
chunk2.RebuildMesh();
chunk3.RebuildMesh();
chunk4.RebuildMesh();
}
ImGui::End();*/
// 2. Show a simple window that we create ourselves. We use a Begin/End pair to created a named window.
{
static float f = 0.0f;
static int counter = 0;
static bool hasTarget = false;
ImGui::Begin("Camera"); // Create a window called "Hello, world!" and append into it.
ImGui::Text("position");
ImGui::InputFloat3("pos", cpos);
ImGui::Checkbox("target", &hasTarget);
if (hasTarget)
{
ImGui::InputFloat3("dir", tpos);
}
if (ImGui::Button("Move")) // Buttons return true when clicked (most widgets return true when edited/activated)
{
MainCamera.SetPosition(glm::vec3(cpos[0], cpos[1], cpos[2]));
if (hasTarget)
{
glm::vec3 target = glm::vec3(cpos[0] - tpos[0], cpos[1] - tpos[1], cpos[2] - tpos[2]);
MainCamera.SetDirection(glm::normalize(target));
}
}
ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
ImGui::End();
}
// Rendering
ImGui::Render();
}
void Application::InitGLFW()
{
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); // consider switching to 2.1 with extensions for release
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, 1);
//glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // uncomment this statement to fix compilation on OS X
Window = sptr_GLFWwindow(glfwCreateWindow(WindowWidth, WindowHeight, "LearnOpenGL", NULL, NULL));
if (Window == NULL)
{
std::cout << "Failed to create GLFW window" << std::endl;
glfwTerminate();
//return -1;
}
glfwMakeContextCurrent(Window.get());
glfwSwapInterval(1);
// Ensure we can capture the escape key being pressed below
glfwSetInputMode(Window.get(), GLFW_STICKY_KEYS, GL_TRUE);
// Hide the mouse and enable unlimited mouvement
glfwSetInputMode(Window.get(), GLFW_CURSOR, GLFW_CURSOR_DISABLED);
//callbacks
glfwSetWindowUserPointer(Window.get(), this);
auto framebufferFunc = [](GLFWwindow* w, int width, int height)
{
static_cast<Application*>(glfwGetWindowUserPointer(w))->GLFWFramebufferSizeCallback(w, width, height);
};
glfwSetFramebufferSizeCallback(Window.get(), framebufferFunc);
auto keyFunc = [](GLFWwindow* w, int key, int scancode, int action, int mods)
{
static_cast<Application*>(glfwGetWindowUserPointer(w))->GLFWKeyCallback(w, key, scancode, action, mods);
};
glfwSetKeyCallback(Window.get(), keyFunc);
}
void Application::InitGLEW()
{
glewExperimental = GL_TRUE;
//init glew after the context have been made
glewInit();
// enable experimental?
GLint GlewInitResult = glewInit();
if (GLEW_OK != GlewInitResult)
{
std::cout << "GLEW INIT FAILED";
}
}
void Application::InitOGL()
{
// Enable depth test
glEnable(GL_DEPTH_TEST);
// Accept fragment if it closer to the camera than the former one
glDepthFunc(GL_LESS);
// Cull triangles which normal is not towards the camera
glEnable(GL_CULL_FACE);
glPolygonMode(GL_FRONT, GL_FILL);
glPolygonMode(GL_BACK, GL_LINE);
auto ogldebugfunc = [](GLenum source,
GLenum type,
GLuint id,
GLenum severity,
GLsizei length,
const GLchar* message,
const void* userParam) {
cout << "---------------------opengl-callback-start------------" << endl;
cout << "message: " << message << endl;
cout << "type: ";
switch (type) {
case GL_DEBUG_TYPE_ERROR:
cout << "ERROR";
break;
case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR:
cout << "DEPRECATED_BEHAVIOR";
break;
case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR:
cout << "UNDEFINED_BEHAVIOR";
break;
case GL_DEBUG_TYPE_PORTABILITY:
cout << "PORTABILITY";
break;
case GL_DEBUG_TYPE_PERFORMANCE:
cout << "PERFORMANCE";
break;
case GL_DEBUG_TYPE_OTHER:
cout << "OTHER";
break;
}
cout << endl;
cout << "id: " << id << endl;
cout << "severity: ";
switch (severity) {
case GL_DEBUG_SEVERITY_LOW:
cout << "LOW";
break;
case GL_DEBUG_SEVERITY_MEDIUM:
cout << "MEDIUM";
break;
case GL_DEBUG_SEVERITY_HIGH:
cout << "HIGH";
break;
}
cout << endl;
cout << "---------------------opengl-callback-end--------------" << endl;
};
glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
glDebugMessageCallback(ogldebugfunc, nullptr);
GLuint unusedIds = 0;
glDebugMessageControl(GL_DONT_CARE,
GL_DONT_CARE,
GL_DONT_CARE,
0,
&unusedIds,
true);
}
void Application::InitIMGUI()
{
// Setup Dear ImGui context
IMGUI_CHECKVERSION();
ImGui::CreateContext();
ImGuiIO& io = ImGui::GetIO(); (void)io;
//io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls
//io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls
// Setup Dear ImGui style
ImGui::StyleColorsDark();
//ImGui::StyleColorsClassic();
// Setup Platform/Renderer bindings
ImGui_ImplGlfw_InitForOpenGL(Window.get(), true);
ImGui_ImplOpenGL3_Init("#version 330");
}
void Application::GLFWFramebufferSizeCallback(GLFWwindow* window, int width, int height)
{
// make sure the viewport matches the new window dimensions; note that width and
// height will be significantly larger than specified on retina displays.
glViewport(0, 0, width, height);
}
void Application::GLFWKeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods)
{
if (key == GLFW_KEY_I && action == GLFW_PRESS)
{
MainCamera.SetAngles(0, 3.14f);
}
if (key == GLFW_KEY_O && action == GLFW_PRESS)
{
IsMouseLookEnabled = !IsMouseLookEnabled;
if (IsMouseLookEnabled)
{
DisableCursor();
}
else
{
EnableCursor();
}
}
if (key == GLFW_KEY_P && action == GLFW_PRESS)
{
IsWireframeEnabled = !IsWireframeEnabled;
if (IsWireframeEnabled)
{
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
//glPolygonMode(GL_BACK, GL_LINE);
}
else
{
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
}
}
}
void Application::CalculateDeltaTime()
{
DeltaTime = float((float)glfwGetTime() - LastTime);
}
void Application::SaveLastDeltaTime()
{
LastTime = DeltaTime;
}
void Application::ClearColor()
{
glClearColor(BackgroundColor.GetR(), BackgroundColor.GetG(), BackgroundColor.GetB(), BackgroundColor.GetA());
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
}
void Application::SwapBuffersPollEvents()
{
// glfw: swap buffers and poll IO events (keys pressed/released, mouse moved etc.)
// -------------------------------------------------------------------------------
glfwSwapBuffers(Window.get());
glfwPollEvents();
}
void Application::CloseOnEsc()
{
if (glfwGetKey(Window.get(), GLFW_KEY_ESCAPE) == GLFW_PRESS)
glfwSetWindowShouldClose(Window.get(), true);
}
void Application::EnableCursor()
{
glfwSetInputMode(Window.get(), GLFW_CURSOR, GLFW_CURSOR_NORMAL);
}
void Application::DisableCursor()
{
glfwSetInputMode(Window.get(), GLFW_CURSOR, GLFW_CURSOR_DISABLED);
}
void Application::InitTestCode()
{
Sh = std::unique_ptr<Shader>(new Shader("test.v", "test.f"));
TextureArrayShader = std::unique_ptr<Shader>(new Shader("Data//Shaders//texturearray.v", "Data//Shaders//texturearray.f"));
TexArrLightShader = std::shared_ptr<Shader>(new Shader("Data//Shaders//texarrlight.v", "Data//Shaders//texarrlight.f"));
TestTexture = std::unique_ptr<Texture>(new Texture("Data//Textures//dirt.jpg", GL_TEXTURE_2D));
TestTexture2 = std::unique_ptr<Texture>(new Texture("Data//Textures//stone.png", GL_TEXTURE_2D));
/*chunk.Create(glm::vec3(0), TexArrLightShader);
chunk2.Create(glm::vec3(16, 0, 0), TexArrLightShader);
chunk3.Create(glm::vec3(16, 0, 16), TexArrLightShader);
chunk4.Create(glm::vec3(0, 0, 16), TexArrLightShader);*/
int size = 8;
ChMgr.CreateFixedWorld(size, size, size, TexArrLightShader);
ColorShader = std::unique_ptr<Shader>(new Shader("Data//Shaders//color.v", "Data//Shaders//color.f"));
CoordsObj.Create(ColorShader.get());
MainCamera.SetSpeed(0.1f);
MainCamera.SetPosition(glm::vec3(0, 0, 5));
glGenTextures(1, &TextureArray);
glBindTexture(GL_TEXTURE_2D_ARRAY, TextureArray);
glTexStorage3D(GL_TEXTURE_2D_ARRAY, 1, GL_RGBA8, 512, 512, 2);//last three numbers are size of images and array
int dw, dh, sw, sh;
unsigned char* image1 = SOIL_load_image("Data//Textures//dirt.jpg", &dw, &dh, NULL, SOIL_LOAD_RGBA);
unsigned char* image2 = SOIL_load_image("Data//Textures//stone.png", &sw, &sh, NULL, SOIL_LOAD_RGBA);
glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, 0, dw, dh, 1, GL_RGBA, GL_UNSIGNED_BYTE, image1);
glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, 1, sw, sh, 1, GL_RGBA, GL_UNSIGNED_BYTE, image2);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
}
void Application::RenderTestCode()
{
CoordsObj.Render(ColorShader.get(), &MainCamera);
//TestTexture->bind(0);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D_ARRAY, TextureArray);
TexArrLightShader->bind(); // this should be done once and somewhere else
GLint modelLoc = glGetUniformLocation(TexArrLightShader->id(), "M"); //dont do that in main loop
glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(glm::mat4(1)/*chunk.GetWorldMatrix()*/));
GLint lightPosLoc = glGetUniformLocation(TexArrLightShader->id(), "lightPos"); //dont do that in main loop
GLint objectColorLoc = glGetUniformLocation(TexArrLightShader->id(), "objectColor"); //dont do that in main loop
GLint lightColorLoc = glGetUniformLocation(TexArrLightShader->id(), "lightColor"); //dont do that in main loop
GLint ambientStrenghtLoc = glGetUniformLocation(TexArrLightShader->id(), "ambientStrenght"); //dont do that in main loop
GLint camPosLoc = glGetUniformLocation(TexArrLightShader->id(), "camPos"); //dont do that in main loop
GLint cusDirLightLoc = glGetUniformLocation(TexArrLightShader->id(), "cusDirLight"); //dont do that in main loop
glUniform3f(lightPosLoc, -5.0f, 5.0f, 5.0f);
glUniform3f(objectColorLoc, 0.0f, 1.0f, 0.0f); //since it doesnt change could be done outside main loop
glUniform3f(lightColorLoc, 1.0f, 1.0f, 1.0f); //since it doesnt change could be done outside main loop
glUniform1f(ambientStrenghtLoc, 0.5f); //since it doesnt change could be done outside main loop
glUniform3f(camPosLoc, MainCamera.GetPosition().x, MainCamera.GetPosition().y, MainCamera.GetPosition().z);
glUniform3f(cusDirLightLoc, 0.5f, -1, 0.5f);
ChMgr.Update(&MainCamera, DeltaTime);
ChMgr.Render(&MainCamera);
/*chunk.Render(&MainCamera);
chunk2.Render(&MainCamera);
chunk3.Render(&MainCamera);
chunk4.Render(&MainCamera);*/
}