2018-11-26 08:59:16 +00:00
|
|
|
|
// This source code is property of the Computer Graphics and Visualization
|
|
|
|
|
// chair of the TU Dresden. Do not distribute!
|
2018-11-13 08:35:18 +00:00
|
|
|
|
// Copyright (C) CGV TU Dresden - All Rights Reserved
|
|
|
|
|
|
|
|
|
|
#include "Viewer.h"
|
|
|
|
|
|
|
|
|
|
#include <nanogui/window.h>
|
|
|
|
|
#include <nanogui/layout.h>
|
|
|
|
|
#include <nanogui/checkbox.h>
|
|
|
|
|
|
|
|
|
|
#include <gui/SliderHelper.h>
|
|
|
|
|
|
|
|
|
|
#include <iostream>
|
|
|
|
|
|
|
|
|
|
#include <stb_image.h>
|
|
|
|
|
|
2018-11-26 08:59:16 +00:00
|
|
|
|
#include "glsl.h"
|
2018-11-13 08:35:18 +00:00
|
|
|
|
#include "textures.h"
|
|
|
|
|
|
2018-11-16 11:47:55 +00:00
|
|
|
|
#include <fstream>
|
2018-11-26 16:58:30 +00:00
|
|
|
|
#include <sstream>
|
2018-11-16 11:47:55 +00:00
|
|
|
|
|
2018-11-26 16:58:30 +00:00
|
|
|
|
constexpr bool REFERENCE = true;
|
|
|
|
|
constexpr uint32_t PATCH_SIZE = 256; //number of vertices along one side of the terrain patch
|
2018-11-13 08:35:18 +00:00
|
|
|
|
|
|
|
|
|
Viewer::Viewer()
|
|
|
|
|
: AbstractViewer("CG1 Exercise 2"),
|
2018-11-26 08:59:16 +00:00
|
|
|
|
terrainPositions(nse::gui::VertexBuffer), terrainIndices(nse::gui::IndexBuffer),
|
2018-11-26 16:58:30 +00:00
|
|
|
|
offsetBuffer(nse::gui::VertexBuffer),
|
|
|
|
|
referenceVB(nse::gui::VertexBuffer), referenceIB(nse::gui::IndexBuffer)
|
2018-11-26 08:59:16 +00:00
|
|
|
|
{
|
2018-11-13 08:35:18 +00:00
|
|
|
|
LoadShaders();
|
|
|
|
|
CreateGeometry();
|
2018-11-26 08:59:16 +00:00
|
|
|
|
|
2018-11-26 12:11:05 +00:00
|
|
|
|
grass_texture_location = terrainShader.uniform("grass");
|
2018-11-26 16:58:30 +00:00
|
|
|
|
rock_texture_location = terrainShader.uniform("rock");
|
|
|
|
|
alpha_texture_location = terrainShader.uniform("alpha");
|
|
|
|
|
road_texture_location = terrainShader.uniform("road");
|
|
|
|
|
road_specular_location = terrainShader.uniform("specular_road");
|
2018-11-26 12:11:05 +00:00
|
|
|
|
|
2018-11-13 08:35:18 +00:00
|
|
|
|
//Create a texture and framebuffer for the background
|
2018-11-26 08:59:16 +00:00
|
|
|
|
glGenFramebuffers(1, &backgroundFBO);
|
|
|
|
|
glGenTextures(1, &backgroundTexture);
|
2018-11-13 08:35:18 +00:00
|
|
|
|
|
|
|
|
|
//Align camera to view a reasonable part of the terrain
|
|
|
|
|
camera().SetSceneExtent(nse::math::BoundingBox<float, 3>(Eigen::Vector3f(0, 0, 0), Eigen::Vector3f(PATCH_SIZE - 1, 0, PATCH_SIZE - 1)));
|
2018-11-26 08:59:16 +00:00
|
|
|
|
camera().FocusOnPoint(0.5f * Eigen::Vector3f(PATCH_SIZE - 1, 15, PATCH_SIZE - 1));
|
2018-11-13 08:35:18 +00:00
|
|
|
|
camera().Zoom(-30);
|
|
|
|
|
camera().RotateAroundFocusPointLocal(Eigen::AngleAxisf(-0.5f, Eigen::Vector3f::UnitY()) * Eigen::AngleAxisf(-0.05f, Eigen::Vector3f::UnitX()));
|
|
|
|
|
camera().FixClippingPlanes(0.1, 1000);
|
|
|
|
|
}
|
|
|
|
|
|
2018-11-26 08:59:16 +00:00
|
|
|
|
bool Viewer::resizeEvent(const Eigen::Vector2i &)
|
2018-11-13 08:35:18 +00:00
|
|
|
|
{
|
|
|
|
|
//Re-generate the texture and FBO for the background
|
|
|
|
|
glBindFramebuffer(GL_FRAMEBUFFER, backgroundFBO);
|
|
|
|
|
glBindTexture(GL_TEXTURE_2D, backgroundTexture);
|
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
|
|
|
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width(), height(), 0, GL_RGB, GL_UNSIGNED_BYTE, nullptr);
|
|
|
|
|
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, backgroundTexture, 0);
|
|
|
|
|
auto fboStatus = glCheckFramebufferStatus(GL_FRAMEBUFFER);
|
|
|
|
|
if (fboStatus != GL_FRAMEBUFFER_COMPLETE)
|
|
|
|
|
std::cout << "Warning: Background framebuffer is not complete: " << fboStatus << std::endl;
|
|
|
|
|
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2018-11-16 11:47:55 +00:00
|
|
|
|
inline std::string loadShaderText(const char *path)
|
|
|
|
|
{
|
|
|
|
|
std::ifstream is(path);
|
|
|
|
|
std::string s_save;
|
|
|
|
|
|
|
|
|
|
if (is.is_open())
|
|
|
|
|
{
|
|
|
|
|
s_save.assign(std::istreambuf_iterator<char>(is), std::istreambuf_iterator<char>());
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
std::cout << "could not open " << path << std::endl;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
is.close();
|
|
|
|
|
return s_save;
|
|
|
|
|
}
|
|
|
|
|
|
2018-11-13 08:35:18 +00:00
|
|
|
|
void Viewer::LoadShaders()
|
|
|
|
|
{
|
2018-11-16 11:47:55 +00:00
|
|
|
|
std::string sky_vs = loadShaderText("exercise2/glsl/sky.vert");
|
|
|
|
|
std::string sky_fs = loadShaderText("exercise2/glsl/sky.frag");
|
|
|
|
|
|
|
|
|
|
std::string terrain_vs = loadShaderText("exercise2/glsl/terrain.vert");
|
|
|
|
|
std::string terrain_fs = loadShaderText("exercise2/glsl/terrain.frag");
|
|
|
|
|
|
|
|
|
|
skyShader.init("Sky Shader", sky_vs, sky_fs);
|
|
|
|
|
terrainShader.init("Terrain Shader", terrain_vs, terrain_fs);
|
2018-11-13 08:35:18 +00:00
|
|
|
|
}
|
|
|
|
|
|
2018-11-26 08:59:16 +00:00
|
|
|
|
GLuint CreateTexture(const unsigned char *fileData, size_t fileLength, bool repeat = true)
|
2018-11-13 08:35:18 +00:00
|
|
|
|
{
|
|
|
|
|
GLuint textureName;
|
|
|
|
|
int textureWidth, textureHeight, textureChannels;
|
|
|
|
|
auto pixelData = stbi_load_from_memory(fileData, fileLength, &textureWidth, &textureHeight, &textureChannels, 3);
|
2018-11-26 12:11:05 +00:00
|
|
|
|
|
|
|
|
|
GLenum provided_format;
|
|
|
|
|
|
|
|
|
|
if (textureChannels == 1)
|
|
|
|
|
{
|
|
|
|
|
provided_format = GL_R;
|
|
|
|
|
}
|
|
|
|
|
else if (textureChannels == 2)
|
|
|
|
|
{
|
|
|
|
|
provided_format = GL_RG;
|
|
|
|
|
}
|
|
|
|
|
else if (textureChannels == 3)
|
|
|
|
|
{
|
|
|
|
|
provided_format = GL_RGB;
|
|
|
|
|
}
|
|
|
|
|
else if (textureChannels == 4)
|
|
|
|
|
{
|
|
|
|
|
provided_format = GL_RGBA;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
glGenTextures(1, &textureName);
|
|
|
|
|
glBindTexture(GL_TEXTURE_2D, textureName);
|
|
|
|
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, textureWidth, textureHeight, 0, provided_format, GL_UNSIGNED_BYTE, pixelData);
|
|
|
|
|
|
|
|
|
|
glGenerateMipmap(GL_TEXTURE_2D);
|
|
|
|
|
|
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
|
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR_MIPMAP_LINEAR);
|
|
|
|
|
|
|
|
|
|
if (repeat)
|
|
|
|
|
{
|
|
|
|
|
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
|
|
|
|
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
|
|
|
|
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
|
|
|
|
}
|
|
|
|
|
|
2018-11-13 08:35:18 +00:00
|
|
|
|
stbi_image_free(pixelData);
|
|
|
|
|
return textureName;
|
|
|
|
|
}
|
|
|
|
|
|
2018-11-26 16:58:30 +00:00
|
|
|
|
std::string vec4_to_str(Eigen::Vector4f &v)
|
|
|
|
|
{
|
|
|
|
|
std::stringstream ss;
|
|
|
|
|
|
|
|
|
|
ss << "(" << v.x() << ", "
|
|
|
|
|
<< v.y() << ", "
|
|
|
|
|
<< v.z() << ", "
|
|
|
|
|
<< v.w() << ")";
|
|
|
|
|
|
|
|
|
|
//std::cout << ss.str() << std::endl;
|
|
|
|
|
|
|
|
|
|
return ss.str();
|
|
|
|
|
}
|
|
|
|
|
|
2018-11-13 08:35:18 +00:00
|
|
|
|
void Viewer::CreateGeometry()
|
|
|
|
|
{
|
|
|
|
|
//empty VAO for sky
|
|
|
|
|
emptyVAO.generate();
|
|
|
|
|
|
2018-11-26 08:59:16 +00:00
|
|
|
|
//terrain VAO
|
2018-11-13 08:35:18 +00:00
|
|
|
|
terrainVAO.generate();
|
|
|
|
|
terrainVAO.bind();
|
2018-11-26 08:59:16 +00:00
|
|
|
|
|
2018-11-13 08:35:18 +00:00
|
|
|
|
std::vector<Eigen::Vector4f> positions;
|
|
|
|
|
std::vector<uint32_t> indices;
|
2018-11-26 08:59:16 +00:00
|
|
|
|
|
2018-11-13 08:35:18 +00:00
|
|
|
|
/*Generate positions and indices for a terrain patch with a
|
|
|
|
|
single triangle strip */
|
|
|
|
|
|
2018-11-26 08:59:16 +00:00
|
|
|
|
for (int i = 0; i < PATCH_SIZE; i++)
|
|
|
|
|
{
|
|
|
|
|
for (int j = 0; j < PATCH_SIZE; j++)
|
|
|
|
|
{
|
2018-11-26 16:58:30 +00:00
|
|
|
|
positions.emplace_back((float)j, 0.0f, (float)i, 1.0f);
|
2018-11-16 08:27:11 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// full x direction, we skip x = 255 inside the loop
|
|
|
|
|
// decrease y direction by 1
|
2018-11-26 08:59:16 +00:00
|
|
|
|
int count = (PATCH_SIZE) * (PATCH_SIZE - 1);
|
2018-11-16 08:27:11 +00:00
|
|
|
|
|
2018-11-26 08:59:16 +00:00
|
|
|
|
for (int k = 0; k < count; k++)
|
|
|
|
|
{
|
2018-11-16 08:27:11 +00:00
|
|
|
|
|
|
|
|
|
// skip creating triangles on last x in row
|
2018-11-26 16:58:30 +00:00
|
|
|
|
/*
|
|
|
|
|
int end_of_x = k % (PATCH_SIZE);
|
2018-11-16 08:27:11 +00:00
|
|
|
|
|
2018-11-26 08:59:16 +00:00
|
|
|
|
if (end_of_x == 0)
|
|
|
|
|
{
|
2018-11-16 08:27:11 +00:00
|
|
|
|
continue;
|
|
|
|
|
}
|
2018-11-26 16:58:30 +00:00
|
|
|
|
*/
|
2018-11-16 08:27:11 +00:00
|
|
|
|
|
|
|
|
|
indices.emplace_back(k);
|
|
|
|
|
indices.emplace_back(k + PATCH_SIZE);
|
2018-11-16 11:47:55 +00:00
|
|
|
|
//indices.emplace_back(k + 1);
|
|
|
|
|
//indices.emplace_back(k + 1 + PATCH_SIZE);
|
2018-11-16 08:27:11 +00:00
|
|
|
|
}
|
|
|
|
|
|
2018-11-13 08:35:18 +00:00
|
|
|
|
terrainShader.bind();
|
|
|
|
|
terrainPositions.uploadData(positions).bindToAttribute("position");
|
|
|
|
|
terrainIndices.uploadData(indices.size() * sizeof(uint32_t), indices.data());
|
|
|
|
|
|
2018-11-26 16:58:30 +00:00
|
|
|
|
referenceVAO.generate();
|
|
|
|
|
referenceVAO.bind();
|
|
|
|
|
|
|
|
|
|
std::vector<Eigen::Vector4f> ref_pos;
|
|
|
|
|
std::vector<uint32_t> ref_ind;
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < PATCH_SIZE; i++)
|
|
|
|
|
{
|
|
|
|
|
for (int j = 0; j < PATCH_SIZE; j++)
|
|
|
|
|
{
|
|
|
|
|
ref_pos.emplace_back((float)j, 0.0f, (float)i, 1.0f);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int index_width = PATCH_SIZE - 1;
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < index_width; i++)
|
|
|
|
|
{
|
|
|
|
|
for (int j = 0; j < index_width; j++)
|
|
|
|
|
{
|
|
|
|
|
int p1 = i + (PATCH_SIZE * j);
|
|
|
|
|
int p2 = i + (PATCH_SIZE * j) + 1;
|
|
|
|
|
int p3 = i + (PATCH_SIZE * (j + 1));
|
|
|
|
|
int p4 = i + (PATCH_SIZE * (j + 1)) + 1;
|
|
|
|
|
|
|
|
|
|
ref_ind.emplace_back(p1);
|
|
|
|
|
ref_ind.emplace_back(p3);
|
|
|
|
|
ref_ind.emplace_back(p2);
|
|
|
|
|
|
|
|
|
|
ref_ind.emplace_back(p3);
|
|
|
|
|
ref_ind.emplace_back(p2);
|
|
|
|
|
ref_ind.emplace_back(p4);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
referenceVB.uploadData(ref_pos)
|
|
|
|
|
.bindToAttribute("position");
|
|
|
|
|
referenceIB.uploadData(ref_ind.size() * sizeof(uint32_t), ref_ind.data());
|
|
|
|
|
|
2018-11-13 08:35:18 +00:00
|
|
|
|
//textures
|
2018-11-26 08:59:16 +00:00
|
|
|
|
grassTexture = CreateTexture((unsigned char *)grass_jpg, grass_jpg_size);
|
|
|
|
|
rockTexture = CreateTexture((unsigned char *)rock_jpg, rock_jpg_size);
|
|
|
|
|
roadColorTexture = CreateTexture((unsigned char *)roadcolor_jpg, roadcolor_jpg_size);
|
|
|
|
|
roadNormalMap = CreateTexture((unsigned char *)roadnormals_jpg, roadnormals_jpg_size);
|
|
|
|
|
roadSpecularMap = CreateTexture((unsigned char *)roadspecular_jpg, roadspecular_jpg_size);
|
|
|
|
|
alphaMap = CreateTexture((unsigned char *)alpha_jpg, alpha_jpg_size, false);
|
2018-11-13 08:35:18 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Viewer::RenderSky()
|
|
|
|
|
{
|
|
|
|
|
Eigen::Matrix4f skyView = view;
|
|
|
|
|
for (int i = 0; i < 3; ++i)
|
|
|
|
|
skyView.col(i).normalize();
|
|
|
|
|
skyView.col(3).head<3>().setZero();
|
|
|
|
|
Eigen::Matrix4f skyMvp = proj * skyView;
|
|
|
|
|
glDepthMask(GL_FALSE);
|
|
|
|
|
glEnable(GL_DEPTH_CLAMP);
|
|
|
|
|
emptyVAO.bind();
|
|
|
|
|
skyShader.bind();
|
|
|
|
|
skyShader.setUniform("mvp", skyMvp);
|
|
|
|
|
glDrawArrays(GL_TRIANGLE_STRIP, 0, 6);
|
|
|
|
|
glDisable(GL_DEPTH_CLAMP);
|
|
|
|
|
glDepthMask(GL_TRUE);
|
|
|
|
|
|
|
|
|
|
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, backgroundFBO);
|
|
|
|
|
glBlitFramebuffer(0, 0, width(), height(), 0, 0, width(), height(), GL_COLOR_BUFFER_BIT, GL_NEAREST);
|
|
|
|
|
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
|
|
|
|
|
}
|
|
|
|
|
|
2018-11-26 08:59:16 +00:00
|
|
|
|
void CalculateViewFrustum(const Eigen::Matrix4f &mvp, Eigen::Vector4f *frustumPlanes, nse::math::BoundingBox<float, 3> &bbox)
|
2018-11-13 08:35:18 +00:00
|
|
|
|
{
|
|
|
|
|
frustumPlanes[0] = (mvp.row(3) + mvp.row(0)).transpose();
|
|
|
|
|
frustumPlanes[1] = (mvp.row(3) - mvp.row(0)).transpose();
|
|
|
|
|
frustumPlanes[2] = (mvp.row(3) + mvp.row(1)).transpose();
|
|
|
|
|
frustumPlanes[3] = (mvp.row(3) - mvp.row(1)).transpose();
|
|
|
|
|
frustumPlanes[4] = (mvp.row(3) + mvp.row(2)).transpose();
|
|
|
|
|
frustumPlanes[5] = (mvp.row(3) - mvp.row(2)).transpose();
|
|
|
|
|
|
|
|
|
|
Eigen::Matrix4f invMvp = mvp.inverse();
|
|
|
|
|
bbox.reset();
|
2018-11-26 08:59:16 +00:00
|
|
|
|
for (int x = -1; x <= 1; x += 2)
|
|
|
|
|
for (int y = -1; y <= 1; y += 2)
|
2018-11-13 08:35:18 +00:00
|
|
|
|
for (int z = -1; z <= 1; z += 2)
|
2018-11-26 08:59:16 +00:00
|
|
|
|
{
|
|
|
|
|
Eigen::Vector4f corner = invMvp * Eigen::Vector4f(x, y, z, 1);
|
|
|
|
|
corner /= corner.w();
|
|
|
|
|
bbox.expand(corner.head<3>());
|
|
|
|
|
}
|
2018-11-13 08:35:18 +00:00
|
|
|
|
}
|
|
|
|
|
|
2018-11-26 08:59:16 +00:00
|
|
|
|
bool IsBoxCompletelyBehindPlane(const Eigen::Vector3f &boxMin, const Eigen::Vector3f &boxMax, const Eigen::Vector4f &plane)
|
2018-11-13 08:35:18 +00:00
|
|
|
|
{
|
2018-11-26 08:59:16 +00:00
|
|
|
|
return plane.dot(Eigen::Vector4f(boxMin.x(), boxMin.y(), boxMin.z(), 1)) < 0 &&
|
|
|
|
|
plane.dot(Eigen::Vector4f(boxMin.x(), boxMin.y(), boxMax.z(), 1)) < 0 &&
|
|
|
|
|
plane.dot(Eigen::Vector4f(boxMin.x(), boxMax.y(), boxMin.z(), 1)) < 0 &&
|
|
|
|
|
plane.dot(Eigen::Vector4f(boxMin.x(), boxMax.y(), boxMin.z(), 1)) < 0 &&
|
|
|
|
|
plane.dot(Eigen::Vector4f(boxMax.x(), boxMin.y(), boxMin.z(), 1)) < 0 &&
|
|
|
|
|
plane.dot(Eigen::Vector4f(boxMax.x(), boxMin.y(), boxMax.z(), 1)) < 0 &&
|
|
|
|
|
plane.dot(Eigen::Vector4f(boxMax.x(), boxMax.y(), boxMin.z(), 1)) < 0 &&
|
|
|
|
|
plane.dot(Eigen::Vector4f(boxMax.x(), boxMax.y(), boxMin.z(), 1)) < 0;
|
2018-11-13 08:35:18 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Viewer::drawContents()
|
|
|
|
|
{
|
|
|
|
|
camera().ComputeCameraMatrices(view, proj);
|
|
|
|
|
|
|
|
|
|
Eigen::Matrix4f mvp = proj * view;
|
|
|
|
|
Eigen::Vector3f cameraPosition = view.inverse().col(3).head<3>();
|
|
|
|
|
int visiblePatches = 0;
|
|
|
|
|
|
|
|
|
|
RenderSky();
|
2018-11-26 08:59:16 +00:00
|
|
|
|
|
2018-11-13 08:35:18 +00:00
|
|
|
|
//render terrain
|
|
|
|
|
glEnable(GL_DEPTH_TEST);
|
2018-11-26 16:58:30 +00:00
|
|
|
|
|
|
|
|
|
if (REFERENCE)
|
|
|
|
|
{
|
|
|
|
|
referenceVAO.bind();
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
terrainVAO.bind();
|
|
|
|
|
}
|
|
|
|
|
|
2018-11-26 08:59:16 +00:00
|
|
|
|
terrainShader.bind();
|
|
|
|
|
|
2018-11-13 08:35:18 +00:00
|
|
|
|
terrainShader.setUniform("screenSize", Eigen::Vector2f(width(), height()), false);
|
|
|
|
|
terrainShader.setUniform("mvp", mvp);
|
|
|
|
|
terrainShader.setUniform("cameraPos", cameraPosition, false);
|
|
|
|
|
|
2018-11-26 12:11:05 +00:00
|
|
|
|
glActiveTexture(GL_TEXTURE0);
|
|
|
|
|
glBindTexture(GL_TEXTURE_2D, grassTexture);
|
|
|
|
|
glUniform1i(grass_texture_location, 0);
|
|
|
|
|
|
2018-11-26 16:58:30 +00:00
|
|
|
|
glActiveTexture(GL_TEXTURE1);
|
|
|
|
|
glBindTexture(GL_TEXTURE_2D, rockTexture);
|
|
|
|
|
glUniform1i(rock_texture_location, 1);
|
|
|
|
|
|
|
|
|
|
glActiveTexture(GL_TEXTURE2);
|
|
|
|
|
glBindTexture(GL_TEXTURE_2D, alphaMap);
|
|
|
|
|
glUniform1i(alpha_texture_location, 2);
|
|
|
|
|
|
|
|
|
|
glActiveTexture(GL_TEXTURE3);
|
|
|
|
|
glBindTexture(GL_TEXTURE_2D, roadColorTexture);
|
|
|
|
|
glUniform1i(road_texture_location, 3);
|
|
|
|
|
|
|
|
|
|
glActiveTexture(GL_TEXTURE4);
|
|
|
|
|
glBindTexture(GL_TEXTURE_2D, roadSpecularMap);
|
|
|
|
|
glUniform1i(road_specular_location, 4);
|
|
|
|
|
|
|
|
|
|
if (REFERENCE)
|
|
|
|
|
{
|
|
|
|
|
glDrawElements(GL_TRIANGLES, (PATCH_SIZE - 1) * (PATCH_SIZE - 1) * 6, GL_UNSIGNED_INT, 0);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
glPrimitiveRestartIndex(PATCH_SIZE * 2);
|
|
|
|
|
glDrawElements(GL_TRIANGLE_STRIP, (PATCH_SIZE - 1) * PATCH_SIZE * 2, GL_UNSIGNED_INT, 0);
|
|
|
|
|
}
|
2018-11-26 08:59:16 +00:00
|
|
|
|
|
2018-11-13 08:35:18 +00:00
|
|
|
|
//Render text
|
|
|
|
|
nvgBeginFrame(mNVGContext, width(), height(), mPixelRatio);
|
|
|
|
|
std::string text = "Patches visible: " + std::to_string(visiblePatches);
|
|
|
|
|
nvgText(mNVGContext, 10, 20, text.c_str(), nullptr);
|
|
|
|
|
nvgEndFrame(mNVGContext);
|
|
|
|
|
}
|