Browse Source

Add support for biome and level loading

master
C. J. Howard 7 years ago
parent
commit
5b7ce2f672
20 changed files with 916 additions and 200 deletions
  1. +5
    -1
      CMakeLists.txt
  2. +1
    -1
      data
  3. +1
    -1
      lib/emergent
  4. +9
    -9
      src/application.cpp
  5. +6
    -2
      src/application.hpp
  6. +7
    -0
      src/configuration.hpp.in
  7. +123
    -0
      src/game/biome.cpp
  8. +42
    -0
      src/game/biome.hpp
  9. +133
    -0
      src/game/level.cpp
  10. +35
    -0
      src/game/level.hpp
  11. +1
    -1
      src/game/navmesh.hpp
  12. +330
    -33
      src/game/terrain.cpp
  13. +75
    -12
      src/game/terrain.hpp
  14. +10
    -3
      src/materials.hpp
  15. +40
    -65
      src/render-passes.cpp
  16. +18
    -20
      src/render-passes.hpp
  17. +2
    -19
      src/states/experiment-state.cpp
  18. +12
    -7
      src/states/splash-state.cpp
  19. +61
    -25
      src/states/title-state.cpp
  20. +5
    -1
      src/states/title-state.hpp

+ 5
- 1
CMakeLists.txt View File

@ -121,8 +121,12 @@ set(EXECUTABLE_SOURCES
${EXECUTABLE_SOURCE_DIR}/game/nest.cpp ${EXECUTABLE_SOURCE_DIR}/game/nest.cpp
${EXECUTABLE_SOURCE_DIR}/game/navmesh.hpp ${EXECUTABLE_SOURCE_DIR}/game/navmesh.hpp
${EXECUTABLE_SOURCE_DIR}/game/navmesh.cpp ${EXECUTABLE_SOURCE_DIR}/game/navmesh.cpp
${EXECUTABLE_SOURCE_DIR}/game/pheromone.hpp
${EXECUTABLE_SOURCE_DIR}/game/pheromone.cpp ${EXECUTABLE_SOURCE_DIR}/game/pheromone.cpp
${EXECUTABLE_SOURCE_DIR}/game/pheromone.cpp
${EXECUTABLE_SOURCE_DIR}/game/level.hpp
${EXECUTABLE_SOURCE_DIR}/game/level.cpp
${EXECUTABLE_SOURCE_DIR}/game/biome.hpp
${EXECUTABLE_SOURCE_DIR}/game/biome.cpp
${EXECUTABLE_SOURCE_DIR}/debug.hpp ${EXECUTABLE_SOURCE_DIR}/debug.hpp
${EXECUTABLE_SOURCE_DIR}/debug.cpp ${EXECUTABLE_SOURCE_DIR}/debug.cpp
${EXECUTABLE_SOURCE_DIR}/camera-controller.hpp ${EXECUTABLE_SOURCE_DIR}/camera-controller.hpp

+ 1
- 1
data

@ -1 +1 @@
Subproject commit 935cc4cf3090766c657eb1f11b6c26adb164a325
Subproject commit 8e817687dd5f843360a2cd90be66ae0e31ae9d4b

+ 1
- 1
lib/emergent

@ -1 +1 @@
Subproject commit af599983ef5650ef399fb30dc985a98f436b5db0
Subproject commit 14b8aeb2bf524d6f55407df259bad3eee85ef95c

+ 9
- 9
src/application.cpp View File

@ -273,6 +273,11 @@ Application::Application(int argc, char* argv[]):
std::cout << "success" << std::endl; std::cout << "success" << std::endl;
} }
// Clear screen to black
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
SDL_GL_SwapWindow(window);
// Get display DPI // Get display DPI
std::cout << "Getting DPI of display 0... "; std::cout << "Getting DPI of display 0... ";
if (SDL_GetDisplayDPI(0, &dpi, nullptr, nullptr) != 0) if (SDL_GetDisplayDPI(0, &dpi, nullptr, nullptr) != 0)
@ -313,13 +318,13 @@ Application::Application(int argc, char* argv[]):
menuControlProfile->registerControl("toggle_fullscreen", &toggleFullscreen); menuControlProfile->registerControl("toggle_fullscreen", &toggleFullscreen);
menuControlProfile->registerControl("escape", &escape); menuControlProfile->registerControl("escape", &escape);
menuLeft.bindKey(keyboard, SDL_SCANCODE_LEFT); menuLeft.bindKey(keyboard, SDL_SCANCODE_LEFT);
menuLeft.bindKey(keyboard, SDL_SCANCODE_A);
//menuLeft.bindKey(keyboard, SDL_SCANCODE_A);
menuRight.bindKey(keyboard, SDL_SCANCODE_RIGHT); menuRight.bindKey(keyboard, SDL_SCANCODE_RIGHT);
menuRight.bindKey(keyboard, SDL_SCANCODE_D);
//menuRight.bindKey(keyboard, SDL_SCANCODE_D);
menuUp.bindKey(keyboard, SDL_SCANCODE_UP); menuUp.bindKey(keyboard, SDL_SCANCODE_UP);
menuUp.bindKey(keyboard, SDL_SCANCODE_W);
//menuUp.bindKey(keyboard, SDL_SCANCODE_W);
menuDown.bindKey(keyboard, SDL_SCANCODE_DOWN); menuDown.bindKey(keyboard, SDL_SCANCODE_DOWN);
menuDown.bindKey(keyboard, SDL_SCANCODE_S);
//menuDown.bindKey(keyboard, SDL_SCANCODE_S);
menuSelect.bindKey(keyboard, SDL_SCANCODE_RETURN); menuSelect.bindKey(keyboard, SDL_SCANCODE_RETURN);
menuSelect.bindKey(keyboard, SDL_SCANCODE_SPACE); menuSelect.bindKey(keyboard, SDL_SCANCODE_SPACE);
menuSelect.bindKey(keyboard, SDL_SCANCODE_Z); menuSelect.bindKey(keyboard, SDL_SCANCODE_Z);
@ -367,11 +372,6 @@ Application::Application(int argc, char* argv[]):
titleState = new TitleState(this); titleState = new TitleState(this);
experimentState = new ExperimentState(this); experimentState = new ExperimentState(this);
// Clear screen to black
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
SDL_GL_SwapWindow(window);
// Setup loaders // Setup loaders
textureLoader = new TextureLoader(); textureLoader = new TextureLoader();
materialLoader = new MaterialLoader(); materialLoader = new MaterialLoader();

+ 6
- 2
src/application.hpp View File

@ -25,6 +25,8 @@ using namespace Emergent;
#include "mesh.hpp" #include "mesh.hpp"
#include "game/terrain.hpp" #include "game/terrain.hpp"
#include "game/level.hpp"
#include "game/biome.hpp"
#include "input.hpp" #include "input.hpp"
#include "controls.hpp" #include "controls.hpp"
#include "settings.hpp" #include "settings.hpp"
@ -96,6 +98,7 @@ public:
Compositor shadowCompositor; Compositor shadowCompositor;
Camera sunlightCamera; Camera sunlightCamera;
RenderTarget defaultRenderTarget; RenderTarget defaultRenderTarget;
SoilRenderPass soilPass;
LightingRenderPass lightingPass; LightingRenderPass lightingPass;
DebugRenderPass debugPass; DebugRenderPass debugPass;
Compositor defaultCompositor; Compositor defaultCompositor;
@ -253,12 +256,13 @@ public:
Menu* settingsMenu; Menu* settingsMenu;
// Models // Models
Model* displayModel;
Model* antModel; Model* antModel;
ModelInstance* displayModelInstance;
ModelInstance* antModelInstance; ModelInstance* antModelInstance;
// Game variables // Game variables
Campaign campaign;
Biosphere biosphere;
Colony* colony; Colony* colony;
SurfaceCameraController* surfaceCam; SurfaceCameraController* surfaceCam;
TunnelCameraController* tunnelCam; TunnelCameraController* tunnelCam;

+ 7
- 0
src/configuration.hpp.in View File

@ -26,4 +26,11 @@
#define ANTKEEPER_VERSION_STRING "@ANTKEEPER_VERSION@" #define ANTKEEPER_VERSION_STRING "@ANTKEEPER_VERSION@"
#cmakedefine ANTKEEPER_DEBUG #cmakedefine ANTKEEPER_DEBUG
#if defined(ANTKEEPER_DEBUG)
#define ANTKEEPER_FIRST_WORLD_INDEX 0
#else
#define ANTKEEPER_FIRST_WORLD_INDEX 1
#endif
#define ANTKEEPER_FIRST_LEVEL_INDEX 1
#endif // CONFIGURATION_HPP #endif // CONFIGURATION_HPP

+ 123
- 0
src/game/biome.cpp View File

@ -0,0 +1,123 @@
#include "biome.hpp"
#include "../settings.hpp"
#if defined(_WIN32) || defined(__CYGWIN__)
#include "../windows-dirent.h"
#else
#include <dirent.h>
#endif
#include <iostream>
Biome::Biome()
{}
Biome::~Biome()
{}
bool Biome::load()
{
ParameterDict parameters;
if (!parameters.load(filename))
{
return false;
}
parameters.get("name", &name);
parameters.get("soil-horizon-o", &soilHorizonOFilename);
parameters.get("soil-horizon-a", &soilHorizonAFilename);
parameters.get("soil-horizon-b", &soilHorizonBFilename);
parameters.get("soil-horizon-c", &soilHorizonCFilename);
parameters.get("cubemap", &cubemapName);
TextureLoader textureLoader;
textureLoader.setCubemap(false);
textureLoader.setMipmapChain(false);
// Load soil horizon textures
soilHorizonO = textureLoader.load(std::string("data/textures/") + soilHorizonOFilename);
soilHorizonA = textureLoader.load(std::string("data/textures/") + soilHorizonAFilename);
soilHorizonB = textureLoader.load(std::string("data/textures/") + soilHorizonBFilename);
soilHorizonC = textureLoader.load(std::string("data/textures/") + soilHorizonCFilename);
// Load diffuse cubemap
textureLoader.setCubemap(true);
textureLoader.setMipmapChain(false);
std::string diffuseCubemapFilename = std::string("data/textures/") + cubemapName + std::string("-diffuse.png");
diffuseCubemap = textureLoader.load(diffuseCubemapFilename);
if (!diffuseCubemap)
{
std::cerr << "Failed to load diffuse cubemap \"" << diffuseCubemapFilename << "\"" << std::endl;
}
// Load specular cubemap
textureLoader.setCubemap(true);
textureLoader.setMipmapChain(true);
std::string specularCubemapFilename = std::string("data/textures/") + cubemapName + std::string("-specular_m%02d.png");
specularCubemap = textureLoader.load(specularCubemapFilename);
if (!specularCubemap)
{
std::cerr << "Failed to load specular cubemap \"" << specularCubemapFilename << "\"" << std::endl;
}
return true;
}
bool Biosphere::load(const std::string& directory)
{
// Open biomes directory
DIR* dir = opendir(directory.c_str());
if (dir == nullptr)
{
std::cout << "Failed to open biome directory \"" << directory << "\"" << std::endl;
return false;
}
// Scan directory for .bio files
for (struct dirent* entry = readdir(dir); entry != nullptr; entry = readdir(dir))
{
if (entry->d_type == DT_DIR || *entry->d_name == '.')
{
continue;
}
std::string filename = entry->d_name;
std::string::size_type delimeter = filename.find_last_of('.');
if (delimeter == std::string::npos)
{
continue;
}
std::string extension = filename.substr(delimeter + 1);
if (extension != "bio")
{
continue;
}
// Add biome
std::string name = filename.substr(0, delimeter);
Biome* biome = &biomes[name];
biome->filename = directory + filename;
}
// Close biomes directory
closedir(dir);
// Load biomes
for (std::map<std::string, Biome>::iterator it = biomes.begin(); it != biomes.end(); ++it)
{
Biome* biome = &it->second;
if (!biome->load())
{
std::cout << "Failed to load biome \"" << biome->filename << "\"" << std::endl;
}
else
{
std::cout << "Loaded biome \"" << biome->filename << "\"" << std::endl;
}
}
return true;
}

+ 42
- 0
src/game/biome.hpp View File

@ -0,0 +1,42 @@
#ifndef BIOME_HPP
#define BIOME_HPP
#include <map>
#include <string>
#include <emergent/emergent.hpp>
using namespace Emergent;
class Biome
{
public:
Biome();
~Biome();
bool load();
std::string filename;
std::string name;
std::string soilHorizonOFilename;
std::string soilHorizonAFilename;
std::string soilHorizonBFilename;
std::string soilHorizonCFilename;
std::string cubemapName;
Texture* soilHorizonO;
Texture* soilHorizonA;
Texture* soilHorizonB;
Texture* soilHorizonC;
Texture* diffuseCubemap;
Texture* specularCubemap;
};
class Biosphere
{
public:
bool load(const std::string& directory);
std::map<std::string, Biome> biomes;
};
#endif // BIOME_HPP

+ 133
- 0
src/game/level.cpp View File

@ -0,0 +1,133 @@
#include "level.hpp"
#include "../settings.hpp"
#if defined(_WIN32) || defined(__CYGWIN__)
#include "../windows-dirent.h"
#else
#include <dirent.h>
#endif
#include <iostream>
#include <sstream>
Level::Level():
worldIndex(-1),
levelIndex(-1)
{}
Level::~Level()
{}
bool Level::load()
{
ParameterDict parameters;
if (!parameters.load(filename))
{
return false;
}
parameters.get("biome", &biome);
parameters.get("heightmap", &heightmap);
return true;
}
Campaign::Campaign()
{}
Campaign::~Campaign()
{}
bool Campaign::load(const std::string& directory)
{
// Open levels directory
DIR* dir = opendir(directory.c_str());
if (dir == nullptr)
{
std::cout << "Failed to open levels directory \"" << directory << "\"" << std::endl;
return false;
}
// Scan directory for .lvl files
for (struct dirent* entry = readdir(dir); entry != nullptr; entry = readdir(dir))
{
if (entry->d_type == DT_DIR || *entry->d_name == '.')
{
continue;
}
std::string filename = entry->d_name;
std::string::size_type delimeter = filename.find_last_of('.');
if (delimeter == std::string::npos)
{
continue;
}
std::string extension = filename.substr(delimeter + 1);
if (extension != "lvl")
{
continue;
}
std::string worldIndexString = filename.substr(0, 2);
std::string levelIndexString = filename.substr(3, 2);
int worldIndex = -1;
int levelIndex = -1;
std::stringstream stream;
stream << worldIndexString;
stream >> worldIndex;
stream.str(std::string());
stream.clear();
stream << levelIndexString;
stream >> levelIndex;
if (worldIndex < 0 || levelIndex < 0)
{
std::cout << "Invalid level \"" << filename << "\"" << std::endl;
continue;
}
// Resize vector to accommodate maximum world index
if (worldIndex >= static_cast<int>(levels.size()))
{
levels.resize(worldIndex + 1);
}
// Resize vector to accommodate maximum level index
if (levelIndex >= static_cast<int>(levels[worldIndex].size()))
{
levels[worldIndex].resize(levelIndex + 1);
}
// Add level
Level* level = &levels[worldIndex][levelIndex];
level->filename = directory + filename;
level->worldIndex = worldIndex;
level->levelIndex = levelIndex;
}
// Close levels directory
closedir(dir);
// Load levels
for (std::size_t i = ANTKEEPER_FIRST_WORLD_INDEX; i < levels.size(); ++i)
{
for (std::size_t j = ANTKEEPER_FIRST_LEVEL_INDEX; j < levels[i].size(); ++j)
{
Level* level = &levels[i][j];
if (!level->load())
{
std::cout << "Failed to load level " << i << "-" << j << std::endl;
}
else
{
std::cout << "Loaded level " << i << "-" << j << std::endl;
}
}
}
return true;
}

+ 35
- 0
src/game/level.hpp View File

@ -0,0 +1,35 @@
#ifndef LEVEL_SELECTOR_HPP
#define LEVEL_SELECTOR_HPP
#include "../configuration.hpp"
#include <string>
#include <vector>
class Level
{
public:
Level();
~Level();
bool load();
std::string filename;
int worldIndex;
int levelIndex;
std::string biome;
std::string heightmap;
};
class Campaign
{
public:
Campaign();
~Campaign();
bool load(const std::string& directory);
std::vector<std::vector<Level>> levels;
};
#endif // LEVEL_SELECTOR_HPP

+ 1
- 1
src/game/navmesh.hpp View File

@ -181,12 +181,12 @@ public:
Edge* edge; Edge* edge;
}; };
private:
/** /**
* Calculates the faceted surface normals for each triangle. * Calculates the faceted surface normals for each triangle.
*/ */
void calculateNormals(); void calculateNormals();
private:
/** /**
* Reads Wavefront OBJ data from an input stream * Reads Wavefront OBJ data from an input stream
* *

+ 330
- 33
src/game/terrain.cpp View File

@ -12,12 +12,14 @@ void Terrain::create(int columns, int rows, const Vector3& dimensions)
void Terrain::createSurface() void Terrain::createSurface()
{ {
std::size_t vertexCount = (columns + 1) * (rows + 1);
std::size_t triangleCount = columns * rows * 2;
std::size_t indexCount = triangleCount * 3;
surfaceVertices.resize(vertexCount);
surfaceIndices.resize(indexCount);
surfaceVertexSize = 3 + 3 + 2;
surfaceVertexCount = (columns + 1) * (rows + 1);
surfaceTriangleCount = columns * rows * 2;
surfaceIndexCount = surfaceTriangleCount * 3;
surfaceVertexData = new float[surfaceVertexSize * surfaceVertexCount];
surfaceIndexData = new std::uint32_t[surfaceIndexCount];
surfaceVertices.resize(surfaceVertexCount);
surfaceIndices.resize(surfaceIndexCount);
// Calculate scale and offset // Calculate scale and offset
Vector2 scale(dimensions.x / (float)columns, dimensions.z / (float)rows); Vector2 scale(dimensions.x / (float)columns, dimensions.z / (float)rows);
@ -29,11 +31,21 @@ void Terrain::createSurface()
for (int j = 0; j <= columns; ++j) for (int j = 0; j <= columns; ++j)
{ {
std::size_t index = i * (columns + 1) + j; std::size_t index = i * (columns + 1) + j;
Vector3* vertex = &surfaceVertices[index];
Vector3* vertex = &surfaceVertices[index];
vertex->x = (float)j * scale.x + offset.x; vertex->x = (float)j * scale.x + offset.x;
vertex->y = rand()%10;
vertex->y = 0.0f;
vertex->z = (float)i * scale.y + offset.y; vertex->z = (float)i * scale.y + offset.y;
float* data = &surfaceVertexData[index * surfaceVertexSize];
*(data++) = vertex->x;
*(data++) = vertex->y;
*(data++) = vertex->z;
*(data++) = 0.0f;
*(data++) = 1.0f;
*(data++) = 0.0f;
*(data++) = static_cast<float>(j) / static_cast<float>(columns) * 2.0f;
*(data++) = static_cast<float>(i) / static_cast<float>(rows) * 2.0f;
} }
} }
@ -42,42 +54,90 @@ void Terrain::createSurface()
{ {
for (int j = 0; j < columns; ++j) for (int j = 0; j < columns; ++j)
{ {
std::size_t a = i * (columns + 1) + j;
std::size_t b = (i + 1) * (columns + 1) + j;
std::size_t c = i * (columns + 1) + j + 1;
std::size_t d = (i + 1) * (columns + 1) + j + 1;
unsigned int a = i * (columns + 1) + j;
unsigned int b = (i + 1) * (columns + 1) + j;
unsigned int c = i * (columns + 1) + j + 1;
unsigned int d = (i + 1) * (columns + 1) + j + 1;
std::size_t index = (i * columns + j) * 2 * 3; std::size_t index = (i * columns + j) * 2 * 3;
surfaceIndices[index] = a;
surfaceIndices[index + 1] = b;
surfaceIndices[index + 2] = c;
surfaceIndices[index + 3] = c;
surfaceIndices[index + 4] = b;
surfaceIndices[index + 5] = d;
surfaceIndices[index++] = a;
surfaceIndices[index++] = b;
surfaceIndices[index++] = c;
surfaceIndices[index++] = c;
surfaceIndices[index++] = b;
surfaceIndices[index] = d;
} }
} }
// Create winged-edge mesh
surfaceMesh.create(surfaceVertices, surfaceIndices);
// Generate index data
for (std::size_t i = 0; i < surfaceIndexCount; ++i)
{
surfaceIndexData[i] = surfaceIndices[i];
}
// Generate navmesh
surfaceNavmesh.create(surfaceVertices, surfaceIndices);
// Calculate vertex normals
calculateSurfaceNormals();
// Create and load VAO, VBO, and IBO
glGenVertexArrays(1, &surfaceVAO);
glBindVertexArray(surfaceVAO);
glGenBuffers(1, &surfaceVBO);
glBindBuffer(GL_ARRAY_BUFFER, surfaceVBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(float) * surfaceVertexSize * surfaceVertexCount, surfaceVertexData, GL_STATIC_DRAW);
glEnableVertexAttribArray(EMERGENT_VERTEX_POSITION);
glVertexAttribPointer(EMERGENT_VERTEX_POSITION, 3, GL_FLOAT, GL_FALSE, surfaceVertexSize * sizeof(float), (char*)0 + 0 * sizeof(float));
glEnableVertexAttribArray(EMERGENT_VERTEX_NORMAL);
glVertexAttribPointer(EMERGENT_VERTEX_NORMAL, 3, GL_FLOAT, GL_FALSE, surfaceVertexSize * sizeof(float), (char*)0 + 3 * sizeof(float));
glEnableVertexAttribArray(EMERGENT_VERTEX_TEXCOORD);
glVertexAttribPointer(EMERGENT_VERTEX_TEXCOORD, 2, GL_FLOAT, GL_FALSE, surfaceVertexSize * sizeof(float), (char*)0 + 6 * sizeof(float));
glGenBuffers(1, &surfaceIBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, surfaceIBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(std::uint32_t) * surfaceIndexCount, surfaceIndexData, GL_STATIC_DRAW);
// Setup material
surfaceMaterial.flags = static_cast<unsigned int>(PhysicalMaterial::Flags::OBJECT);
// Setup buffers
surfaceModel.setVAO(surfaceVAO);
surfaceModel.setVBO(surfaceVBO);
surfaceModel.setIBO(surfaceIBO);
// Create model group
Model::Group* group = new Model::Group();
group->name = "default";
group->material = &surfaceMaterial;
group->indexOffset = 0;
group->triangleCount = surfaceTriangleCount;
// Create model
surfaceModel.create(&surfaceMesh);
// Add group to the model
surfaceModel.addGroup(group);
} }
void Terrain::createSubsurface() void Terrain::createSubsurface()
{ {
std::size_t vertexCount = (columns + 1) * 4 + (rows + 1) * 4;
std::size_t triangleCount = columns * 4 + rows * 4 + 2;
std::size_t indexCount = triangleCount * 3;
subsurfaceVertices.resize(vertexCount);
subsurfaceIndices.resize(indexCount);
subsurfaceVertexSize = 3 + 3 + 2;
subsurfaceVertexCount = (columns + 1) * 4 + (rows + 1) * 4;
subsurfaceTriangleCount = columns * 4 + rows * 4 + 2;
subsurfaceIndexCount = subsurfaceTriangleCount * 3;
subsurfaceVertexData = new float[subsurfaceVertexSize * subsurfaceVertexCount];
subsurfaceIndexData = new std::uint32_t[subsurfaceIndexCount];
subsurfaceVertices.resize(subsurfaceVertexCount);
subsurfaceIndices.resize(subsurfaceIndexCount);
float maxDimension = dimensions.y;
float textureScaleX = dimensions.x / maxDimension;
float textureScaleY = dimensions.y / maxDimension;
float textureScaleZ = dimensions.z / maxDimension;
// Calculate floor position // Calculate floor position
float subsurfaceFloor = -dimensions.y; float subsurfaceFloor = -dimensions.y;
// Calculate vertex positions // Calculate vertex positions
Vector3* vertex = &subsurfaceVertices[0]; Vector3* vertex = &subsurfaceVertices[0];
float* data = &subsurfaceVertexData[0];
// Top row // Top row
for (int j = 0; j <= columns; ++j) for (int j = 0; j <= columns; ++j)
@ -85,9 +145,27 @@ void Terrain::createSubsurface()
int i = 0; int i = 0;
std::size_t surfaceIndex = i * (columns + 1) + j; std::size_t surfaceIndex = i * (columns + 1) + j;
const Vector3& surfaceVertex = surfaceVertices[surfaceIndex]; const Vector3& surfaceVertex = surfaceVertices[surfaceIndex];
float u = 1.0f - (static_cast<float>(j) / static_cast<float>(columns)) * textureScaleX;
*(vertex++) = surfaceVertex; *(vertex++) = surfaceVertex;
*(data++) = surfaceVertex.x;
*(data++) = surfaceVertex.y;
*(data++) = surfaceVertex.z;
*(data++) = 0.0f;
*(data++) = 0.0f;
*(data++) = 1.0f;
*(data++) = u;
*(data++) = 0.0f;
*(vertex++) = Vector3(surfaceVertex.x, subsurfaceFloor, surfaceVertex.z); *(vertex++) = Vector3(surfaceVertex.x, subsurfaceFloor, surfaceVertex.z);
*(data++) = surfaceVertex.x;
*(data++) = subsurfaceFloor;
*(data++) = surfaceVertex.z;
*(data++) = 0.0f;
*(data++) = 0.0f;
*(data++) = 1.0f;
*(data++) = u;
*(data++) = textureScaleY;
} }
// Bottom row // Bottom row
@ -96,9 +174,27 @@ void Terrain::createSubsurface()
int i = rows; int i = rows;
std::size_t surfaceIndex = i * (columns + 1) + j; std::size_t surfaceIndex = i * (columns + 1) + j;
const Vector3& surfaceVertex = surfaceVertices[surfaceIndex]; const Vector3& surfaceVertex = surfaceVertices[surfaceIndex];
float u = (static_cast<float>(j) / static_cast<float>(columns)) * textureScaleX;
*(vertex++) = surfaceVertex; *(vertex++) = surfaceVertex;
*(data++) = surfaceVertex.x;
*(data++) = surfaceVertex.y;
*(data++) = surfaceVertex.z;
*(data++) = 0.0f;
*(data++) = 0.0f;
*(data++) = 1.0f;
*(data++) = u;
*(data++) = 0.0f;
*(vertex++) = Vector3(surfaceVertex.x, subsurfaceFloor, surfaceVertex.z); *(vertex++) = Vector3(surfaceVertex.x, subsurfaceFloor, surfaceVertex.z);
*(data++) = surfaceVertex.x;
*(data++) = subsurfaceFloor;
*(data++) = surfaceVertex.z;
*(data++) = 0.0f;
*(data++) = 0.0f;
*(data++) = 1.0f;
*(data++) = u;
*(data++) = textureScaleY;
} }
// Left column // Left column
@ -107,9 +203,27 @@ void Terrain::createSubsurface()
int j = 0; int j = 0;
std::size_t surfaceIndex = i * (columns + 1) + j; std::size_t surfaceIndex = i * (columns + 1) + j;
const Vector3& surfaceVertex = surfaceVertices[surfaceIndex]; const Vector3& surfaceVertex = surfaceVertices[surfaceIndex];
float u = (static_cast<float>(i) / static_cast<float>(rows)) * textureScaleZ;
*(vertex++) = surfaceVertex; *(vertex++) = surfaceVertex;
*(data++) = surfaceVertex.x;
*(data++) = surfaceVertex.y;
*(data++) = surfaceVertex.z;
*(data++) = 0.0f;
*(data++) = 0.0f;
*(data++) = 1.0f;
*(data++) = u;
*(data++) = 0.0f;
*(vertex++) = Vector3(surfaceVertex.x, subsurfaceFloor, surfaceVertex.z); *(vertex++) = Vector3(surfaceVertex.x, subsurfaceFloor, surfaceVertex.z);
*(data++) = surfaceVertex.x;
*(data++) = subsurfaceFloor;
*(data++) = surfaceVertex.z;
*(data++) = 0.0f;
*(data++) = 0.0f;
*(data++) = 1.0f;
*(data++) = u;
*(data++) = textureScaleY;
} }
// Right column // Right column
@ -118,9 +232,27 @@ void Terrain::createSubsurface()
int j = columns; int j = columns;
std::size_t surfaceIndex = i * (columns + 1) + j; std::size_t surfaceIndex = i * (columns + 1) + j;
const Vector3& surfaceVertex = surfaceVertices[surfaceIndex]; const Vector3& surfaceVertex = surfaceVertices[surfaceIndex];
float u = 1.0f - (static_cast<float>(i) / static_cast<float>(rows)) * textureScaleZ;
*(vertex++) = surfaceVertex; *(vertex++) = surfaceVertex;
*(data++) = surfaceVertex.x;
*(data++) = surfaceVertex.y;
*(data++) = surfaceVertex.z;
*(data++) = 0.0f;
*(data++) = 0.0f;
*(data++) = 1.0f;
*(data++) = u;
*(data++) = 0.0f;
*(vertex++) = Vector3(surfaceVertex.x, subsurfaceFloor, surfaceVertex.z); *(vertex++) = Vector3(surfaceVertex.x, subsurfaceFloor, surfaceVertex.z);
*(data++) = surfaceVertex.x;
*(data++) = subsurfaceFloor;
*(data++) = surfaceVertex.z;
*(data++) = 0.0f;
*(data++) = 0.0f;
*(data++) = 1.0f;
*(data++) = u;
*(data++) = textureScaleY;
} }
// Generate indices // Generate indices
@ -192,11 +324,176 @@ void Terrain::createSubsurface()
(*(index++)) = c; (*(index++)) = c;
(*(index++)) = d; (*(index++)) = d;
// Create winged-edge mesh
subsurfaceMesh.create(subsurfaceVertices, subsurfaceIndices);
// Generate index data
for (std::size_t i = 0; i < subsurfaceIndexCount; ++i)
{
subsurfaceIndexData[i] = subsurfaceIndices[i];
}
// Generate navmesh
subsurfaceNavmesh.create(subsurfaceVertices, subsurfaceIndices);
// Create and load VAO, VBO, and IBO
glGenVertexArrays(1, &subsurfaceVAO);
glBindVertexArray(subsurfaceVAO);
glGenBuffers(1, &subsurfaceVBO);
glBindBuffer(GL_ARRAY_BUFFER, subsurfaceVBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(float) * subsurfaceVertexSize * subsurfaceVertexCount, subsurfaceVertexData, GL_STATIC_DRAW);
glEnableVertexAttribArray(EMERGENT_VERTEX_POSITION);
glVertexAttribPointer(EMERGENT_VERTEX_POSITION, 3, GL_FLOAT, GL_FALSE, subsurfaceVertexSize * sizeof(float), (char*)0 + 0 * sizeof(float));
glEnableVertexAttribArray(EMERGENT_VERTEX_NORMAL);
glVertexAttribPointer(EMERGENT_VERTEX_NORMAL, 3, GL_FLOAT, GL_FALSE, subsurfaceVertexSize * sizeof(float), (char*)0 + 3 * sizeof(float));
glEnableVertexAttribArray(EMERGENT_VERTEX_TEXCOORD);
glVertexAttribPointer(EMERGENT_VERTEX_TEXCOORD, 2, GL_FLOAT, GL_FALSE, subsurfaceVertexSize * sizeof(float), (char*)0 + 6 * sizeof(float));
glGenBuffers(1, &subsurfaceIBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, subsurfaceIBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(std::uint32_t) * subsurfaceIndexCount, subsurfaceIndexData, GL_STATIC_DRAW);
// Setup material
subsurfaceMaterial.flags = static_cast<unsigned int>(PhysicalMaterial::Flags::SOIL);
// Setup buffers
subsurfaceModel.setVAO(subsurfaceVAO);
subsurfaceModel.setVBO(subsurfaceVBO);
subsurfaceModel.setIBO(subsurfaceIBO);
// Create model group
Model::Group* group = new Model::Group();
group->name = "default";
group->material = &subsurfaceMaterial;
group->indexOffset = 0;
group->triangleCount = subsurfaceTriangleCount;
// Add group to the model
subsurfaceModel.addGroup(group);
}
void Terrain::calculateSurfaceNormals()
{
for (std::size_t i = 0; i < surfaceVertexCount; ++i)
{
const Navmesh::Vertex* vertex = (*surfaceNavmesh.getVertices())[i];
Vector3 normal(0.0f);
const Navmesh::Edge* start = vertex->edge;
const Navmesh::Edge* e = start;
do
{
normal += e->triangle->normal;
e = e->previous->symmetric;
}
while (e != start && e != nullptr);
normal = glm::normalize(normal);
float* data = &surfaceVertexData[i * surfaceVertexSize];
data[3] = normal.x;
data[4] = normal.y;
data[5] = normal.z;
}
}
bool Terrain::load(const std::string& filename)
{
int width;
int height;
int channels;
stbi_set_flip_vertically_on_load(true);
// Load image data
unsigned char* pixels = stbi_load(filename.c_str(), &width, &height, &channels, 1);
if (width != columns + 1 || height != rows + 1)
{
// Free loaded image data
stbi_image_free(pixels);
return false;
}
// Set surface vertex heights
for (int i = 0; i <= rows; ++i)
{
for (int j = 0; j <= columns; ++j)
{
std::size_t index = i * (columns + 1) + j;
float elevation = (float)pixels[index] / 255.0f * 5.0f;
surfaceVertexData[index * surfaceVertexSize + 1] = elevation;
surfaceVertices[index].y = elevation;
(*surfaceNavmesh.getVertices())[index]->position.y = elevation;
}
}
// Free loaded image data
stbi_image_free(pixels);
// Set subsurface vertex heights
std::size_t subsurfaceIndex = 0;
// Top row
for (int j = 0; j <= columns; ++j)
{
int i = 0;
std::size_t surfaceIndex = i * (columns + 1) + j;
float elevation = surfaceVertices[surfaceIndex].y;
subsurfaceVertexData[subsurfaceIndex * subsurfaceVertexSize + 1] = elevation;
subsurfaceVertices[subsurfaceIndex].y = elevation;
(*subsurfaceNavmesh.getVertices())[subsurfaceIndex]->position.y = elevation;
subsurfaceIndex += 2;
}
// Bottom row
for (int j = 0; j <= columns; ++j)
{
int i = rows;
std::size_t surfaceIndex = i * (columns + 1) + j;
float elevation = surfaceVertices[surfaceIndex].y;
subsurfaceVertexData[subsurfaceIndex * subsurfaceVertexSize + 1] = elevation;
subsurfaceVertices[subsurfaceIndex].y = elevation;
(*subsurfaceNavmesh.getVertices())[subsurfaceIndex]->position.y = elevation;
subsurfaceIndex += 2;
}
// Left column
for (int i = 0; i <= rows; ++i)
{
int j = 0;
std::size_t surfaceIndex = i * (columns + 1) + j;
float elevation = surfaceVertices[surfaceIndex].y;
subsurfaceVertexData[subsurfaceIndex * subsurfaceVertexSize + 1] = elevation;
subsurfaceVertices[subsurfaceIndex].y = elevation;
(*subsurfaceNavmesh.getVertices())[subsurfaceIndex]->position.y = elevation;
subsurfaceIndex += 2;
}
// Right column
for (int i = 0; i <= rows; ++i)
{
int j = columns;
std::size_t surfaceIndex = i * (columns + 1) + j;
float elevation = surfaceVertices[surfaceIndex].y;
subsurfaceVertexData[subsurfaceIndex * subsurfaceVertexSize + 1] = elevation;
subsurfaceVertices[subsurfaceIndex].y = elevation;
(*subsurfaceNavmesh.getVertices())[subsurfaceIndex]->position.y = elevation;
subsurfaceIndex += 2;
}
// Calculate navmesh normals
surfaceNavmesh.calculateNormals();
subsurfaceNavmesh.calculateNormals();
// Calculate vertex normals
calculateSurfaceNormals();
// Update VBOs
glBindBuffer(GL_ARRAY_BUFFER, surfaceVBO);
glBufferSubData(GL_ARRAY_BUFFER, 0, surfaceVertexCount * surfaceVertexSize * sizeof(float), surfaceVertexData);
glBindBuffer(GL_ARRAY_BUFFER, subsurfaceVBO);
glBufferSubData(GL_ARRAY_BUFFER, 0, subsurfaceVertexCount * subsurfaceVertexSize * sizeof(float), subsurfaceVertexData);
// Create model
subsurfaceModel.create(&subsurfaceMesh);
return true;
} }
struct voxel struct voxel

+ 75
- 12
src/game/terrain.hpp View File

@ -20,6 +20,8 @@
#ifndef TERRAIN_HPP #ifndef TERRAIN_HPP
#define TERRAIN_HPP #define TERRAIN_HPP
#include "navmesh.hpp"
#include "../materials.hpp"
#include <emergent/emergent.hpp> #include <emergent/emergent.hpp>
using namespace Emergent; using namespace Emergent;
@ -36,43 +38,94 @@ public:
*/ */
void create(int columns, int rows, const Vector3& dimensions); void create(int columns, int rows, const Vector3& dimensions);
/// Returns the winged-edge mesh representing the terrain surface.
const WingedEdge* getSurfaceMesh() const;
/// Loads a heightmap
bool load(const std::string& filename);
/// Returns the winged-edge mesh representing the terrain subsurface.
const WingedEdge* getSubsurfaceMesh() const;
/// Returns the navmesh representing the terrain surface.
const Navmesh* getSurfaceNavmesh() const;
/// Returns the navmesh representing the terrain surface.
Navmesh* getSurfaceNavmesh();
/// Returns the navmesh representing the terrain subsurface.
const Navmesh* getSubsurfaceNavmesh() const;
/// Returns the navmesh representing the terrain subsurface.
Navmesh* getSubsurfaceNavmesh();
/// Returns the model representing the terrain surface. /// Returns the model representing the terrain surface.
const Model* getSurfaceModel() const; const Model* getSurfaceModel() const;
/// Returns the model representing the terrain surface.
Model* getSurfaceModel();
/// Returns the model representing the terrain subsurface. /// Returns the model representing the terrain subsurface.
const Model* getSubsurfaceModel() const; const Model* getSubsurfaceModel() const;
/// Returns the model representing the terrain subsurface.
Model* getSubsurfaceModel();
private: private:
void createSurface(); void createSurface();
void createSubsurface(); void createSubsurface();
void calculateSurfaceNormals();
int columns; int columns;
int rows; int rows;
Vector3 dimensions; Vector3 dimensions;
// Surface
std::size_t surfaceVertexSize;
std::size_t surfaceVertexCount;
std::size_t surfaceTriangleCount;
std::size_t surfaceIndexCount;
float* surfaceVertexData;
std::uint32_t* surfaceIndexData;
std::vector<Vector3> surfaceVertices; std::vector<Vector3> surfaceVertices;
std::vector<Vector3> subsurfaceVertices;
std::vector<std::size_t> surfaceIndices; std::vector<std::size_t> surfaceIndices;
std::vector<std::size_t> subsurfaceIndices;
WingedEdge surfaceMesh;
WingedEdge subsurfaceMesh;
GLuint surfaceVAO;
GLuint surfaceVBO;
GLuint surfaceIBO;
PhysicalMaterial surfaceMaterial;
Model surfaceModel; Model surfaceModel;
Navmesh surfaceNavmesh;
// Subsurface
std::size_t subsurfaceVertexSize;
std::size_t subsurfaceVertexCount;
std::size_t subsurfaceTriangleCount;
std::size_t subsurfaceIndexCount;
float* subsurfaceVertexData;
std::uint32_t* subsurfaceIndexData;
std::vector<Vector3> subsurfaceVertices;
std::vector<std::size_t> subsurfaceIndices;
GLuint subsurfaceVAO;
GLuint subsurfaceVBO;
GLuint subsurfaceIBO;
PhysicalMaterial subsurfaceMaterial;
Model subsurfaceModel; Model subsurfaceModel;
Navmesh subsurfaceNavmesh;
}; };
inline const WingedEdge* Terrain::getSurfaceMesh() const
inline Navmesh* Terrain::getSurfaceNavmesh()
{ {
return &surfaceMesh;
return &surfaceNavmesh;
}; };
inline const WingedEdge* Terrain::getSubsurfaceMesh() const
inline const Navmesh* Terrain::getSurfaceNavmesh() const
{ {
return &subsurfaceMesh;
return &surfaceNavmesh;
};
inline Navmesh* Terrain::getSubsurfaceNavmesh()
{
return &subsurfaceNavmesh;
};
inline const Navmesh* Terrain::getSubsurfaceNavmesh() const
{
return &subsurfaceNavmesh;
}; };
inline const Model* Terrain::getSurfaceModel() const inline const Model* Terrain::getSurfaceModel() const
@ -80,9 +133,19 @@ inline const Model* Terrain::getSurfaceModel() const
return &surfaceModel; return &surfaceModel;
} }
inline Model* Terrain::getSurfaceModel()
{
return &surfaceModel;
}
inline const Model* Terrain::getSubsurfaceModel() const inline const Model* Terrain::getSubsurfaceModel() const
{ {
return &subsurfaceModel; return &subsurfaceModel;
} }
inline Model* Terrain::getSubsurfaceModel()
{
return &subsurfaceModel;
}
#endif // TERRAIN_HPP #endif // TERRAIN_HPP

+ 10
- 3
src/materials.hpp View File

@ -50,23 +50,30 @@ inline unsigned int UIMaterial::getMaterialFormatID() const
class PhysicalMaterial: public Material class PhysicalMaterial: public Material
{ {
public: public:
enum class Flags
{
OBJECT = 0x01,
TERRAIN = 0x02,
SOIL = 0x04,
};
PhysicalMaterial(): PhysicalMaterial():
albedoOpacityMap(nullptr), albedoOpacityMap(nullptr),
metalnessRoughnessMap(nullptr), metalnessRoughnessMap(nullptr),
normalOcclusionMap(nullptr)
normalOcclusionMap(nullptr),
flags((unsigned int)Flags::OBJECT)
{}; {};
virtual ~PhysicalMaterial() {}; virtual ~PhysicalMaterial() {};
virtual unsigned int getMaterialFormatID() const; virtual unsigned int getMaterialFormatID() const;
unsigned int flags;
Vector3 albedo; Vector3 albedo;
float opacity; float opacity;
float metalness; float metalness;
float roughness; float roughness;
Texture* albedoOpacityMap; Texture* albedoOpacityMap;
Texture* metalnessRoughnessMap; Texture* metalnessRoughnessMap;
Texture* normalOcclusionMap; Texture* normalOcclusionMap;
bool shadowCaster; bool shadowCaster;
bool shadowReceiver; bool shadowReceiver;
}; };

+ 40
- 65
src/render-passes.cpp View File

@ -187,36 +187,37 @@ void ClippingRenderPass::setClippingPlane(const Plane& plane)
this->clippingPlane = Vector4(plane.getNormal(), plane.getDistance()); this->clippingPlane = Vector4(plane.getNormal(), plane.getDistance());
} }
CappingRenderPass::CappingRenderPass():
SoilRenderPass::SoilRenderPass():
shader(nullptr) shader(nullptr)
{ {
horizonTexturesParam = parameterSet.addParameter("horizonTextures", ShaderParameter::Type::INT, 4); horizonTexturesParam = parameterSet.addParameter("horizonTextures", ShaderParameter::Type::INT, 4);
modelParam = parameterSet.addParameter("modelMatrix", ShaderParameter::Type::MATRIX_4, 1); modelParam = parameterSet.addParameter("modelMatrix", ShaderParameter::Type::MATRIX_4, 1);
modelViewProjectionParam = parameterSet.addParameter("modelViewProjectionMatrix", ShaderParameter::Type::MATRIX_4, 1); modelViewProjectionParam = parameterSet.addParameter("modelViewProjectionMatrix", ShaderParameter::Type::MATRIX_4, 1);
horizonOTexture = nullptr;
horizonATexture = nullptr;
horizonBTexture = nullptr;
horizonCTexture = nullptr;
} }
bool CappingRenderPass::load(const RenderContext* renderContext)
bool SoilRenderPass::load(const RenderContext* renderContext)
{ {
shaderLoader.undefine();
shaderLoader.define("TEXTURE_COUNT", 4);
shaderLoader.define("VERTEX_POSITION", EMERGENT_VERTEX_POSITION);
shaderLoader.define("VERTEX_TEXCOORD", EMERGENT_VERTEX_TEXCOORD);
shaderLoader.define("VERTEX_NORMAL", EMERGENT_VERTEX_NORMAL);
shader = shaderLoader.load("data/shaders/soil-profile.glsl", &parameterSet); shader = shaderLoader.load("data/shaders/soil-profile.glsl", &parameterSet);
if (!shader) if (!shader)
{ {
return false; return false;
} }
TextureLoader textureLoader;
horizonOTexture = textureLoader.load("data/textures/horizon-o.png");
horizonATexture = textureLoader.load("data/textures/horizon-a.png");
horizonBTexture = textureLoader.load("data/textures/horizon-b.png");
horizonCTexture = textureLoader.load("data/textures/horizon-c.png");
return true; return true;
} }
void CappingRenderPass::unload()
void SoilRenderPass::unload()
{ {
shaderLoader.undefine();
delete shader; delete shader;
shader = nullptr; shader = nullptr;
@ -231,16 +232,12 @@ void CappingRenderPass::unload()
horizonCTexture = nullptr; horizonCTexture = nullptr;
} }
void CappingRenderPass::render(const RenderContext* renderContext)
void SoilRenderPass::render(const RenderContext* renderContext)
{ {
glStencilFunc(GL_NOTEQUAL, 0, ~0);
glStencilOp(GL_KEEP, GL_ZERO, GL_ZERO);
//glDepthMask(GL_FALSE);
// Bind shader // Bind shader
shader->bind(); shader->bind();
// Bind texture
// Bind textures
glActiveTexture(GL_TEXTURE0); glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, horizonOTexture->getTextureID()); glBindTexture(GL_TEXTURE_2D, horizonOTexture->getTextureID());
glActiveTexture(GL_TEXTURE1); glActiveTexture(GL_TEXTURE1);
@ -254,12 +251,32 @@ void CappingRenderPass::render(const RenderContext* renderContext)
int textureUnits[] = {0, 1, 2, 3}; int textureUnits[] = {0, 1, 2, 3};
shader->setParameter(horizonTexturesParam, 0, &textureUnits[0], 4); shader->setParameter(horizonTexturesParam, 0, &textureUnits[0], 4);
// Enable depth testing
glEnable(GL_DEPTH_TEST);
glDepthMask(GL_TRUE);
glDepthFunc(GL_LEQUAL);
// Enable backface culling
glEnable(GL_CULL_FACE);
glCullFace(GL_BACK);
const Camera& camera = *(renderContext->camera); const Camera& camera = *(renderContext->camera);
const std::list<RenderOperation>* operations = renderContext->queue->getOperations(); const std::list<RenderOperation>* operations = renderContext->queue->getOperations();
// Render operations // Render operations
for (const RenderOperation& operation: *operations) for (const RenderOperation& operation: *operations)
{
{
// Skip render operations with unsupported materials
if (operation.material->getMaterialFormatID() != static_cast<unsigned int>(MaterialFormat::PHYSICAL))
{
continue;
}
const PhysicalMaterial* material = static_cast<const PhysicalMaterial*>(operation.material);
if (!(material->flags & (unsigned int)PhysicalMaterial::Flags::SOIL))
{
continue;
}
const Matrix4& modelMatrix = operation.transform; const Matrix4& modelMatrix = operation.transform;
Matrix4 modelViewProjectionMatrix = camera.getViewProjection() * modelMatrix; Matrix4 modelViewProjectionMatrix = camera.getViewProjection() * modelMatrix;
shader->setParameter(modelParam, modelMatrix); shader->setParameter(modelParam, modelMatrix);
@ -268,9 +285,6 @@ void CappingRenderPass::render(const RenderContext* renderContext)
glBindVertexArray(operation.vao); glBindVertexArray(operation.vao);
glDrawElementsBaseVertex(GL_TRIANGLES, operation.triangleCount * 3, GL_UNSIGNED_INT, (void*)0, operation.indexOffset); glDrawElementsBaseVertex(GL_TRIANGLES, operation.triangleCount * 3, GL_UNSIGNED_INT, (void*)0, operation.indexOffset);
} }
//glDepthMask(GL_TRUE);
glDisable(GL_STENCIL_TEST);
} }
LightingRenderPass::LightingRenderPass(): LightingRenderPass::LightingRenderPass():
@ -305,18 +319,6 @@ LightingRenderPass::LightingRenderPass():
bool LightingRenderPass::load(const RenderContext* renderContext) bool LightingRenderPass::load(const RenderContext* renderContext)
{ {
// For each render operation
/*
if (renderContext != nullptr)
{
const std::list<RenderOperation>* operations = renderContext->queue->getOperations();
for (const RenderOperation& operation: *operations)
{
loadShader(operation);
}
}
*/
// Load tree shadow // Load tree shadow
TextureLoader textureLoader; TextureLoader textureLoader;
treeShadow = textureLoader.load("data/textures/tree-shadow-0.png"); treeShadow = textureLoader.load("data/textures/tree-shadow-0.png");
@ -341,34 +343,6 @@ bool LightingRenderPass::load(const RenderContext* renderContext)
{ {
std::cerr << "Failed to load cubemap" << std::endl; std::cerr << "Failed to load cubemap" << std::endl;
} }
// Load unit plane
unitPlaneModel = modelLoader->load("data/models/unit-plane.mdl");
if (!unitPlaneModel)
{
std::cout << "Failed to load unit plane" << std::endl;
}
// Setup capping plane model
for (int i = 0; i < 5; ++i)
{
cappingPlaneInstances[i].setModel(unitPlaneModel);
}
// Create capping render context
cappingRenderContext.queue = &cappingRenderQueue;
// Load clipping render pass
if (!clippingRenderPass.load(nullptr))
{
return false;
}
// Load capping render pass
if (!cappingRenderPass.load(nullptr))
{
return false;
}
// Load lighting shader // Load lighting shader
shaderLoader.undefine(); shaderLoader.undefine();
@ -390,9 +364,6 @@ bool LightingRenderPass::load(const RenderContext* renderContext)
void LightingRenderPass::unload() void LightingRenderPass::unload()
{ {
cappingRenderQueue.clear();
clippingRenderPass.unload();
cappingRenderPass.unload();
delete lightingShader; delete lightingShader;
lightingShader = nullptr; lightingShader = nullptr;
@ -855,6 +826,10 @@ void LightingRenderPass::render(const RenderContext* renderContext)
continue; continue;
} }
const PhysicalMaterial* material = static_cast<const PhysicalMaterial*>(operation.material); const PhysicalMaterial* material = static_cast<const PhysicalMaterial*>(operation.material);
if (!(material->flags & (unsigned int)PhysicalMaterial::Flags::OBJECT))
{
continue;
}
// Skip render operations with unsupported vertex formats // Skip render operations with unsupported vertex formats

+ 18
- 20
src/render-passes.hpp View File

@ -71,16 +71,31 @@ private:
}; };
/** /**
* Caps clipped geometry.
* Renders soil profiles.
*
* A soil profile generally of five soil horizons: O, A, B, C, and R.
*
* Horizon O: Organic
* Horizon A: Surface
* Horizon B: Subsoil
* Horizon C: Substratum
* Horizon R: Bedrock
*
* In this render pass, only the O, A, B, and C horizons are used.
*/ */
class CappingRenderPass: public RenderPass
class SoilRenderPass: public RenderPass
{ {
public: public:
CappingRenderPass();
SoilRenderPass();
virtual bool load(const RenderContext* renderContext); virtual bool load(const RenderContext* renderContext);
virtual void unload(); virtual void unload();
virtual void render(const RenderContext* renderContext); virtual void render(const RenderContext* renderContext);
inline void setHorizonOTexture(Texture* texture) { horizonOTexture = texture; }
inline void setHorizonATexture(Texture* texture) { horizonATexture = texture; }
inline void setHorizonBTexture(Texture* texture) { horizonBTexture = texture; }
inline void setHorizonCTexture(Texture* texture) { horizonCTexture = texture; }
private: private:
ShaderParameterSet parameterSet; ShaderParameterSet parameterSet;
const ShaderParameter* modelParam; const ShaderParameter* modelParam;
@ -113,14 +128,6 @@ public:
inline void setShadowCamera(const Camera* camera) { this->shadowCamera = camera; } inline void setShadowCamera(const Camera* camera) { this->shadowCamera = camera; }
inline void setModelLoader(ModelLoader* modelLoader) { this->modelLoader = modelLoader; } inline void setModelLoader(ModelLoader* modelLoader) { this->modelLoader = modelLoader; }
inline void setClippingPlanes(const Plane* planes)
{
for (int i = 0; i < 5; ++i)
{
this->clippingPlanes[i] = planes[i];
}
}
private: private:
bool loadShader(const RenderOperation& operation); bool loadShader(const RenderOperation& operation);
@ -152,15 +159,6 @@ private:
const Camera* shadowCamera; const Camera* shadowCamera;
float time; float time;
// Cutaway clipping and capping
Plane clippingPlanes[5];
Model* unitPlaneModel;
ModelInstance cappingPlaneInstances[5];
RenderQueue cappingRenderQueue;
RenderContext cappingRenderContext;
ClippingRenderPass clippingRenderPass;
CappingRenderPass cappingRenderPass;
ModelLoader* modelLoader; ModelLoader* modelLoader;
}; };

+ 2
- 19
src/states/experiment-state.cpp View File

@ -210,7 +210,6 @@ void ExperimentState::enter()
objectsLayer->addObject(&application->camera); objectsLayer->addObject(&application->camera);
objectsLayer->addObject(application->displayModelInstance);
objectsLayer->addObject(application->antModelInstance); objectsLayer->addObject(application->antModelInstance);
objectsLayer->addObject(application->lineBatcher->getBatch()); objectsLayer->addObject(application->lineBatcher->getBatch());
@ -416,6 +415,7 @@ void ExperimentState::execute()
Vector3 pick; Vector3 pick;
/*
if (dragging) if (dragging)
{ {
auto result = pickingRay.intersects(*terrain.getSurfaceMesh()); auto result = pickingRay.intersects(*terrain.getSurfaceMesh());
@ -458,30 +458,13 @@ void ExperimentState::execute()
application->clippingPlaneOffsets[2] = Vector3(dragMin.x, -halfWorldSize, 0.0f); application->clippingPlaneOffsets[2] = Vector3(dragMin.x, -halfWorldSize, 0.0f);
application->clippingPlaneOffsets[3] = Vector3(0.0f, -halfWorldSize, dragMax.z); application->clippingPlaneOffsets[3] = Vector3(0.0f, -halfWorldSize, dragMax.z);
} }
*/
// Calculate clipping planes // Calculate clipping planes
float halfWorldSize = worldSize * 0.5f; float halfWorldSize = worldSize * 0.5f;
// E, N, W, S, B
//application->clippingPlaneOffsets[0] = Vector3(halfWorldSize * 0.5f, -halfWorldSize, 0.0f);
//application->clippingPlaneOffsets[1] = Vector3(0.0f, -halfWorldSize, -halfWorldSize * 0.5f);
//application->clippingPlaneOffsets[2] = Vector3(-halfWorldSize * 0.5f, -halfWorldSize, 0.0f);
//application->clippingPlaneOffsets[3] = Vector3(0.0f, -halfWorldSize, halfWorldSize * 0.5f);
application->clippingPlaneOffsets[4] = Vector3(0.0f, -worldSize * 2.0f, 0.0f);
application->clippingPlaneNormals[0] = Vector3(1.0f, 0.0f, 0.0f);
application->clippingPlaneNormals[1] = Vector3(0.0f, 0.0f, -1.0f);
application->clippingPlaneNormals[2] = Vector3(-1.0f, 0.0f, 0.0f);
application->clippingPlaneNormals[3] = Vector3(0.0f, 0.0f, 1.0f);
application->clippingPlaneNormals[4] = Vector3(0.0f, -1.0f, 0.0f);
for (int i = 0; i < 5; ++i)
{
application->clippingPlanes[i].set(application->clippingPlaneNormals[i], application->clippingPlaneOffsets[i]);
}
application->lightingPass.setClippingPlanes(&application->clippingPlanes[0]);
application->lineBatcher->getBatch()->update(); application->lineBatcher->getBatch()->update();

+ 12
- 7
src/states/splash-state.cpp View File

@ -105,8 +105,8 @@ void SplashState::enter()
// Colors // Colors
application->selectedColor = Vector4(1.0f, 1.0f, 1.0f, 1.0f);
application->deselectedColor = Vector4(0.35f, 0.35f, 0.35f, 1.0f);
application->selectedColor = Vector4(0.0f, 0.0f, 0.0f, 1.0f);
application->deselectedColor = Vector4(0.0f, 0.0f, 0.0f, 0.35f);
// Build UI // Build UI
application->uiRootElement = new UIContainer(); application->uiRootElement = new UIContainer();
@ -158,7 +158,8 @@ void SplashState::enter()
application->menuSelectorLabel = new UILabel(); application->menuSelectorLabel = new UILabel();
application->menuSelectorLabel->setAnchor(Anchor::TOP_LEFT); application->menuSelectorLabel->setAnchor(Anchor::TOP_LEFT);
application->menuSelectorLabel->setFont(application->menuFont); application->menuSelectorLabel->setFont(application->menuFont);
application->menuSelectorLabel->setText(">");
application->menuSelectorLabel->setText("<");
application->menuSelectorLabel->setTintColor(application->selectedColor);
/* /*
application->menuSelectorLabel = new UIImage(); application->menuSelectorLabel = new UIImage();
@ -351,10 +352,10 @@ void SplashState::enter()
application->copyrightFadeOutTween->setUpdateCallback(std::bind(UIElement::setTintColor, application->copyrightImage, std::placeholders::_1)); application->copyrightFadeOutTween->setUpdateCallback(std::bind(UIElement::setTintColor, application->copyrightImage, std::placeholders::_1));
application->tweener->addTween(application->copyrightFadeOutTween); application->tweener->addTween(application->copyrightFadeOutTween);
application->anyKeyFadeInTween = new Tween<Vector4>(EaseFunction::LINEAR, 0.0f, 1.5f, Vector4(1.0f, 1.0f, 1.0f, 0.0f), Vector4(0.0f, 0.0f, 0.0f, 1.0f));
application->anyKeyFadeInTween = new Tween<Vector4>(EaseFunction::LINEAR, 0.0f, 1.5f, Vector4(0.0f, 0.0f, 0.0f, 0.0f), Vector4(0.0f, 0.0f, 0.0f, 1.0f));
application->anyKeyFadeInTween->setUpdateCallback(std::bind(UIElement::setTintColor, application->anyKeyLabel, std::placeholders::_1)); application->anyKeyFadeInTween->setUpdateCallback(std::bind(UIElement::setTintColor, application->anyKeyLabel, std::placeholders::_1));
application->tweener->addTween(application->anyKeyFadeInTween); application->tweener->addTween(application->anyKeyFadeInTween);
application->anyKeyFadeOutTween = new Tween<Vector4>(EaseFunction::LINEAR, 0.0f, 1.5f, Vector4(1.0f, 1.0f, 1.0f, 1.0f), Vector4(0.0f, 0.0f, 0.0f, -1.0f));
application->anyKeyFadeOutTween = new Tween<Vector4>(EaseFunction::LINEAR, 0.0f, 1.5f, Vector4(0.0f, 0.0f, 0.0f, 1.0f), Vector4(0.0f, 0.0f, 0.0f, -1.0f));
application->anyKeyFadeOutTween->setUpdateCallback(std::bind(UIElement::setTintColor, application->anyKeyLabel, std::placeholders::_1)); application->anyKeyFadeOutTween->setUpdateCallback(std::bind(UIElement::setTintColor, application->anyKeyLabel, std::placeholders::_1));
application->tweener->addTween(application->anyKeyFadeOutTween); application->tweener->addTween(application->anyKeyFadeOutTween);
@ -492,17 +493,21 @@ void SplashState::enter()
application->selectMenuItem(application->selectedMenuItemIndex); application->selectMenuItem(application->selectedMenuItemIndex);
// Models // Models
application->displayModel = application->modelLoader->load("data/models/icosphere.mdl");
application->antModel = application->modelLoader->load("data/models/debug-worker.mdl"); application->antModel = application->modelLoader->load("data/models/debug-worker.mdl");
// Model instances // Model instances
application->displayModelInstance = new ModelInstance();
application->antModelInstance = new ModelInstance(); application->antModelInstance = new ModelInstance();
// Allocate game variables // Allocate game variables
application->surfaceCam = new SurfaceCameraController(); application->surfaceCam = new SurfaceCameraController();
application->tunnelCam = new TunnelCameraController(); application->tunnelCam = new TunnelCameraController();
// Load biosphere
application->biosphere.load("data/biomes/");
// Load campaign
application->campaign.load("data/levels/");
// Setup screen fade-in transition // Setup screen fade-in transition
fadeIn = false; fadeIn = false;
fadeOut = false; fadeOut = false;

+ 61
- 25
src/states/title-state.cpp View File

@ -47,9 +47,6 @@ void TitleState::enter()
fadeIn = false; fadeIn = false;
fadeOut = false; fadeOut = false;
application->displayModelInstance->setModel(application->displayModel);
application->displayModelInstance->setTransform(Transform::getIdentity());
application->antModelInstance->setModel(application->antModel); application->antModelInstance->setModel(application->antModel);
application->antModelInstance->setTransform(Transform::getIdentity()); application->antModelInstance->setTransform(Transform::getIdentity());
@ -61,7 +58,7 @@ void TitleState::enter()
Billboard* bgBillboard = application->bgBatch.getBillboard(0); Billboard* bgBillboard = application->bgBatch.getBillboard(0);
bgBillboard->setDimensions(Vector2(1.0f, 1.0f)); bgBillboard->setDimensions(Vector2(1.0f, 1.0f));
bgBillboard->setTranslation(Vector3(0.5f, 0.5f, 0.0f)); bgBillboard->setTranslation(Vector3(0.5f, 0.5f, 0.0f));
bgBillboard->setTintColor(Vector4(1, 0, 0, 1));
bgBillboard->setTintColor(Vector4(1, 1, 1, 1));
application->bgBatch.update(); application->bgBatch.update();
application->vignettePass.setRenderTarget(&application->defaultRenderTarget); application->vignettePass.setRenderTarget(&application->defaultRenderTarget);
@ -80,6 +77,39 @@ void TitleState::enter()
application->sunlight.setColor(glm::vec3(1.0f)); application->sunlight.setColor(glm::vec3(1.0f));
application->sunlight.setDirection(glm::normalize(glm::vec3(0.5, -1, -0.5))); application->sunlight.setDirection(glm::normalize(glm::vec3(0.5, -1, -0.5)));
const Level* level = &application->campaign.levels[1][1];
const Biome* biome = &application->biosphere.biomes[level->biome];
// Setup soil pass
application->soilPass.setRenderTarget(&application->defaultRenderTarget);
TextureLoader textureLoader;
/*application->soilPass.setHorizonOTexture(textureLoader.load("data/textures/debug-soil-horizon-o.png"));
application->soilPass.setHorizonATexture(textureLoader.load("data/textures/debug-soil-horizon-a.png"));
application->soilPass.setHorizonBTexture(textureLoader.load("data/textures/debug-soil-horizon-b.png"));
application->soilPass.setHorizonCTexture(textureLoader.load("data/textures/debug-soil-horizon-c.png"));*/
application->soilPass.setHorizonOTexture(biome->soilHorizonO);
application->soilPass.setHorizonATexture(biome->soilHorizonA);
application->soilPass.setHorizonBTexture(biome->soilHorizonB);
application->soilPass.setHorizonCTexture(biome->soilHorizonC);
application->defaultCompositor.addPass(&application->soilPass);
// Create terrain
std::string heightmap = std::string("data/textures/") + level->heightmap;
terrain.create(255, 255, Vector3(50, 20, 50));
terrain.load(heightmap);
terrain.getSurfaceModel()->getGroup(0)->material = application->materialLoader->load("data/materials/debug-terrain-surface.mtl");
terrainSurface.setModel(terrain.getSurfaceModel());
terrainSurface.setTranslation(Vector3(0, 0, 0));
terrainSubsurface.setModel(terrain.getSubsurfaceModel());
terrainSubsurface.setTranslation(Vector3(0, 0, 0));
application->scene.getLayer(0)->addObject(&terrainSurface);
application->scene.getLayer(0)->addObject(&terrainSubsurface);
navmesh = terrain.getSurfaceNavmesh();
// Setup lighting pass // Setup lighting pass
application->lightingPass.setRenderTarget(&application->defaultRenderTarget); application->lightingPass.setRenderTarget(&application->defaultRenderTarget);
@ -114,8 +144,6 @@ void TitleState::enter()
application->scene.getLayer(0)->addObject(lightA); application->scene.getLayer(0)->addObject(lightA);
application->scene.getLayer(0)->addObject(lightB); application->scene.getLayer(0)->addObject(lightB);
application->scene.getLayer(0)->addObject(lightC); application->scene.getLayer(0)->addObject(lightC);
application->scene.getLayer(0)->addObject(application->displayModelInstance);
application->scene.getLayer(0)->addObject(&application->camera); application->scene.getLayer(0)->addObject(&application->camera);
// Load compositor // Load compositor
@ -140,9 +168,9 @@ void TitleState::enter()
// Setup camera controller // Setup camera controller
application->surfaceCam->setCamera(&application->camera); application->surfaceCam->setCamera(&application->camera);
application->surfaceCam->setFocalPoint(Vector3(0.0f)); application->surfaceCam->setFocalPoint(Vector3(0.0f));
application->surfaceCam->setFocalDistance(10.0f);
application->surfaceCam->setElevation(0.0f);
application->surfaceCam->setAzimuth(0.0f);
application->surfaceCam->setFocalDistance(300.0f);
application->surfaceCam->setElevation(glm::radians(32.5f));
application->surfaceCam->setAzimuth(glm::radians(-45.0f));
application->surfaceCam->setTargetFocalPoint(application->surfaceCam->getFocalPoint()); application->surfaceCam->setTargetFocalPoint(application->surfaceCam->getFocalPoint());
application->surfaceCam->setTargetFocalDistance(application->surfaceCam->getFocalDistance()); application->surfaceCam->setTargetFocalDistance(application->surfaceCam->getFocalDistance());
application->surfaceCam->setTargetElevation(application->surfaceCam->getElevation()); application->surfaceCam->setTargetElevation(application->surfaceCam->getElevation());
@ -154,19 +182,17 @@ void TitleState::enter()
wasDragging = dragging; wasDragging = dragging;
application->arcball.setCenter(Vector2(application->width * 0.5f, application->height * 0.5f)); application->arcball.setCenter(Vector2(application->width * 0.5f, application->height * 0.5f));
application->arcball.setRadius(application->height * 0.5f); application->arcball.setRadius(application->height * 0.5f);
// Load navmesh
navmesh.loadOBJ("data/textures/icosphere.obj");
// Setup colony // Setup colony
colony.setAntModel(application->antModel); colony.setAntModel(application->antModel);
for (int i = 0; i < 10; ++i)
for (int i = 0; i < 50; ++i)
{ {
Navmesh::Triangle* triangle = (*navmesh.getTriangles())[0];
Navmesh::Triangle* triangle = (*navmesh->getTriangles())[0];
ant = colony.spawn(&navmesh, triangle, normalize_barycentric(Vector3(0.5f)));
ant = colony.spawn(navmesh, triangle, normalize_barycentric(Vector3(0.5f)));
Vector3 forward = glm::normalize(triangle->edge->vertex->position - triangle->edge->next->vertex->position); Vector3 forward = glm::normalize(triangle->edge->vertex->position - triangle->edge->next->vertex->position);
Vector3 up = triangle->normal; Vector3 up = triangle->normal;
@ -202,12 +228,6 @@ void TitleState::execute()
application->titleFadeInTween->start(); application->titleFadeInTween->start();
} }
if (stateTime >= copyrightDelay && !application->copyrightImage->isVisible())
{
//application->copyrightImage->setVisible(true);
//application->copyrightFadeInTween->start();
}
if (stateTime >= pressAnyKeyDelay && !application->anyKeyLabel->isVisible()) if (stateTime >= pressAnyKeyDelay && !application->anyKeyLabel->isVisible())
{ {
application->anyKeyLabel->setVisible(true); application->anyKeyLabel->setVisible(true);
@ -266,8 +286,6 @@ void TitleState::execute()
application->titleFadeInTween->stop(); application->titleFadeInTween->stop();
application->titleFadeOutTween->start(); application->titleFadeOutTween->start();
//application->copyrightFadeInTween->stop();
//application->copyrightFadeOutTween->start();
application->anyKeyFadeInTween->stop(); application->anyKeyFadeInTween->stop();
application->anyKeyFadeOutTween->stop(); application->anyKeyFadeOutTween->stop();
application->anyKeyLabel->setVisible(false); application->anyKeyLabel->setVisible(false);
@ -295,6 +313,7 @@ void TitleState::execute()
fadeIn = true; fadeIn = true;
} }
/*
glm::ivec2 mousePosition = application->mouse->getCurrentPosition(); glm::ivec2 mousePosition = application->mouse->getCurrentPosition();
mousePosition.y = application->height - mousePosition.y; mousePosition.y = application->height - mousePosition.y;
if (dragging && !wasDragging) if (dragging && !wasDragging)
@ -313,7 +332,7 @@ void TitleState::execute()
application->displayModelInstance->setTransform(transform); application->displayModelInstance->setTransform(transform);
} }
wasDragging = dragging; wasDragging = dragging;
*/
// Check if application was closed // Check if application was closed
@ -334,6 +353,23 @@ void TitleState::execute()
application->surfaceCam->rotate(-rotationSpeed); application->surfaceCam->rotate(-rotationSpeed);
if (application->cameraRotateCCW.isTriggered()) if (application->cameraRotateCCW.isTriggered())
application->surfaceCam->rotate(rotationSpeed); application->surfaceCam->rotate(rotationSpeed);
// Move camera
Vector2 movementVector(0.0f);
if (application->cameraMoveLeft.isTriggered())
movementVector.x -= application->cameraMoveLeft.getCurrentValue();
if (application->cameraMoveRight.isTriggered())
movementVector.x += application->cameraMoveRight.getCurrentValue();
if (application->cameraMoveForward.isTriggered())
movementVector.y -= application->cameraMoveForward.getCurrentValue();
if (application->cameraMoveBack.isTriggered())
movementVector.y += application->cameraMoveBack.getCurrentValue();
if (movementVector.x != 0.0f || movementVector.y != 0.0f)
{
movementVector *= 0.005f * application->surfaceCam->getFocalDistance() * dt / (1.0f / 60.0f);
application->surfaceCam->move(movementVector);
}
// Zoom camera // Zoom camera
float zoomFactor = application->surfaceCam->getFocalDistance() / 20.0f * dt / (1.0f / 60.0f); float zoomFactor = application->surfaceCam->getFocalDistance() / 20.0f * dt / (1.0f / 60.0f);
if (application->cameraZoomIn.isTriggered()) if (application->cameraZoomIn.isTriggered())

+ 5
- 1
src/states/title-state.hpp View File

@ -25,6 +25,7 @@
#include "../game/ant.hpp" #include "../game/ant.hpp"
#include "../game/colony.hpp" #include "../game/colony.hpp"
#include "../game/terrain.hpp"
#include <emergent/emergent.hpp> #include <emergent/emergent.hpp>
using namespace Emergent; using namespace Emergent;
@ -60,7 +61,10 @@ private:
Colony colony; Colony colony;
Ant* ant; Ant* ant;
Navmesh navmesh;
Navmesh* navmesh;
Terrain terrain;
ModelInstance terrainSurface;
ModelInstance terrainSubsurface;
}; };
#endif // TITLE_STATE_HPP #endif // TITLE_STATE_HPP

Loading…
Cancel
Save