Merge branch 'opengl_shaders'
This commit is contained in:
commit
7d2d022a98
60 changed files with 2207 additions and 763 deletions
|
@ -4,7 +4,7 @@
|
|||
|
||||
ColorProfile::ColorProfile()
|
||||
{
|
||||
setToneMapping(TONE_MAPPING_UNCHARTED, 2.0);
|
||||
setToneMapping(TONE_MAPPING_UNCHARTED, 1.6);
|
||||
}
|
||||
|
||||
ColorProfile::ColorProfile(ToneMappingOperator tonemapper, double exposure)
|
||||
|
|
|
@ -4,6 +4,9 @@
|
|||
#include "basics_global.h"
|
||||
|
||||
#include "Vector3.h"
|
||||
#ifdef QT_GUI_LIB
|
||||
#include <QMatrix4x4>
|
||||
#endif
|
||||
|
||||
namespace paysages {
|
||||
namespace basics {
|
||||
|
@ -35,6 +38,15 @@ public:
|
|||
|
||||
double getDeterminant() const;
|
||||
|
||||
#ifdef QT_GUI_LIB
|
||||
inline QMatrix4x4 toQMatrix() const {
|
||||
return QMatrix4x4(a, b, c, d,
|
||||
e, f, g, h,
|
||||
i, j, k, l,
|
||||
m, n, o, p);
|
||||
}
|
||||
#endif
|
||||
|
||||
private:
|
||||
double a;
|
||||
double b;
|
||||
|
|
|
@ -19,7 +19,7 @@ Texture2D::~Texture2D()
|
|||
delete[] data;
|
||||
}
|
||||
|
||||
void Texture2D::getSize(int* xsize, int* ysize)
|
||||
void Texture2D::getSize(int* xsize, int* ysize) const
|
||||
{
|
||||
*xsize = this->xsize;
|
||||
*ysize = this->ysize;
|
||||
|
@ -33,7 +33,7 @@ void Texture2D::setPixel(int x, int y, Color col)
|
|||
data[y * xsize + x] = col;
|
||||
}
|
||||
|
||||
Color Texture2D::getPixel(int x, int y)
|
||||
Color Texture2D::getPixel(int x, int y) const
|
||||
{
|
||||
assert(x >= 0 && x < xsize);
|
||||
assert(y >= 0 && y < ysize);
|
||||
|
@ -41,7 +41,7 @@ Color Texture2D::getPixel(int x, int y)
|
|||
return data[y * xsize + x];
|
||||
}
|
||||
|
||||
Color Texture2D::getNearest(double dx, double dy)
|
||||
Color Texture2D::getNearest(double dx, double dy) const
|
||||
{
|
||||
if (dx < 0.0) dx = 0.0;
|
||||
if (dx > 1.0) dx = 1.0;
|
||||
|
@ -57,7 +57,7 @@ Color Texture2D::getNearest(double dx, double dy)
|
|||
return this->data[iy * this->xsize + ix];
|
||||
}
|
||||
|
||||
Color Texture2D::getLinear(double dx, double dy)
|
||||
Color Texture2D::getLinear(double dx, double dy) const
|
||||
{
|
||||
if (dx < 0.0) dx = 0.0;
|
||||
if (dx > 1.0) dx = 1.0;
|
||||
|
@ -89,7 +89,7 @@ Color Texture2D::getLinear(double dx, double dy)
|
|||
return c1.lerp(c2, dy);
|
||||
}
|
||||
|
||||
Color Texture2D::getCubic(double dx, double dy)
|
||||
Color Texture2D::getCubic(double dx, double dy) const
|
||||
{
|
||||
/* TODO */
|
||||
return getLinear(dx, dy);
|
||||
|
@ -122,7 +122,7 @@ void Texture2D::add(Texture2D* source)
|
|||
}
|
||||
}
|
||||
|
||||
void Texture2D::save(PackStream* stream)
|
||||
void Texture2D::save(PackStream* stream) const
|
||||
{
|
||||
int i, n;
|
||||
stream->write(&this->xsize);
|
||||
|
@ -151,17 +151,17 @@ void Texture2D::load(PackStream* stream)
|
|||
class Texture2DWriter:public PictureWriter
|
||||
{
|
||||
public:
|
||||
Texture2DWriter(Texture2D *tex): tex(tex) {}
|
||||
Texture2DWriter(const Texture2D *tex): tex(tex) {}
|
||||
|
||||
virtual unsigned int getPixel(int x, int y) override
|
||||
{
|
||||
return tex->getPixel(x, y).to32BitBGRA();
|
||||
}
|
||||
private:
|
||||
Texture2D *tex;
|
||||
const Texture2D *tex;
|
||||
};
|
||||
|
||||
void Texture2D::saveToFile(const std::string &filepath)
|
||||
void Texture2D::saveToFile(const std::string &filepath) const
|
||||
{
|
||||
Texture2DWriter writer(this);
|
||||
writer.save(filepath, xsize, ysize);
|
||||
|
|
|
@ -12,17 +12,17 @@ public:
|
|||
Texture2D(int xsize, int ysize);
|
||||
~Texture2D();
|
||||
|
||||
void getSize(int* xsize, int* ysize);
|
||||
void getSize(int* xsize, int* ysize) const;
|
||||
void setPixel(int x, int y, Color col);
|
||||
Color getPixel(int x, int y);
|
||||
Color getNearest(double dx, double dy);
|
||||
Color getLinear(double dx, double dy);
|
||||
Color getCubic(double dx, double dy);
|
||||
Color getPixel(int x, int y) const;
|
||||
Color getNearest(double dx, double dy) const;
|
||||
Color getLinear(double dx, double dy) const;
|
||||
Color getCubic(double dx, double dy) const;
|
||||
void fill(Color col);
|
||||
void add(Texture2D* other);
|
||||
void save(PackStream* stream);
|
||||
void save(PackStream* stream) const;
|
||||
void load(PackStream* stream);
|
||||
void saveToFile(const std::string &filepath);
|
||||
void saveToFile(const std::string &filepath) const;
|
||||
|
||||
private:
|
||||
int xsize;
|
||||
|
|
|
@ -20,7 +20,7 @@ Texture3D::~Texture3D()
|
|||
delete[] data;
|
||||
}
|
||||
|
||||
void Texture3D::getSize(int* xsize, int* ysize, int* zsize)
|
||||
void Texture3D::getSize(int* xsize, int* ysize, int* zsize) const
|
||||
{
|
||||
*xsize = this->xsize;
|
||||
*ysize = this->ysize;
|
||||
|
@ -36,7 +36,7 @@ void Texture3D::setPixel(int x, int y, int z, Color col)
|
|||
this->data[z * this->xsize * this->ysize + y * this->xsize + x] = col;
|
||||
}
|
||||
|
||||
Color Texture3D::getPixel(int x, int y, int z)
|
||||
Color Texture3D::getPixel(int x, int y, int z) const
|
||||
{
|
||||
assert(x >= 0 && x < this->xsize);
|
||||
assert(y >= 0 && y < this->ysize);
|
||||
|
@ -45,7 +45,7 @@ Color Texture3D::getPixel(int x, int y, int z)
|
|||
return this->data[z * this->xsize * this->ysize + y * this->xsize + x];
|
||||
}
|
||||
|
||||
Color Texture3D::getNearest(double dx, double dy, double dz)
|
||||
Color Texture3D::getNearest(double dx, double dy, double dz) const
|
||||
{
|
||||
if (dx < 0.0) dx = 0.0;
|
||||
if (dx > 1.0) dx = 1.0;
|
||||
|
@ -65,7 +65,7 @@ Color Texture3D::getNearest(double dx, double dy, double dz)
|
|||
return this->data[iz * this->xsize * this->ysize + iy * this->xsize + ix];
|
||||
}
|
||||
|
||||
Color Texture3D::getLinear(double dx, double dy, double dz)
|
||||
Color Texture3D::getLinear(double dx, double dy, double dz) const
|
||||
{
|
||||
if (dx < 0.0) dx = 0.0;
|
||||
if (dx > 1.0) dx = 1.0;
|
||||
|
@ -112,7 +112,7 @@ Color Texture3D::getLinear(double dx, double dy, double dz)
|
|||
return cy1.lerp(cy2, dz);
|
||||
}
|
||||
|
||||
Color Texture3D::getCubic(double dx, double dy, double dz)
|
||||
Color Texture3D::getCubic(double dx, double dy, double dz) const
|
||||
{
|
||||
/* TODO */
|
||||
return getLinear(dx, dy, dz);
|
||||
|
@ -146,7 +146,7 @@ void Texture3D::add(Texture3D* source)
|
|||
}
|
||||
}
|
||||
|
||||
void Texture3D::save(PackStream* stream)
|
||||
void Texture3D::save(PackStream* stream) const
|
||||
{
|
||||
int i, n;
|
||||
stream->write(&this->xsize);
|
||||
|
@ -177,7 +177,7 @@ void Texture3D::load(PackStream* stream)
|
|||
class Texture3DWriter:public PictureWriter
|
||||
{
|
||||
public:
|
||||
Texture3DWriter(Texture3D *tex): tex(tex) {}
|
||||
Texture3DWriter(const Texture3D *tex): tex(tex) {}
|
||||
|
||||
virtual unsigned int getPixel(int x, int y) override
|
||||
{
|
||||
|
@ -190,10 +190,10 @@ public:
|
|||
return tex->getPixel(x, y, z).to32BitBGRA();
|
||||
}
|
||||
private:
|
||||
Texture3D *tex;
|
||||
const Texture3D *tex;
|
||||
};
|
||||
|
||||
void Texture3D::saveToFile(const std::string &filepath)
|
||||
void Texture3D::saveToFile(const std::string &filepath) const
|
||||
{
|
||||
Texture3DWriter writer(this);
|
||||
writer.save(filepath, xsize, ysize * zsize);
|
||||
|
|
|
@ -12,17 +12,17 @@ public:
|
|||
Texture3D(int xsize, int ysize, int zsize);
|
||||
~Texture3D();
|
||||
|
||||
void getSize(int* xsize, int* ysize, int* zsize);
|
||||
void getSize(int* xsize, int* ysize, int* zsize) const;
|
||||
void setPixel(int x, int y, int z, Color col);
|
||||
Color getPixel(int x, int y, int z);
|
||||
Color getNearest(double dx, double dy, double dz);
|
||||
Color getLinear(double dx, double dy, double dz);
|
||||
Color getCubic(double dx, double dy, double dz);
|
||||
Color getPixel(int x, int y, int z) const;
|
||||
Color getNearest(double dx, double dy, double dz) const;
|
||||
Color getLinear(double dx, double dy, double dz) const;
|
||||
Color getCubic(double dx, double dy, double dz) const;
|
||||
void fill(Color col);
|
||||
void add(Texture3D* other);
|
||||
void save(PackStream* stream);
|
||||
void save(PackStream* stream) const;
|
||||
void load(PackStream* stream);
|
||||
void saveToFile(const std::string &filepath);
|
||||
void saveToFile(const std::string &filepath) const;
|
||||
|
||||
private:
|
||||
int xsize;
|
||||
|
|
|
@ -21,7 +21,7 @@ Texture4D::~Texture4D()
|
|||
delete[] data;
|
||||
}
|
||||
|
||||
void Texture4D::getSize(int* xsize, int* ysize, int* zsize, int* wsize)
|
||||
void Texture4D::getSize(int* xsize, int* ysize, int* zsize, int* wsize) const
|
||||
{
|
||||
*xsize = this->xsize;
|
||||
*ysize = this->ysize;
|
||||
|
@ -39,7 +39,7 @@ void Texture4D::setPixel(int x, int y, int z, int w, Color col)
|
|||
this->data[w * this->xsize * this->ysize * this->zsize + z * this->xsize * this->ysize + y * this->xsize + x] = col;
|
||||
}
|
||||
|
||||
Color Texture4D::getPixel(int x, int y, int z, int w)
|
||||
Color Texture4D::getPixel(int x, int y, int z, int w) const
|
||||
{
|
||||
assert(x >= 0 && x < this->xsize);
|
||||
assert(y >= 0 && y < this->ysize);
|
||||
|
@ -49,7 +49,7 @@ Color Texture4D::getPixel(int x, int y, int z, int w)
|
|||
return this->data[w * this->xsize * this->ysize * this->zsize + z * this->xsize * this->ysize + y * this->xsize + x];
|
||||
}
|
||||
|
||||
Color Texture4D::getNearest(double dx, double dy, double dz, double dw)
|
||||
Color Texture4D::getNearest(double dx, double dy, double dz, double dw) const
|
||||
{
|
||||
if (dx < 0.0) dx = 0.0;
|
||||
if (dx > 1.0) dx = 1.0;
|
||||
|
@ -73,7 +73,7 @@ Color Texture4D::getNearest(double dx, double dy, double dz, double dw)
|
|||
return this->data[iw * this->xsize * this->ysize * this->zsize + iz * this->xsize * this->ysize + iy * this->xsize + ix];
|
||||
}
|
||||
|
||||
Color Texture4D::getLinear(double dx, double dy, double dz, double dw)
|
||||
Color Texture4D::getLinear(double dx, double dy, double dz, double dw) const
|
||||
{
|
||||
if (dx < 0.0) dx = 0.0;
|
||||
if (dx > 1.0) dx = 1.0;
|
||||
|
@ -143,7 +143,7 @@ Color Texture4D::getLinear(double dx, double dy, double dz, double dw)
|
|||
return cz1.lerp(cz2, dw);
|
||||
}
|
||||
|
||||
Color Texture4D::getCubic(double dx, double dy, double dz, double dw)
|
||||
Color Texture4D::getCubic(double dx, double dy, double dz, double dw) const
|
||||
{
|
||||
/* TODO */
|
||||
return getLinear(dx, dy, dz, dw);
|
||||
|
@ -178,7 +178,7 @@ void Texture4D::add(Texture4D* source)
|
|||
}
|
||||
}
|
||||
|
||||
void Texture4D::save(PackStream* stream)
|
||||
void Texture4D::save(PackStream* stream) const
|
||||
{
|
||||
int i, n;
|
||||
stream->write(&this->xsize);
|
||||
|
@ -212,7 +212,7 @@ void Texture4D::load(PackStream* stream)
|
|||
class Texture4DWriter:public PictureWriter
|
||||
{
|
||||
public:
|
||||
Texture4DWriter(Texture4D *tex): tex(tex) {}
|
||||
Texture4DWriter(const Texture4D *tex): tex(tex) {}
|
||||
|
||||
virtual unsigned int getPixel(int x, int y) override
|
||||
{
|
||||
|
@ -228,10 +228,10 @@ public:
|
|||
return tex->getPixel(x, y, z, w).to32BitBGRA();
|
||||
}
|
||||
private:
|
||||
Texture4D *tex;
|
||||
const Texture4D *tex;
|
||||
};
|
||||
|
||||
void Texture4D::saveToFile(const std::string &filepath)
|
||||
void Texture4D::saveToFile(const std::string &filepath) const
|
||||
{
|
||||
Texture4DWriter writer(this);
|
||||
writer.save(filepath, xsize * wsize, ysize * zsize);
|
||||
|
|
|
@ -12,17 +12,17 @@ public:
|
|||
Texture4D(int xsize, int ysize, int zsize, int wsize);
|
||||
~Texture4D();
|
||||
|
||||
void getSize(int* xsize, int* ysize, int* zsize, int* wsize);
|
||||
void getSize(int* xsize, int* ysize, int* zsize, int* wsize) const;
|
||||
void setPixel(int x, int y, int z, int w, Color col);
|
||||
Color getPixel(int x, int y, int z, int w);
|
||||
Color getNearest(double dx, double dy, double dz, double dw);
|
||||
Color getLinear(double dx, double dy, double dz, double dw);
|
||||
Color getCubic(double dx, double dy, double dz, double dw);
|
||||
Color getPixel(int x, int y, int z, int w) const;
|
||||
Color getNearest(double dx, double dy, double dz, double dw) const;
|
||||
Color getLinear(double dx, double dy, double dz, double dw) const;
|
||||
Color getCubic(double dx, double dy, double dz, double dw) const;
|
||||
void fill(Color col);
|
||||
void add(Texture4D* other);
|
||||
void save(PackStream* stream);
|
||||
void save(PackStream* stream) const;
|
||||
void load(PackStream* stream);
|
||||
void saveToFile(const std::string &filepath);
|
||||
void saveToFile(const std::string &filepath) const;
|
||||
|
||||
private:
|
||||
int xsize;
|
||||
|
|
|
@ -20,6 +20,9 @@ namespace basics {
|
|||
class NoiseGenerator;
|
||||
class Curve;
|
||||
class ColorProfile;
|
||||
class Texture2D;
|
||||
class Texture3D;
|
||||
class Texture4D;
|
||||
}
|
||||
}
|
||||
using namespace paysages::basics;
|
||||
|
|
|
@ -36,6 +36,7 @@ public:
|
|||
inline double getRoll() const {return roll;}
|
||||
inline Vector3 getDirection() const {return Vector3(direction);}
|
||||
inline Vector3 getDirectionNormalized() const {return forward;}
|
||||
inline const Matrix4 &getTransformationMatrix() const {return projector;}
|
||||
inline VectorSpherical getDirectionSpherical() const {return direction;}
|
||||
inline CameraPerspective getPerspective() const {return perspective;}
|
||||
|
||||
|
|
|
@ -199,8 +199,8 @@ void Scenery::getWater(WaterDefinition* water)
|
|||
void Scenery::checkCameraAboveGround()
|
||||
{
|
||||
Vector3 camera_location = camera->getLocation();
|
||||
double terrain_height = terrain->getInterpolatedHeight(camera_location.x, camera_location.z, 1, 1) + 0.5;
|
||||
double water_height = terrain->getWaterHeight() + 0.5;
|
||||
double terrain_height = terrain->getInterpolatedHeight(camera_location.x, camera_location.z, 1, 1) + 2.0;
|
||||
double water_height = terrain->getWaterHeight() + 1.5;
|
||||
if (camera_location.y < water_height || camera_location.y < terrain_height)
|
||||
{
|
||||
double diff = ((water_height > terrain_height) ? water_height : terrain_height) - camera_location.y;
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#define DEFINITION_GLOBAL_H
|
||||
|
||||
#include <QtCore/qglobal.h>
|
||||
|
||||
#if defined(DEFINITION_LIBRARY)
|
||||
# define DEFINITIONSHARED_EXPORT Q_DECL_EXPORT
|
||||
#else
|
||||
|
|
|
@ -1,170 +0,0 @@
|
|||
#include "BaseExplorerChunk.h"
|
||||
|
||||
#include <QImage>
|
||||
#include <QGLWidget>
|
||||
#include "ColorProfile.h"
|
||||
|
||||
#ifndef GL_CLAMP_TO_EDGE
|
||||
#define GL_CLAMP_TO_EDGE 0x812F
|
||||
#endif
|
||||
|
||||
BaseExplorerChunk::BaseExplorerChunk(SoftwareRenderer* renderer)
|
||||
{
|
||||
_renderer = renderer;
|
||||
_color_profile = new ColorProfile;
|
||||
|
||||
priority = 0.0;
|
||||
_reset_needed = false;
|
||||
|
||||
_texture = new QImage(1, 1, QImage::Format_ARGB32);
|
||||
_texture_id = 0;
|
||||
_texture_changed = false;
|
||||
_texture_current_size = 0;
|
||||
_texture_max_size = 0;
|
||||
}
|
||||
|
||||
BaseExplorerChunk::~BaseExplorerChunk()
|
||||
{
|
||||
_lock_data.lock();
|
||||
delete _color_profile;
|
||||
delete _texture;
|
||||
_lock_data.unlock();
|
||||
}
|
||||
|
||||
bool BaseExplorerChunk::maintain()
|
||||
{
|
||||
bool subchanged;
|
||||
|
||||
_lock_data.lock();
|
||||
if (_reset_needed)
|
||||
{
|
||||
_reset_needed = false;
|
||||
_texture_current_size = 0;
|
||||
onResetEvent();
|
||||
}
|
||||
_lock_data.unlock();
|
||||
|
||||
subchanged = onMaintainEvent();
|
||||
|
||||
// Improve texture resolution
|
||||
if (_texture_current_size < _texture_max_size)
|
||||
{
|
||||
int new_texture_size = _texture_current_size ? _texture_current_size * 2 : 1;
|
||||
QImage* new_image = new QImage(_texture->scaled(new_texture_size + 1, new_texture_size + 1, Qt::IgnoreAspectRatio, Qt::FastTransformation));
|
||||
for (int j = 0; j <= new_texture_size; j++)
|
||||
{
|
||||
for (int i = 0; i <= new_texture_size; i++)
|
||||
{
|
||||
if (_texture_current_size <= 1 || i % 2 != 0 || j % 2 != 0)
|
||||
{
|
||||
Color color = getTextureColor((double)i / (double)new_texture_size, 1.0 - (double)j / (double)new_texture_size);
|
||||
color = _color_profile->apply(color);
|
||||
color.normalize();
|
||||
new_image->setPixel(i, j, color.to32BitBGRA());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_lock_data.lock();
|
||||
delete _texture;
|
||||
_texture = new_image;
|
||||
_texture_current_size = new_texture_size;
|
||||
_texture_changed = true;
|
||||
_lock_data.unlock();
|
||||
|
||||
/*if (_texture_current_size < 4 && _texture_current_size < _texture_max_size)
|
||||
{
|
||||
maintain();
|
||||
}*/
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return subchanged;
|
||||
}
|
||||
}
|
||||
|
||||
void BaseExplorerChunk::updatePriority(CameraDefinition* camera)
|
||||
{
|
||||
if (_reset_needed || (_texture_max_size > 1 && _texture_current_size <= 1))
|
||||
{
|
||||
priority = 1000.0;
|
||||
}
|
||||
else if (_texture_current_size == _texture_max_size)
|
||||
{
|
||||
priority = -1000.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
priority = getDisplayedSizeHint(camera) - _texture_current_size;
|
||||
}
|
||||
onCameraEvent(camera);
|
||||
}
|
||||
|
||||
void BaseExplorerChunk::render(QGLWidget* widget)
|
||||
{
|
||||
// Put texture in place
|
||||
_lock_data.lock();
|
||||
if (_texture_changed)
|
||||
{
|
||||
_texture_changed = false;
|
||||
if (_texture_id)
|
||||
{
|
||||
widget->deleteTexture(_texture_id);
|
||||
}
|
||||
// TODO Only do the scale if not power-of-two textures are unsupported by GPU
|
||||
_texture_id = widget->bindTexture(_texture->scaled(_texture_current_size, _texture_current_size, Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
|
||||
//_texture_id = widget->bindTexture(*_texture);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
}
|
||||
else
|
||||
{
|
||||
glBindTexture(GL_TEXTURE_2D, _texture_id);
|
||||
}
|
||||
_lock_data.unlock();
|
||||
|
||||
// Delegate poly rendering to subclass
|
||||
if (!_reset_needed)
|
||||
{
|
||||
onRenderEvent(widget);
|
||||
}
|
||||
}
|
||||
|
||||
void BaseExplorerChunk::askReset()
|
||||
{
|
||||
_reset_needed = true;
|
||||
}
|
||||
|
||||
void BaseExplorerChunk::setMaxTextureSize(int size)
|
||||
{
|
||||
_texture_max_size = size;
|
||||
}
|
||||
|
||||
void BaseExplorerChunk::onCameraEvent(CameraDefinition*)
|
||||
{
|
||||
}
|
||||
|
||||
void BaseExplorerChunk::onResetEvent()
|
||||
{
|
||||
}
|
||||
|
||||
bool BaseExplorerChunk::onMaintainEvent()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void BaseExplorerChunk::onRenderEvent(QGLWidget*)
|
||||
{
|
||||
}
|
||||
|
||||
double BaseExplorerChunk::getDisplayedSizeHint(CameraDefinition*)
|
||||
{
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
Color BaseExplorerChunk::getTextureColor(double, double)
|
||||
{
|
||||
return COLOR_TRANSPARENT;
|
||||
}
|
|
@ -1,58 +0,0 @@
|
|||
#ifndef BASEEXPLORERCHUNK_H
|
||||
#define BASEEXPLORERCHUNK_H
|
||||
|
||||
#include "opengl_global.h"
|
||||
|
||||
#include <QMutex>
|
||||
#include "Color.h"
|
||||
|
||||
class QImage;
|
||||
class QGLWidget;
|
||||
|
||||
namespace paysages {
|
||||
namespace opengl {
|
||||
|
||||
class BaseExplorerChunk
|
||||
{
|
||||
public:
|
||||
virtual ~BaseExplorerChunk();
|
||||
|
||||
bool maintain();
|
||||
void updatePriority(CameraDefinition* camera);
|
||||
void render(QGLWidget* widget);
|
||||
|
||||
double priority;
|
||||
protected:
|
||||
BaseExplorerChunk(SoftwareRenderer* renderer);
|
||||
|
||||
inline SoftwareRenderer* renderer() {return _renderer;}
|
||||
|
||||
void askReset();
|
||||
void setMaxTextureSize(int size);
|
||||
|
||||
virtual void onCameraEvent(CameraDefinition* camera);
|
||||
virtual void onResetEvent();
|
||||
virtual bool onMaintainEvent();
|
||||
virtual void onRenderEvent(QGLWidget* widget);
|
||||
virtual double getDisplayedSizeHint(CameraDefinition* camera);
|
||||
virtual Color getTextureColor(double x, double y);
|
||||
|
||||
QMutex _lock_data;
|
||||
|
||||
private:
|
||||
SoftwareRenderer* _renderer;
|
||||
ColorProfile* _color_profile;
|
||||
|
||||
bool _reset_needed;
|
||||
|
||||
QImage* _texture;
|
||||
unsigned int _texture_id;
|
||||
bool _texture_changed;
|
||||
int _texture_current_size;
|
||||
int _texture_max_size;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif // BASEEXPLORERCHUNK_H
|
|
@ -1,148 +0,0 @@
|
|||
#include "ExplorerChunkSky.h"
|
||||
|
||||
#include <cmath>
|
||||
#include <GL/gl.h>
|
||||
#include "CameraDefinition.h"
|
||||
#include "SoftwareRenderer.h"
|
||||
#include "AtmosphereRenderer.h"
|
||||
#include "AtmosphereResult.h"
|
||||
|
||||
ExplorerChunkSky::ExplorerChunkSky(SoftwareRenderer* renderer, double size, SkyboxOrientation orientation) : BaseExplorerChunk(renderer)
|
||||
{
|
||||
_box_size = size;
|
||||
_orientation = orientation;
|
||||
_center = VECTOR_ZERO;
|
||||
|
||||
setMaxTextureSize(256);
|
||||
maintain();
|
||||
}
|
||||
|
||||
void ExplorerChunkSky::onCameraEvent(CameraDefinition* camera)
|
||||
{
|
||||
_center = camera->getLocation();
|
||||
}
|
||||
|
||||
void ExplorerChunkSky::onRenderEvent(QGLWidget*)
|
||||
{
|
||||
double size = _box_size;
|
||||
Vector3 camera = _center;
|
||||
|
||||
glBegin(GL_QUADS);
|
||||
switch (_orientation)
|
||||
{
|
||||
case SKYBOX_NORTH:
|
||||
glTexCoord2d(0.0, 0.0);
|
||||
glVertex3d(camera.x - size, camera.y + size, camera.z - size);
|
||||
glTexCoord2d(0.0, 1.0);
|
||||
glVertex3d(camera.x - size, camera.y - size, camera.z - size);
|
||||
glTexCoord2d(1.0, 1.0);
|
||||
glVertex3d(camera.x + size, camera.y - size, camera.z - size);
|
||||
glTexCoord2d(1.0, 0.0);
|
||||
glVertex3d(camera.x + size, camera.y + size, camera.z - size);
|
||||
break;
|
||||
case SKYBOX_SOUTH:
|
||||
glTexCoord2d(0.0, 0.0);
|
||||
glVertex3d(camera.x + size, camera.y + size, camera.z + size);
|
||||
glTexCoord2d(0.0, 1.0);
|
||||
glVertex3d(camera.x + size, camera.y - size, camera.z + size);
|
||||
glTexCoord2d(1.0, 1.0);
|
||||
glVertex3d(camera.x - size, camera.y - size, camera.z + size);
|
||||
glTexCoord2d(1.0, 0.0);
|
||||
glVertex3d(camera.x - size, camera.y + size, camera.z + size);
|
||||
break;
|
||||
case SKYBOX_EAST:
|
||||
glTexCoord2d(0.0, 0.0);
|
||||
glVertex3d(camera.x + size, camera.y + size, camera.z - size);
|
||||
glTexCoord2d(0.0, 1.0);
|
||||
glVertex3d(camera.x + size, camera.y - size, camera.z - size);
|
||||
glTexCoord2d(1.0, 1.0);
|
||||
glVertex3d(camera.x + size, camera.y - size, camera.z + size);
|
||||
glTexCoord2d(1.0, 0.0);
|
||||
glVertex3d(camera.x + size, camera.y + size, camera.z + size);
|
||||
break;
|
||||
case SKYBOX_WEST:
|
||||
glTexCoord2d(0.0, 0.0);
|
||||
glVertex3d(camera.x - size, camera.y + size, camera.z + size);
|
||||
glTexCoord2d(0.0, 1.0);
|
||||
glVertex3d(camera.x - size, camera.y - size, camera.z + size);
|
||||
glTexCoord2d(1.0, 1.0);
|
||||
glVertex3d(camera.x - size, camera.y - size, camera.z - size);
|
||||
glTexCoord2d(1.0, 0.0);
|
||||
glVertex3d(camera.x - size, camera.y + size, camera.z - size);
|
||||
break;
|
||||
case SKYBOX_TOP:
|
||||
glTexCoord2d(0.0, 0.0);
|
||||
glVertex3d(camera.x - size, camera.y + size, camera.z + size);
|
||||
glTexCoord2d(0.0, 1.0);
|
||||
glVertex3d(camera.x - size, camera.y + size, camera.z - size);
|
||||
glTexCoord2d(1.0, 1.0);
|
||||
glVertex3d(camera.x + size, camera.y + size, camera.z - size);
|
||||
glTexCoord2d(1.0, 0.0);
|
||||
glVertex3d(camera.x + size, camera.y + size, camera.z + size);
|
||||
break;
|
||||
case SKYBOX_BOTTOM:
|
||||
/*glTexCoord2d(0.0, 0.0);
|
||||
glVertex3d(camera.x - size, camera.y - size, camera.z - size);
|
||||
glTexCoord2d(0.0, 1.0);
|
||||
glVertex3d(camera.x - size, camera.y - size, camera.z + size);
|
||||
glTexCoord2d(1.0, 1.0);
|
||||
glVertex3d(camera.x + size, camera.y - size, camera.z + size);
|
||||
glTexCoord2d(1.0, 0.0);
|
||||
glVertex3d(camera.x + size, camera.y - size, camera.z - size);*/
|
||||
break;
|
||||
}
|
||||
glEnd();
|
||||
}
|
||||
|
||||
double ExplorerChunkSky::getDisplayedSizeHint(CameraDefinition*)
|
||||
{
|
||||
return 1000.0;
|
||||
}
|
||||
|
||||
Color ExplorerChunkSky::getTextureColor(double x, double y)
|
||||
{
|
||||
Vector3 location;
|
||||
|
||||
x -= 0.5;
|
||||
y -= 0.5;
|
||||
|
||||
switch (_orientation)
|
||||
{
|
||||
case SKYBOX_NORTH:
|
||||
location.x = x;
|
||||
location.y = -y;
|
||||
location.z = -0.5;
|
||||
break;
|
||||
case SKYBOX_SOUTH:
|
||||
location.x = -x;
|
||||
location.y = -y;
|
||||
location.z = 0.5;
|
||||
break;
|
||||
case SKYBOX_EAST:
|
||||
location.x = 0.5;
|
||||
location.y = -y;
|
||||
location.z = x;
|
||||
break;
|
||||
case SKYBOX_WEST:
|
||||
location.x = -0.5;
|
||||
location.y = -y;
|
||||
location.z = -x;
|
||||
break;
|
||||
case SKYBOX_TOP:
|
||||
location.x = x;
|
||||
location.y = 0.5;
|
||||
location.z = -y;
|
||||
break;
|
||||
case SKYBOX_BOTTOM:
|
||||
location.x = x;
|
||||
location.y = -0.5;
|
||||
location.z = y;
|
||||
break;
|
||||
}
|
||||
location = location.normalize();
|
||||
if (location.y < 0.0)
|
||||
{
|
||||
location.y = 0.0;
|
||||
}
|
||||
return renderer()->getAtmosphereRenderer()->getSkyColor(location).final;
|
||||
}
|
|
@ -1,42 +0,0 @@
|
|||
#ifndef EXPLORERCHUNKSKY_H
|
||||
#define EXPLORERCHUNKSKY_H
|
||||
|
||||
#include "opengl_global.h"
|
||||
|
||||
#include "BaseExplorerChunk.h"
|
||||
|
||||
#include "Vector3.h"
|
||||
|
||||
namespace paysages {
|
||||
namespace opengl {
|
||||
|
||||
enum SkyboxOrientation
|
||||
{
|
||||
SKYBOX_NORTH,
|
||||
SKYBOX_SOUTH,
|
||||
SKYBOX_WEST,
|
||||
SKYBOX_EAST,
|
||||
SKYBOX_TOP,
|
||||
SKYBOX_BOTTOM
|
||||
};
|
||||
|
||||
class OPENGLSHARED_EXPORT ExplorerChunkSky:public BaseExplorerChunk
|
||||
{
|
||||
public:
|
||||
ExplorerChunkSky(SoftwareRenderer* renderer, double size, SkyboxOrientation orientation);
|
||||
|
||||
void onCameraEvent(CameraDefinition* camera);
|
||||
void onRenderEvent(QGLWidget* widget);
|
||||
double getDisplayedSizeHint(CameraDefinition* camera);
|
||||
Color getTextureColor(double x, double y);
|
||||
|
||||
private:
|
||||
SkyboxOrientation _orientation;
|
||||
double _box_size;
|
||||
Vector3 _center;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif // EXPLORERCHUNKSKY_H
|
|
@ -1,13 +1,28 @@
|
|||
#include "ExplorerChunkTerrain.h"
|
||||
|
||||
#include OPENGL_FUNCTIONS_INCLUDE
|
||||
#include <cmath>
|
||||
#include <GL/gl.h>
|
||||
#include <QImage>
|
||||
#include "ColorProfile.h"
|
||||
#include "CameraDefinition.h"
|
||||
#include "SoftwareRenderer.h"
|
||||
#include "OpenGLRenderer.h"
|
||||
#include "TerrainRenderer.h"
|
||||
#include "VertexArray.h"
|
||||
|
||||
ExplorerChunkTerrain::ExplorerChunkTerrain(SoftwareRenderer* renderer, double x, double z, double size, int nbchunks, double water_height) : BaseExplorerChunk(renderer)
|
||||
ExplorerChunkTerrain::ExplorerChunkTerrain(OpenGLRenderer* renderer, double x, double z, double size, int nbchunks, double water_height):
|
||||
_renderer(renderer)
|
||||
{
|
||||
_color_profile = new ColorProfile(ColorProfile::TONE_MAPPING_REIHNARD, 2.0);
|
||||
|
||||
priority = 0.0;
|
||||
_reset_needed = false;
|
||||
|
||||
_texture = new QImage(1, 1, QImage::Format_RGBA8888);
|
||||
texture_id = 0;
|
||||
_texture_changed = false;
|
||||
_texture_current_size = 0;
|
||||
_texture_max_size = 0;
|
||||
|
||||
_startx = x;
|
||||
_startz = z;
|
||||
_size = size;
|
||||
|
@ -18,8 +33,11 @@ ExplorerChunkTerrain::ExplorerChunkTerrain(SoftwareRenderer* renderer, double x,
|
|||
_water_height = water_height;
|
||||
_overwater = false;
|
||||
|
||||
_tessellation_max_size = 32;
|
||||
_tessellation = new double[(_tessellation_max_size + 1) * (_tessellation_max_size + 1)];
|
||||
tessellation_count = 33;
|
||||
tessellated = new VertexArray<TerrainVertex>();
|
||||
tessellated->setGridSize(tessellation_count);
|
||||
tessellated->setAutoGridIndices(tessellation_count);
|
||||
_tessellation_max_size = tessellation_count - 1;
|
||||
_tessellation_current_size = 0;
|
||||
_tessellation_step = _size / (double) _tessellation_max_size;
|
||||
|
||||
|
@ -31,44 +49,108 @@ ExplorerChunkTerrain::ExplorerChunkTerrain(SoftwareRenderer* renderer, double x,
|
|||
ExplorerChunkTerrain::~ExplorerChunkTerrain()
|
||||
{
|
||||
_lock_data.lock();
|
||||
delete [] _tessellation;
|
||||
delete _color_profile;
|
||||
delete _texture;
|
||||
delete tessellated;
|
||||
_lock_data.unlock();
|
||||
}
|
||||
|
||||
void ExplorerChunkTerrain::onResetEvent()
|
||||
bool ExplorerChunkTerrain::maintain()
|
||||
{
|
||||
_tessellation_current_size = 0;
|
||||
_overwater = false;
|
||||
bool subchanged;
|
||||
|
||||
_lock_data.lock();
|
||||
if (_reset_needed)
|
||||
{
|
||||
_reset_needed = false;
|
||||
_texture_current_size = 0;
|
||||
_tessellation_current_size = 0;
|
||||
_overwater = false;
|
||||
}
|
||||
_lock_data.unlock();
|
||||
|
||||
subchanged = onMaintainEvent();
|
||||
|
||||
// Improve texture resolution
|
||||
if (_texture_current_size < _texture_max_size)
|
||||
{
|
||||
int new_texture_size = _texture_current_size ? _texture_current_size * 2 : 1;
|
||||
QImage* new_image = new QImage(_texture->scaled(new_texture_size + 1, new_texture_size + 1, Qt::IgnoreAspectRatio, Qt::FastTransformation));
|
||||
for (int j = 0; j <= new_texture_size; j++)
|
||||
{
|
||||
for (int i = 0; i <= new_texture_size; i++)
|
||||
{
|
||||
if (_texture_current_size <= 1 || i % 2 != 0 || j % 2 != 0)
|
||||
{
|
||||
Color color = getTextureColor((double)i / (double)new_texture_size, (double)j / (double)new_texture_size);
|
||||
//color = _color_profile->apply(color);
|
||||
color.normalize();
|
||||
new_image->setPixel(i, j, color.to32BitRGBA());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_lock_data.lock();
|
||||
delete _texture;
|
||||
_texture = new_image;
|
||||
_texture_current_size = new_texture_size;
|
||||
_texture_changed = true;
|
||||
_lock_data.unlock();
|
||||
|
||||
/*if (_texture_current_size < 4 && _texture_current_size < _texture_max_size)
|
||||
{
|
||||
maintain();
|
||||
}*/
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return subchanged;
|
||||
}
|
||||
}
|
||||
|
||||
bool ExplorerChunkTerrain::onMaintainEvent()
|
||||
{
|
||||
SoftwareRenderer* renderer = this->renderer();
|
||||
|
||||
// Improve heightmap resolution
|
||||
if (_tessellation_current_size < _tessellation_max_size)
|
||||
{
|
||||
int new_tessellation_size = _tessellation_current_size ? _tessellation_current_size * 4 : 2;
|
||||
int old_tessellation_inc = _tessellation_current_size ? _tessellation_max_size / _tessellation_current_size : 1;
|
||||
int new_tessellation_inc = _tessellation_max_size / new_tessellation_size;
|
||||
float internal_step = 1.0f / (float)_tessellation_max_size;
|
||||
for (int j = 0; j <= _tessellation_max_size; j += new_tessellation_inc)
|
||||
{
|
||||
for (int i = 0; i <= _tessellation_max_size; i += new_tessellation_inc)
|
||||
{
|
||||
if (_tessellation_current_size == 0 || i % old_tessellation_inc != 0 || j % old_tessellation_inc != 0)
|
||||
{
|
||||
double height = renderer->getTerrainRenderer()->getHeight(_startx + _tessellation_step * (double) i, _startz + _tessellation_step * (double) j, 1);
|
||||
double x = _startx + _tessellation_step * (float)i;
|
||||
double z = _startz + _tessellation_step * (float)j;
|
||||
|
||||
double height = _renderer->getTerrainRenderer()->getHeight(x, z, 1);
|
||||
if (height >= _water_height)
|
||||
{
|
||||
_overwater = true;
|
||||
}
|
||||
_tessellation[j * (_tessellation_max_size + 1) + i] = height;
|
||||
|
||||
TerrainVertex v;
|
||||
|
||||
v.uv[0] = internal_step * (float)i;
|
||||
v.uv[1] = internal_step * (float)j;
|
||||
|
||||
v.location[0] = x;
|
||||
v.location[1] = height;
|
||||
v.location[2] = z;
|
||||
|
||||
tessellated->setGridVertex(tessellation_count, i, j, v);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_lock_data.lock();
|
||||
_tessellation_current_size = new_tessellation_size;
|
||||
tessellated->setAutoGridIndices(tessellation_count, new_tessellation_inc);
|
||||
_lock_data.unlock();
|
||||
|
||||
if (_tessellation_current_size < 4 && _tessellation_current_size < _tessellation_max_size)
|
||||
|
@ -84,8 +166,21 @@ bool ExplorerChunkTerrain::onMaintainEvent()
|
|||
}
|
||||
}
|
||||
|
||||
void ExplorerChunkTerrain::onCameraEvent(CameraDefinition* camera)
|
||||
void ExplorerChunkTerrain::updatePriority(CameraDefinition* camera)
|
||||
{
|
||||
if (_reset_needed || (_texture_max_size > 1 && _texture_current_size <= 1))
|
||||
{
|
||||
priority = 1000.0;
|
||||
}
|
||||
else if (_texture_current_size == _texture_max_size)
|
||||
{
|
||||
priority = -1000.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
priority = getDisplayedSizeHint(camera) - _texture_current_size;
|
||||
}
|
||||
|
||||
Vector3 camera_location = camera->getLocation();
|
||||
|
||||
// Handle position
|
||||
|
@ -116,33 +211,66 @@ void ExplorerChunkTerrain::onCameraEvent(CameraDefinition* camera)
|
|||
_lock_data.unlock();
|
||||
}
|
||||
|
||||
void ExplorerChunkTerrain::onRenderEvent(QGLWidget*)
|
||||
void ExplorerChunkTerrain::render(QOpenGLShaderProgram* program, OpenGLFunctions* functions)
|
||||
{
|
||||
// Put texture in place
|
||||
_lock_data.lock();
|
||||
int tessellation_size = _tessellation_current_size;
|
||||
double tsize = 1.0 / (double) _tessellation_max_size;
|
||||
if (_texture_changed)
|
||||
{
|
||||
_texture_changed = false;
|
||||
|
||||
// TODO Only do the scale if not power-of-two textures are unsupported by GPU
|
||||
QImage tex = _texture->scaled(_texture_current_size, _texture_current_size, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
|
||||
|
||||
if (texture_id == 0)
|
||||
{
|
||||
GLuint texid;
|
||||
functions->glGenTextures(1, &texid);
|
||||
texture_id = texid;
|
||||
}
|
||||
|
||||
functions->glBindTexture(GL_TEXTURE_2D, texture_id);
|
||||
functions->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
functions->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
functions->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
functions->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
functions->glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex.width(), tex.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, tex.bits());
|
||||
}
|
||||
_lock_data.unlock();
|
||||
|
||||
if (tessellation_size <= 1 or not _overwater)
|
||||
// Render tessellated mesh
|
||||
if (!_reset_needed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
_lock_data.lock();
|
||||
int tessellation_size = _tessellation_current_size;
|
||||
_lock_data.unlock();
|
||||
|
||||
int tessellation_inc = _tessellation_max_size / (double) tessellation_size;
|
||||
for (int j = 0; j < _tessellation_max_size; j += tessellation_inc)
|
||||
{
|
||||
glBegin(GL_QUAD_STRIP);
|
||||
for (int i = 0; i <= _tessellation_max_size; i += tessellation_inc)
|
||||
if (tessellation_size <= 1 or not _overwater)
|
||||
{
|
||||
glTexCoord2d(tsize * (double) i, tsize * (double) j);
|
||||
glVertex3d(_startx + _tessellation_step * (double) i, _tessellation[j * (_tessellation_max_size + 1) + i], _startz + _tessellation_step * (double) j);
|
||||
glTexCoord2d(tsize * (double) i, tsize * (double) (j + tessellation_inc));
|
||||
glVertex3d(_startx + _tessellation_step * (double) i, _tessellation[(j + tessellation_inc) * (_tessellation_max_size + 1) + i], _startz + _tessellation_step * (double) (j + tessellation_inc));
|
||||
return;
|
||||
}
|
||||
glEnd();
|
||||
|
||||
_lock_data.lock(); // TEMP
|
||||
// TEMP
|
||||
functions->glActiveTexture(GL_TEXTURE0 + 3);
|
||||
functions->glBindTexture(GL_TEXTURE_2D, texture_id);
|
||||
program->setUniformValue("groundTexture", 3);
|
||||
|
||||
tessellated->render(program, functions);
|
||||
_lock_data.unlock(); // TEMP
|
||||
}
|
||||
}
|
||||
|
||||
void ExplorerChunkTerrain::askReset()
|
||||
{
|
||||
_reset_needed = true;
|
||||
}
|
||||
|
||||
void ExplorerChunkTerrain::setMaxTextureSize(int size)
|
||||
{
|
||||
_texture_max_size = size;
|
||||
}
|
||||
|
||||
double ExplorerChunkTerrain::getDisplayedSizeHint(CameraDefinition* camera)
|
||||
{
|
||||
double distance;
|
||||
|
@ -170,7 +298,7 @@ double ExplorerChunkTerrain::getDisplayedSizeHint(CameraDefinition* camera)
|
|||
Color ExplorerChunkTerrain::getTextureColor(double x, double y)
|
||||
{
|
||||
Vector3 location = {_startx + x * _size, 0.0, _startz + y * _size};
|
||||
return renderer()->getTerrainRenderer()->getFinalColor(location, 0.01);
|
||||
return _renderer->getTerrainRenderer()->getFinalColor(location, 0.01);
|
||||
}
|
||||
|
||||
Vector3 ExplorerChunkTerrain::getCenter()
|
||||
|
|
|
@ -1,26 +1,41 @@
|
|||
#ifndef EXPLORERCHUNKTERRAIN_H
|
||||
#define EXPLORERCHUNKTERRAIN_H
|
||||
|
||||
#include "BaseExplorerChunk.h"
|
||||
#include "opengl_global.h"
|
||||
|
||||
#include "Vector3.h"
|
||||
#include <QMutex>
|
||||
class QImage;
|
||||
class QOpenGLShaderProgram;
|
||||
|
||||
namespace paysages {
|
||||
namespace opengl {
|
||||
|
||||
class OPENGLSHARED_EXPORT ExplorerChunkTerrain:public BaseExplorerChunk
|
||||
class OPENGLSHARED_EXPORT ExplorerChunkTerrain
|
||||
{
|
||||
public:
|
||||
ExplorerChunkTerrain(SoftwareRenderer* renderer, double x, double z, double size, int nbchunks, double water_height);
|
||||
typedef struct
|
||||
{
|
||||
float location[3];
|
||||
float uv[2];
|
||||
} TerrainVertex;
|
||||
|
||||
public:
|
||||
ExplorerChunkTerrain(OpenGLRenderer* renderer, double x, double z, double size, int nbchunks, double water_height);
|
||||
~ExplorerChunkTerrain();
|
||||
|
||||
void onCameraEvent(CameraDefinition* camera);
|
||||
void onResetEvent();
|
||||
bool maintain();
|
||||
void updatePriority(CameraDefinition* camera);
|
||||
void render(QOpenGLShaderProgram* program, OpenGLFunctions* functions);
|
||||
|
||||
void askReset();
|
||||
void setMaxTextureSize(int size);
|
||||
|
||||
bool onMaintainEvent();
|
||||
void onRenderEvent(QGLWidget* widget);
|
||||
double getDisplayedSizeHint(CameraDefinition* camera);
|
||||
Color getTextureColor(double x, double y);
|
||||
|
||||
double priority;
|
||||
|
||||
private:
|
||||
Vector3 getCenter();
|
||||
|
||||
|
@ -33,11 +48,24 @@ private:
|
|||
double _water_height;
|
||||
bool _overwater;
|
||||
|
||||
double* _tessellation;
|
||||
int tessellation_count;
|
||||
VertexArray<TerrainVertex> *tessellated;
|
||||
int _tessellation_max_size;
|
||||
int _tessellation_current_size;
|
||||
double _tessellation_step;
|
||||
|
||||
QMutex _lock_data;
|
||||
|
||||
OpenGLRenderer* _renderer;
|
||||
ColorProfile* _color_profile;
|
||||
|
||||
bool _reset_needed;
|
||||
|
||||
QImage* _texture;
|
||||
unsigned int texture_id;
|
||||
bool _texture_changed;
|
||||
int _texture_current_size;
|
||||
int _texture_max_size;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
49
src/render/opengl/OpenGLPart.cpp
Normal file
49
src/render/opengl/OpenGLPart.cpp
Normal file
|
@ -0,0 +1,49 @@
|
|||
#include "OpenGLPart.h"
|
||||
|
||||
#include <QDir>
|
||||
#include <cmath>
|
||||
#include "OpenGLRenderer.h"
|
||||
#include "OpenGLShaderProgram.h"
|
||||
#include "CameraDefinition.h"
|
||||
#include "AtmosphereDefinition.h"
|
||||
#include "AtmosphereRenderer.h"
|
||||
#include "Scenery.h"
|
||||
|
||||
OpenGLPart::OpenGLPart(OpenGLRenderer* renderer):
|
||||
renderer(renderer)
|
||||
{
|
||||
}
|
||||
|
||||
OpenGLPart::~OpenGLPart()
|
||||
{
|
||||
QMapIterator<QString, OpenGLShaderProgram*> i(shaders);
|
||||
while (i.hasNext())
|
||||
{
|
||||
i.next();
|
||||
delete i.value();
|
||||
}
|
||||
}
|
||||
|
||||
OpenGLShaderProgram* OpenGLPart::createShader(QString name)
|
||||
{
|
||||
OpenGLShaderProgram* program = new OpenGLShaderProgram(name, renderer);
|
||||
|
||||
if (!shaders.contains(name))
|
||||
{
|
||||
shaders[name] = program;
|
||||
return program;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void OpenGLPart::updateScenery(bool onlyCommon)
|
||||
{
|
||||
// Let subclass do its own collecting
|
||||
if (not onlyCommon)
|
||||
{
|
||||
update();
|
||||
}
|
||||
}
|
44
src/render/opengl/OpenGLPart.h
Normal file
44
src/render/opengl/OpenGLPart.h
Normal file
|
@ -0,0 +1,44 @@
|
|||
#ifndef OPENGLPART_H
|
||||
#define OPENGLPART_H
|
||||
|
||||
#include "opengl_global.h"
|
||||
|
||||
#include <QMap>
|
||||
#include <QString>
|
||||
|
||||
namespace paysages {
|
||||
namespace opengl {
|
||||
|
||||
// Class that can be inherited by scenery parts, to use OpenGL features
|
||||
|
||||
class OPENGLSHARED_EXPORT OpenGLPart
|
||||
{
|
||||
public:
|
||||
OpenGLPart(OpenGLRenderer* renderer);
|
||||
virtual ~OpenGLPart();
|
||||
|
||||
// Initialize the part rendering (create shaders, prepare static textures...)
|
||||
virtual void initialize() = 0;
|
||||
|
||||
// Update parameters from scenery
|
||||
virtual void update() = 0;
|
||||
|
||||
// Do the rendering
|
||||
virtual void render() = 0;
|
||||
|
||||
void updateScenery(bool onlyCommon=false);
|
||||
|
||||
protected:
|
||||
// Create a shader program
|
||||
OpenGLShaderProgram* createShader(QString name);
|
||||
|
||||
// Access to the main scenery renderer
|
||||
OpenGLRenderer* renderer;
|
||||
|
||||
private:
|
||||
QMap<QString, OpenGLShaderProgram*> shaders;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif // OPENGLPART_H
|
|
@ -1,62 +1,147 @@
|
|||
#include "OpenGLRenderer.h"
|
||||
|
||||
#include <cmath>
|
||||
#include <GL/gl.h>
|
||||
#include <GL/glu.h>
|
||||
#include "Scenery.h"
|
||||
#include OPENGL_FUNCTIONS_INCLUDE
|
||||
#include "CameraDefinition.h"
|
||||
#include "OpenGLSharedState.h"
|
||||
#include "OpenGLSkybox.h"
|
||||
#include "OpenGLWater.h"
|
||||
#include "OpenGLTerrain.h"
|
||||
#include "Scenery.h"
|
||||
#include "LightingManager.h"
|
||||
#include "Logs.h"
|
||||
|
||||
#include "GL/glu.h" // TEMP
|
||||
|
||||
OpenGLRenderer::OpenGLRenderer(Scenery* scenery):
|
||||
SoftwareRenderer(scenery)
|
||||
{
|
||||
ready = false;
|
||||
|
||||
functions = new OpenGLFunctions();
|
||||
shared_state = new OpenGLSharedState();
|
||||
|
||||
shared_state->set("viewDistance", 300.0);
|
||||
shared_state->set("exposure", 1.6);
|
||||
|
||||
skybox = new OpenGLSkybox(this);
|
||||
water = new OpenGLWater(this);
|
||||
terrain = new OpenGLTerrain(this);
|
||||
}
|
||||
|
||||
OpenGLRenderer::~OpenGLRenderer()
|
||||
{
|
||||
delete skybox;
|
||||
delete water;
|
||||
delete terrain;
|
||||
|
||||
delete functions;
|
||||
delete shared_state;
|
||||
}
|
||||
|
||||
void OpenGLRenderer::initialize()
|
||||
{
|
||||
glClearColor(0.0, 0.0, 0.0, 0.0);
|
||||
ready = functions->initializeOpenGLFunctions();
|
||||
|
||||
glDisable(GL_LIGHTING);
|
||||
if (ready)
|
||||
{
|
||||
functions->glClearColor(0.0, 0.0, 0.0, 0.0);
|
||||
|
||||
glFrontFace(GL_CCW);
|
||||
glCullFace(GL_BACK);
|
||||
glEnable(GL_CULL_FACE);
|
||||
functions->glDisable(GL_LIGHTING);
|
||||
|
||||
glDepthFunc(GL_LESS);
|
||||
glDepthMask(1);
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
functions->glFrontFace(GL_CCW);
|
||||
functions->glCullFace(GL_BACK);
|
||||
functions->glEnable(GL_CULL_FACE);
|
||||
|
||||
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
|
||||
glEnable(GL_LINE_SMOOTH);
|
||||
glLineWidth(1.0);
|
||||
functions->glDepthFunc(GL_LESS);
|
||||
functions->glDepthMask(1);
|
||||
functions->glEnable(GL_DEPTH_TEST);
|
||||
|
||||
glDisable(GL_FOG);
|
||||
functions->glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
|
||||
functions->glEnable(GL_LINE_SMOOTH);
|
||||
functions->glLineWidth(1.0);
|
||||
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
functions->glDisable(GL_FOG);
|
||||
|
||||
prepare();
|
||||
functions->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
|
||||
prepare();
|
||||
|
||||
disableClouds();
|
||||
getLightingManager()->setSpecularity(false);
|
||||
|
||||
skybox->initialize();
|
||||
skybox->updateScenery();
|
||||
|
||||
water->initialize();
|
||||
water->updateScenery();
|
||||
|
||||
terrain->initialize();
|
||||
terrain->updateScenery();
|
||||
|
||||
cameraChangeEvent(getScenery()->getCamera());
|
||||
}
|
||||
else
|
||||
{
|
||||
logError("Failed to initialize OpenGL bindings");
|
||||
}
|
||||
}
|
||||
|
||||
void OpenGLRenderer::resize(int width, int height)
|
||||
{
|
||||
CameraPerspective perspective;
|
||||
if (ready)
|
||||
{
|
||||
functions->glViewport(0, 0, width, height);
|
||||
}
|
||||
getScenery()->getCamera()->setRenderSize(width, height);
|
||||
render_camera->setRenderSize(width, height);
|
||||
|
||||
glViewport(0, 0, width, height);
|
||||
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadIdentity();
|
||||
perspective = render_camera->getPerspective();
|
||||
gluPerspective(perspective.yfov * 180.0 / M_PI, perspective.xratio, perspective.znear, perspective.zfar);
|
||||
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
cameraChangeEvent(getScenery()->getCamera());
|
||||
}
|
||||
|
||||
void OpenGLRenderer::paint()
|
||||
{
|
||||
if (ready)
|
||||
{
|
||||
functions->glClearColor(0.0, 0.0, 0.0, 0.0);
|
||||
functions->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
|
||||
functions->glEnable(GL_BLEND);
|
||||
functions->glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
skybox->render();
|
||||
terrain->render();
|
||||
water->render();
|
||||
|
||||
int error_code;
|
||||
while ((error_code = glGetError()) != GL_NO_ERROR)
|
||||
{
|
||||
logWarning("[OpenGL] ERROR : %s", (const char*)gluErrorString(error_code));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OpenGLRenderer::cameraChangeEvent(CameraDefinition *camera)
|
||||
{
|
||||
// Get camera info
|
||||
Vector3 location = camera->getLocation();
|
||||
Vector3 target = camera->getTarget();
|
||||
Vector3 up = camera->getUpVector();
|
||||
CameraPerspective perspective = camera->getPerspective();
|
||||
|
||||
// Compute matrix
|
||||
QMatrix4x4 transform;
|
||||
transform.setToIdentity();
|
||||
transform.lookAt(QVector3D(location.x, location.y, location.z),
|
||||
QVector3D(target.x, target.y, target.z),
|
||||
QVector3D(up.x, up.y, up.z));
|
||||
|
||||
QMatrix4x4 projection;
|
||||
projection.setToIdentity();
|
||||
projection.perspective(perspective.yfov * 180.0 / M_PI, perspective.xratio, perspective.znear, perspective.zfar);
|
||||
|
||||
// Set in shaders
|
||||
shared_state->set("cameraLocation", location);
|
||||
shared_state->set("viewMatrix", projection * transform);
|
||||
}
|
||||
|
||||
double OpenGLRenderer::getPrecision(const Vector3 &)
|
||||
|
|
|
@ -21,8 +21,23 @@ public:
|
|||
void resize(int width, int height);
|
||||
void paint();
|
||||
|
||||
void cameraChangeEvent(CameraDefinition* camera);
|
||||
|
||||
inline OpenGLFunctions* getOpenGlFunctions() const {return functions;}
|
||||
inline OpenGLSharedState* getSharedState() const {return shared_state;}
|
||||
|
||||
virtual double getPrecision(const Vector3 &location) override;
|
||||
virtual Color applyMediumTraversal(Vector3 location, Color color) override;
|
||||
|
||||
private:
|
||||
bool ready;
|
||||
|
||||
OpenGLFunctions* functions;
|
||||
OpenGLSharedState* shared_state;
|
||||
|
||||
OpenGLSkybox* skybox;
|
||||
OpenGLWater* water;
|
||||
OpenGLTerrain* terrain;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
115
src/render/opengl/OpenGLShaderProgram.cpp
Normal file
115
src/render/opengl/OpenGLShaderProgram.cpp
Normal file
|
@ -0,0 +1,115 @@
|
|||
#include "OpenGLShaderProgram.h"
|
||||
|
||||
#include OPENGL_FUNCTIONS_INCLUDE
|
||||
#include <QOpenGLShaderProgram>
|
||||
#include <QDir>
|
||||
#include "OpenGLRenderer.h"
|
||||
#include "OpenGLSharedState.h"
|
||||
#include "Texture2D.h"
|
||||
#include "Texture3D.h"
|
||||
#include "Texture4D.h"
|
||||
#include "Color.h"
|
||||
#include "Logs.h"
|
||||
|
||||
OpenGLShaderProgram::OpenGLShaderProgram(QString name, OpenGLRenderer* renderer):
|
||||
renderer(renderer), name(name)
|
||||
{
|
||||
program = new QOpenGLShaderProgram();
|
||||
functions = renderer->getOpenGlFunctions();
|
||||
compiled = false;
|
||||
}
|
||||
|
||||
OpenGLShaderProgram::~OpenGLShaderProgram()
|
||||
{
|
||||
delete program;
|
||||
}
|
||||
|
||||
void OpenGLShaderProgram::addVertexSource(QString path)
|
||||
{
|
||||
QFile file(QString(":/shaders/%1.vert").arg(path));
|
||||
if (file.open(QIODevice::ReadOnly | QIODevice::Text))
|
||||
{
|
||||
source_vertex += QString(file.readAll()).toStdString();
|
||||
}
|
||||
else
|
||||
{
|
||||
logError() << "Can't open vertex file " << file.fileName();
|
||||
}
|
||||
}
|
||||
|
||||
void OpenGLShaderProgram::addFragmentSource(QString path)
|
||||
{
|
||||
QFile file(QString(":/shaders/%1.frag").arg(path));
|
||||
if (file.open(QIODevice::ReadOnly | QIODevice::Text))
|
||||
{
|
||||
source_fragment += QString(file.readAll()).toStdString();
|
||||
}
|
||||
else
|
||||
{
|
||||
logError() << "Can't open fragment file " << file.fileName();
|
||||
}
|
||||
}
|
||||
|
||||
void OpenGLShaderProgram::compile()
|
||||
{
|
||||
program->addShaderFromSourceCode(QOpenGLShader::Vertex, QString::fromStdString(source_vertex));
|
||||
program->addShaderFromSourceCode(QOpenGLShader::Fragment, QString::fromStdString(source_fragment));
|
||||
|
||||
if (not program->link())
|
||||
{
|
||||
qWarning() << "Error while compiling shader " << name << "\n" << program->log() << "\n";
|
||||
}
|
||||
else if (program->log().length() > 0)
|
||||
{
|
||||
qDebug() << "Shader " << name << " compilation output:\n" << program->log() << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
void OpenGLShaderProgram::bind()
|
||||
{
|
||||
if (not compiled)
|
||||
{
|
||||
compile();
|
||||
compiled = true;
|
||||
}
|
||||
|
||||
program->bind();
|
||||
|
||||
int texture_unit = 0;
|
||||
renderer->getSharedState()->apply(this, texture_unit);
|
||||
}
|
||||
|
||||
void OpenGLShaderProgram::release()
|
||||
{
|
||||
program->release();
|
||||
}
|
||||
|
||||
void OpenGLShaderProgram::drawTriangles(float* vertices, int triangle_count)
|
||||
{
|
||||
bind();
|
||||
|
||||
GLuint vertex = program->attributeLocation("vertex");
|
||||
program->setAttributeArray(vertex, GL_FLOAT, vertices, 3);
|
||||
program->enableAttributeArray(vertex);
|
||||
|
||||
functions->glDrawArrays(GL_TRIANGLES, 0, triangle_count * 3);
|
||||
|
||||
program->disableAttributeArray(vertex);
|
||||
|
||||
release();
|
||||
}
|
||||
|
||||
void OpenGLShaderProgram::drawTriangleStrip(float* vertices, int vertex_count)
|
||||
{
|
||||
bind();
|
||||
|
||||
GLuint vertex = program->attributeLocation("vertex");
|
||||
program->setAttributeArray(vertex, GL_FLOAT, vertices, 3);
|
||||
program->enableAttributeArray(vertex);
|
||||
|
||||
functions->glDrawArrays(GL_TRIANGLE_STRIP, 0, vertex_count);
|
||||
|
||||
program->disableAttributeArray(vertex);
|
||||
|
||||
release();
|
||||
}
|
52
src/render/opengl/OpenGLShaderProgram.h
Normal file
52
src/render/opengl/OpenGLShaderProgram.h
Normal file
|
@ -0,0 +1,52 @@
|
|||
#ifndef OPENGLSHADERPROGRAM_H
|
||||
#define OPENGLSHADERPROGRAM_H
|
||||
|
||||
#include "opengl_global.h"
|
||||
|
||||
#include <QString>
|
||||
|
||||
class QOpenGLShaderProgram;
|
||||
|
||||
namespace paysages {
|
||||
namespace opengl {
|
||||
|
||||
class OPENGLSHARED_EXPORT OpenGLShaderProgram
|
||||
{
|
||||
public:
|
||||
OpenGLShaderProgram(QString name, OpenGLRenderer* renderer);
|
||||
~OpenGLShaderProgram();
|
||||
|
||||
void addVertexSource(QString path);
|
||||
void addFragmentSource(QString path);
|
||||
|
||||
void drawTriangles(float* vertices, int triangle_count);
|
||||
void drawTriangleStrip(float* vertices, int vertex_count);
|
||||
|
||||
void bind();
|
||||
void release();
|
||||
|
||||
inline QOpenGLShaderProgram* getProgram() const {return program;}
|
||||
inline OpenGLRenderer* getRenderer() const {return renderer;}
|
||||
|
||||
protected:
|
||||
friend class OpenGLVariable;
|
||||
|
||||
private:
|
||||
void compile();
|
||||
|
||||
bool compiled;
|
||||
|
||||
OpenGLRenderer* renderer;
|
||||
|
||||
QString name;
|
||||
QOpenGLShaderProgram* program;
|
||||
OpenGLFunctions* functions;
|
||||
|
||||
std::string source_vertex;
|
||||
std::string source_fragment;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif // OPENGLSHADERPROGRAM_H
|
23
src/render/opengl/OpenGLSharedState.cpp
Normal file
23
src/render/opengl/OpenGLSharedState.cpp
Normal file
|
@ -0,0 +1,23 @@
|
|||
#include "OpenGLSharedState.h"
|
||||
|
||||
OpenGLSharedState::OpenGLSharedState()
|
||||
{
|
||||
}
|
||||
|
||||
void OpenGLSharedState::apply(OpenGLShaderProgram *program, int &texture_unit)
|
||||
{
|
||||
for (const auto &pair : variables)
|
||||
{
|
||||
pair.second->apply(program, texture_unit);
|
||||
}
|
||||
}
|
||||
|
||||
OpenGLVariable *OpenGLSharedState::get(const std::string &name)
|
||||
{
|
||||
OpenGLVariable*& var = variables[name];
|
||||
if (var == 0)
|
||||
{
|
||||
var = new OpenGLVariable(name);
|
||||
}
|
||||
return var;
|
||||
}
|
48
src/render/opengl/OpenGLSharedState.h
Normal file
48
src/render/opengl/OpenGLSharedState.h
Normal file
|
@ -0,0 +1,48 @@
|
|||
#ifndef OPENGLSHAREDSTATE_H
|
||||
#define OPENGLSHAREDSTATE_H
|
||||
|
||||
#include "opengl_global.h"
|
||||
|
||||
#include <map>
|
||||
#include "OpenGLVariable.h"
|
||||
|
||||
namespace paysages {
|
||||
namespace opengl {
|
||||
|
||||
/*!
|
||||
* \brief OpenGL variables that can be shared between shaders.
|
||||
*/
|
||||
class OPENGLSHARED_EXPORT OpenGLSharedState
|
||||
{
|
||||
public:
|
||||
OpenGLSharedState();
|
||||
|
||||
/*!
|
||||
* \brief Apply the stored variables to the bound program.
|
||||
*/
|
||||
void apply(OpenGLShaderProgram* program, int &texture_unit);
|
||||
|
||||
/*!
|
||||
* \brief Get or create a variable in the state.
|
||||
*/
|
||||
OpenGLVariable *get(const std::string &name);
|
||||
|
||||
// Shortcuts
|
||||
inline void set(const std::string &name, const Texture2D *texture) {get(name)->set(texture);}
|
||||
inline void set(const std::string &name, const Texture3D *texture) {get(name)->set(texture);}
|
||||
inline void set(const std::string &name, const Texture4D *texture) {get(name)->set(texture);}
|
||||
inline void set(const std::string &name, float value) {get(name)->set(value);}
|
||||
inline void set(const std::string &name, const Vector3 &vector) {get(name)->set(vector);}
|
||||
inline void set(const std::string &name, const QVector3D &vector) {get(name)->set(vector);}
|
||||
inline void set(const std::string &name, const Matrix4 &matrix) {get(name)->set(matrix);}
|
||||
inline void set(const std::string &name, const QMatrix4x4 &matrix) {get(name)->set(matrix);}
|
||||
inline void set(const std::string &name, const Color &color) {get(name)->set(color);}
|
||||
|
||||
private:
|
||||
std::map<std::string, OpenGLVariable*> variables;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif // OPENGLSHAREDSTATE_H
|
104
src/render/opengl/OpenGLSkybox.cpp
Normal file
104
src/render/opengl/OpenGLSkybox.cpp
Normal file
|
@ -0,0 +1,104 @@
|
|||
#include "OpenGLSkybox.h"
|
||||
|
||||
#include <cmath>
|
||||
#include "OpenGLRenderer.h"
|
||||
#include "OpenGLShaderProgram.h"
|
||||
#include "OpenGLSharedState.h"
|
||||
#include "Scenery.h"
|
||||
#include "AtmosphereDefinition.h"
|
||||
#include "AtmosphereRenderer.h"
|
||||
#include "AtmosphereModelBruneton.h"
|
||||
|
||||
OpenGLSkybox::OpenGLSkybox(OpenGLRenderer* renderer):
|
||||
OpenGLPart(renderer)
|
||||
{
|
||||
vertices = new float[14 * 3];
|
||||
daytime = renderer->getScenery()->getAtmosphere()->_daytime;
|
||||
}
|
||||
|
||||
OpenGLSkybox::~OpenGLSkybox()
|
||||
{
|
||||
delete[] vertices;
|
||||
}
|
||||
|
||||
void OpenGLSkybox::initialize()
|
||||
{
|
||||
program = createShader("skybox");
|
||||
program->addVertexSource("skybox");
|
||||
program->addFragmentSource("bruneton");
|
||||
program->addFragmentSource("tonemapping");
|
||||
program->addFragmentSource("skybox");
|
||||
|
||||
setVertex(0, 1.0f, 1.0f, 1.0f);
|
||||
setVertex(12, 1.0f, 1.0f, 1.0f);
|
||||
|
||||
setVertex(1, 1.0f, -1.0f, 1.0f);
|
||||
setVertex(5, 1.0f, -1.0f, 1.0f);
|
||||
setVertex(13, 1.0f, -1.0f, 1.0f);
|
||||
|
||||
setVertex(2, -1.0f, 1.0f, 1.0f);
|
||||
setVertex(10, -1.0f, 1.0f, 1.0f);
|
||||
|
||||
setVertex(3, -1.0f, -1.0f, 1.0f);
|
||||
|
||||
setVertex(4, -1.0f, -1.0f, -1.0f);
|
||||
setVertex(8, -1.0f, -1.0f, -1.0f);
|
||||
|
||||
setVertex(6, 1.0f, -1.0f, -1.0f);
|
||||
|
||||
setVertex(7, 1.0f, 1.0f, -1.0f);
|
||||
setVertex(11, 1.0f, 1.0f, -1.0f);
|
||||
|
||||
setVertex(9, -1.0f, 1.0f, -1.0f);
|
||||
}
|
||||
|
||||
void OpenGLSkybox::update()
|
||||
{
|
||||
Vector3 sun_direction = renderer->getAtmosphereRenderer()->getSunDirection();
|
||||
renderer->getSharedState()->set("sunDirection", sun_direction);
|
||||
|
||||
Color sun_color = renderer->getScenery()->getAtmosphere()->sun_color;
|
||||
renderer->getSharedState()->set("sunColor", sun_color);
|
||||
|
||||
SoftwareBrunetonAtmosphereRenderer* bruneton = (SoftwareBrunetonAtmosphereRenderer*)renderer->getAtmosphereRenderer();
|
||||
renderer->getSharedState()->set("transmittanceTexture", bruneton->getModel()->getTextureTransmittance());
|
||||
renderer->getSharedState()->set("inscatterTexture", bruneton->getModel()->getTextureInscatter());
|
||||
}
|
||||
|
||||
void OpenGLSkybox::render()
|
||||
{
|
||||
program->drawTriangleStrip(vertices, 14);
|
||||
}
|
||||
|
||||
void OpenGLSkybox::alterDayTime(double delta)
|
||||
{
|
||||
#if 0
|
||||
Scenery* scenery = renderer->getScenery();
|
||||
AtmosphereDefinition* definition = scenery->getAtmosphere()->definition;
|
||||
daytime = fmod(daytime + delta * 0.001, 1.0);
|
||||
// TEMP
|
||||
if (daytime > 0.8)
|
||||
{
|
||||
daytime -= 0.6;
|
||||
}
|
||||
if (daytime < 0.2)
|
||||
{
|
||||
daytime += 0.6;
|
||||
}
|
||||
|
||||
definition->hour = (int)(daytime * 24.0);
|
||||
definition->minute = (int)((daytime - (((double)definition->hour) / 24.0)) * 1440.0);
|
||||
|
||||
AtmosphereDefinitionClass.validate(definition);
|
||||
|
||||
// TODO Update only the sun
|
||||
updateScenery(scenery, true);
|
||||
#endif
|
||||
}
|
||||
|
||||
void OpenGLSkybox::setVertex(int i, float x, float y, float z)
|
||||
{
|
||||
vertices[i * 3] = x;
|
||||
vertices[i * 3 + 1] = y;
|
||||
vertices[i * 3 + 2] = z;
|
||||
}
|
35
src/render/opengl/OpenGLSkybox.h
Normal file
35
src/render/opengl/OpenGLSkybox.h
Normal file
|
@ -0,0 +1,35 @@
|
|||
#ifndef OPENGLSKYBOX_H
|
||||
#define OPENGLSKYBOX_H
|
||||
|
||||
#include "opengl_global.h"
|
||||
|
||||
#include "OpenGLPart.h"
|
||||
|
||||
namespace paysages {
|
||||
namespace opengl {
|
||||
|
||||
class OPENGLSHARED_EXPORT OpenGLSkybox: public OpenGLPart
|
||||
{
|
||||
public:
|
||||
OpenGLSkybox(OpenGLRenderer* renderer);
|
||||
virtual ~OpenGLSkybox();
|
||||
|
||||
virtual void initialize() override;
|
||||
virtual void update() override;
|
||||
virtual void render() override;
|
||||
|
||||
void alterDayTime(double delta);
|
||||
|
||||
private:
|
||||
void setVertex(int i, float x, float y, float z);
|
||||
|
||||
OpenGLShaderProgram* program;
|
||||
float* vertices;
|
||||
|
||||
double daytime;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif // OPENGLSKYBOX_H
|
128
src/render/opengl/OpenGLTerrain.cpp
Normal file
128
src/render/opengl/OpenGLTerrain.cpp
Normal file
|
@ -0,0 +1,128 @@
|
|||
#include "OpenGLTerrain.h"
|
||||
|
||||
#include OPENGL_FUNCTIONS_INCLUDE
|
||||
#include "OpenGLRenderer.h"
|
||||
#include "OpenGLShaderProgram.h"
|
||||
#include "ParallelPool.h"
|
||||
#include "Thread.h"
|
||||
#include "ExplorerChunkTerrain.h"
|
||||
#include "WaterRenderer.h"
|
||||
#include "CameraDefinition.h"
|
||||
#include "Scenery.h"
|
||||
|
||||
class ChunkMaintenanceThreads:public ParallelPool
|
||||
{
|
||||
public:
|
||||
ChunkMaintenanceThreads(OpenGLTerrain* terrain):
|
||||
terrain(terrain)
|
||||
{
|
||||
}
|
||||
|
||||
virtual void work() override
|
||||
{
|
||||
while (running)
|
||||
{
|
||||
terrain->performChunksMaintenance();
|
||||
Thread::timeSleepMs(10);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
OpenGLTerrain* terrain;
|
||||
};
|
||||
|
||||
OpenGLTerrain::OpenGLTerrain(OpenGLRenderer *renderer):
|
||||
OpenGLPart(renderer)
|
||||
{
|
||||
work = new ChunkMaintenanceThreads(this);
|
||||
}
|
||||
|
||||
OpenGLTerrain::~OpenGLTerrain()
|
||||
{
|
||||
delete work;
|
||||
|
||||
for (int i = 0; i < _chunks.count(); i++)
|
||||
{
|
||||
delete _chunks[i];
|
||||
}
|
||||
}
|
||||
|
||||
void OpenGLTerrain::initialize()
|
||||
{
|
||||
// Prepare shader programs
|
||||
program = createShader("terrain");
|
||||
program->addVertexSource("terrain");
|
||||
program->addFragmentSource("bruneton");
|
||||
program->addFragmentSource("tonemapping");
|
||||
program->addFragmentSource("fadeout");
|
||||
program->addFragmentSource("terrain");
|
||||
|
||||
// Add terrain chunks
|
||||
int chunks = 25;
|
||||
double size = 800.0;
|
||||
double chunksize = size / (double) chunks;
|
||||
double start = -size / 2.0;
|
||||
double water_height = renderer->getWaterRenderer()->getHeightInfo().base_height;
|
||||
for (int i = 0; i < chunks; i++)
|
||||
{
|
||||
for (int j = 0; j < chunks; j++)
|
||||
{
|
||||
ExplorerChunkTerrain* chunk = new ExplorerChunkTerrain(renderer, start + chunksize * (double) i, start + chunksize * (double) j, chunksize, chunks, water_height);
|
||||
_chunks.append(chunk);
|
||||
_updateQueue.append(chunk);
|
||||
}
|
||||
}
|
||||
|
||||
// Start chunks maintenance
|
||||
work->start();
|
||||
}
|
||||
|
||||
void OpenGLTerrain::update()
|
||||
{
|
||||
}
|
||||
|
||||
void OpenGLTerrain::render()
|
||||
{
|
||||
program->bind();
|
||||
|
||||
for (int i = 0; i < _chunks.count(); i++)
|
||||
{
|
||||
_chunks[i]->render(program->getProgram(), renderer->getOpenGlFunctions());
|
||||
}
|
||||
|
||||
program->release();
|
||||
}
|
||||
|
||||
static bool _cmpChunks(const ExplorerChunkTerrain* c1, const ExplorerChunkTerrain* c2)
|
||||
{
|
||||
return c1->priority > c2->priority;
|
||||
}
|
||||
|
||||
void OpenGLTerrain::performChunksMaintenance()
|
||||
{
|
||||
CameraDefinition* camera = renderer->getScenery()->getCamera();
|
||||
ExplorerChunkTerrain* chunk;
|
||||
|
||||
_lock_chunks.lock();
|
||||
if (_updateQueue.count() > 0)
|
||||
{
|
||||
chunk = _updateQueue.takeFirst();
|
||||
_lock_chunks.unlock();
|
||||
}
|
||||
else
|
||||
{
|
||||
_lock_chunks.unlock();
|
||||
return;
|
||||
}
|
||||
|
||||
chunk->maintain();
|
||||
|
||||
_lock_chunks.lock();
|
||||
_updateQueue.append(chunk);
|
||||
for (int i = 0; i < _chunks.count(); i++)
|
||||
{
|
||||
_chunks[i]->updatePriority(camera);
|
||||
}
|
||||
qSort(_updateQueue.begin(), _updateQueue.end(), _cmpChunks);
|
||||
_lock_chunks.unlock();
|
||||
}
|
40
src/render/opengl/OpenGLTerrain.h
Normal file
40
src/render/opengl/OpenGLTerrain.h
Normal file
|
@ -0,0 +1,40 @@
|
|||
#ifndef OPENGLTERRAIN_H
|
||||
#define OPENGLTERRAIN_H
|
||||
|
||||
#include "opengl_global.h"
|
||||
|
||||
#include "OpenGLPart.h"
|
||||
|
||||
#include <QVector>
|
||||
#include <QList>
|
||||
#include <QMutex>
|
||||
|
||||
namespace paysages {
|
||||
namespace opengl {
|
||||
|
||||
class OPENGLSHARED_EXPORT OpenGLTerrain:public OpenGLPart
|
||||
{
|
||||
public:
|
||||
OpenGLTerrain(OpenGLRenderer* renderer);
|
||||
virtual ~OpenGLTerrain();
|
||||
|
||||
virtual void initialize() override;
|
||||
virtual void update() override;
|
||||
virtual void render() override;
|
||||
|
||||
void performChunksMaintenance();
|
||||
|
||||
private:
|
||||
OpenGLShaderProgram* program;
|
||||
|
||||
ParallelPool* work;
|
||||
|
||||
QVector<ExplorerChunkTerrain*> _chunks;
|
||||
QList<ExplorerChunkTerrain*> _updateQueue;
|
||||
QMutex _lock_chunks;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif // OPENGLTERRAIN_H
|
231
src/render/opengl/OpenGLVariable.cpp
Normal file
231
src/render/opengl/OpenGLVariable.cpp
Normal file
|
@ -0,0 +1,231 @@
|
|||
#include "OpenGLVariable.h"
|
||||
|
||||
#include OPENGL_FUNCTIONS_INCLUDE
|
||||
#include <QOpenGLShaderProgram>
|
||||
#include <cassert>
|
||||
#include "OpenGLRenderer.h"
|
||||
#include "OpenGLShaderProgram.h"
|
||||
#include "Vector3.h"
|
||||
#include "Matrix4.h"
|
||||
#include "Color.h"
|
||||
#include "Texture2D.h"
|
||||
#include "Texture3D.h"
|
||||
#include "Texture4D.h"
|
||||
|
||||
OpenGLVariable::OpenGLVariable(const std::string &name):
|
||||
name(name)
|
||||
{
|
||||
type = TYPE_NONE;
|
||||
texture_toupload = false;
|
||||
}
|
||||
|
||||
void OpenGLVariable::apply(OpenGLShaderProgram *program, int &texture_unit)
|
||||
{
|
||||
QOpenGLShaderProgram* pr = program->getProgram();
|
||||
OpenGLFunctions* functions = program->getRenderer()->getOpenGlFunctions();
|
||||
|
||||
if (texture_toupload)
|
||||
{
|
||||
uploadTexture(program->getRenderer());
|
||||
texture_toupload = false;
|
||||
}
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case TYPE_FLOAT:
|
||||
pr->setUniformValue(name.c_str(), value_float);
|
||||
break;
|
||||
case TYPE_COLOR:
|
||||
pr->setUniformValue(name.c_str(), value_color);
|
||||
break;
|
||||
case TYPE_VECTOR3:
|
||||
pr->setUniformValue(name.c_str(), value_vector3);
|
||||
break;
|
||||
case TYPE_MATRIX4:
|
||||
pr->setUniformValue(name.c_str(), value_matrix4);
|
||||
break;
|
||||
case TYPE_TEXTURE_2D:
|
||||
functions->glActiveTexture(GL_TEXTURE0 + texture_unit);
|
||||
functions->glBindTexture(GL_TEXTURE_2D, texture_id);
|
||||
pr->setUniformValue(name.c_str(), texture_unit);
|
||||
texture_unit++;
|
||||
break;
|
||||
case TYPE_TEXTURE_3D:
|
||||
case TYPE_TEXTURE_4D:
|
||||
functions->glActiveTexture(GL_TEXTURE0 + texture_unit);
|
||||
functions->glBindTexture(GL_TEXTURE_3D, texture_id);
|
||||
pr->setUniformValue(name.c_str(), texture_unit);
|
||||
texture_unit++;
|
||||
break;
|
||||
case TYPE_NONE:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void OpenGLVariable::set(const Texture2D *texture)
|
||||
{
|
||||
assert(type == TYPE_NONE or type == TYPE_TEXTURE_2D);
|
||||
|
||||
type = TYPE_TEXTURE_2D;
|
||||
value_tex2d = texture;
|
||||
texture_toupload = true;
|
||||
}
|
||||
|
||||
void OpenGLVariable::set(const Texture3D *texture)
|
||||
{
|
||||
assert(type == TYPE_NONE or type == TYPE_TEXTURE_3D);
|
||||
|
||||
type = TYPE_TEXTURE_3D;
|
||||
value_tex3d = texture;
|
||||
texture_toupload = true;
|
||||
}
|
||||
|
||||
void OpenGLVariable::set(const Texture4D *texture)
|
||||
{
|
||||
assert(type == TYPE_NONE or type == TYPE_TEXTURE_4D);
|
||||
|
||||
type = TYPE_TEXTURE_4D;
|
||||
value_tex4d = texture;
|
||||
texture_toupload = true;
|
||||
}
|
||||
|
||||
void OpenGLVariable::set(float value)
|
||||
{
|
||||
assert(type == TYPE_NONE or type == TYPE_FLOAT);
|
||||
|
||||
type = TYPE_FLOAT;
|
||||
value_float = value;
|
||||
}
|
||||
|
||||
void OpenGLVariable::set(const Vector3 &vector)
|
||||
{
|
||||
set(QVector3D(vector.x, vector.y, vector.z));
|
||||
}
|
||||
|
||||
void OpenGLVariable::set(const QVector3D &vector)
|
||||
{
|
||||
assert(type == TYPE_NONE or type == TYPE_VECTOR3);
|
||||
|
||||
type = TYPE_VECTOR3;
|
||||
value_vector3 = vector;
|
||||
}
|
||||
|
||||
void OpenGLVariable::set(const Matrix4 &matrix)
|
||||
{
|
||||
set(matrix.toQMatrix());
|
||||
}
|
||||
|
||||
void OpenGLVariable::set(const QMatrix4x4 &matrix)
|
||||
{
|
||||
assert(type == TYPE_NONE or type == TYPE_MATRIX4);
|
||||
|
||||
type = TYPE_MATRIX4;
|
||||
value_matrix4 = matrix;
|
||||
}
|
||||
|
||||
void OpenGLVariable::set(const Color &color)
|
||||
{
|
||||
assert(type == TYPE_NONE or type == TYPE_COLOR);
|
||||
|
||||
type = TYPE_COLOR;
|
||||
value_color = QColor(color.r, color.g, color.b);
|
||||
}
|
||||
|
||||
void OpenGLVariable::uploadTexture(OpenGLRenderer* renderer)
|
||||
{
|
||||
OpenGLFunctions* functions = renderer->getOpenGlFunctions();
|
||||
|
||||
assert(type == TYPE_TEXTURE_2D or type == TYPE_TEXTURE_3D or type == TYPE_TEXTURE_4D);
|
||||
|
||||
if (texture_id == 0)
|
||||
{
|
||||
GLuint texid;
|
||||
functions->glGenTextures(1, &texid);
|
||||
texture_id = texid;
|
||||
}
|
||||
|
||||
GLenum textype = (type == TYPE_TEXTURE_2D) ? GL_TEXTURE_2D : GL_TEXTURE_3D;
|
||||
|
||||
functions->glBindTexture(textype, texture_id);
|
||||
functions->glTexParameteri(textype, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
functions->glTexParameteri(textype, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
functions->glTexParameteri(textype, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
functions->glTexParameteri(textype, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
if (textype == GL_TEXTURE_3D)
|
||||
{
|
||||
functions->glTexParameteri(textype, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
|
||||
}
|
||||
|
||||
if (type == TYPE_TEXTURE_2D)
|
||||
{
|
||||
int sx, sy;
|
||||
value_tex2d->getSize(&sx, &sy);
|
||||
float* pixels = new float[sx * sy * 4];
|
||||
for (int x = 0; x < sx; x++)
|
||||
{
|
||||
for (int y = 0; y < sy; y++)
|
||||
{
|
||||
float* pixel = pixels + (y * sx + x) * 4;
|
||||
Color col = value_tex2d->getPixel(x, y);
|
||||
pixel[0] = (float)col.r;
|
||||
pixel[1] = (float)col.g;
|
||||
pixel[2] = (float)col.b;
|
||||
pixel[3] = (float)col.a;
|
||||
}
|
||||
}
|
||||
|
||||
functions->glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, sx, sy, 0, GL_RGBA, GL_FLOAT, pixels);
|
||||
delete[] pixels;
|
||||
}
|
||||
else if (type == TYPE_TEXTURE_3D)
|
||||
{
|
||||
int sx, sy, sz;
|
||||
value_tex3d->getSize(&sx, &sy, &sz);
|
||||
float* pixels = new float[sx * sy * sz * 4];
|
||||
for (int x = 0; x < sx; x++)
|
||||
{
|
||||
for (int y = 0; y < sy; y++)
|
||||
{
|
||||
for (int z = 0; z < sz; z++)
|
||||
{
|
||||
float* pixel = pixels + (z * (sx * sy) + y * sx + x) * 4;
|
||||
Color col = value_tex3d->getPixel(x, y, z);
|
||||
pixel[0] = (float)col.r;
|
||||
pixel[1] = (float)col.g;
|
||||
pixel[2] = (float)col.b;
|
||||
pixel[3] = (float)col.a;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
functions->glTexImage3D(GL_TEXTURE_3D, 0, GL_RGBA, sx, sy, sz, 0, GL_RGBA, GL_FLOAT, pixels);
|
||||
delete[] pixels;
|
||||
}
|
||||
else
|
||||
{
|
||||
int sx, sy, sz, sw;
|
||||
value_tex4d->getSize(&sx, &sy, &sz, &sw);
|
||||
float* pixels = new float[sx * sy * sz * sw * 4];
|
||||
for (int x = 0; x < sx; x++)
|
||||
{
|
||||
for (int y = 0; y < sy; y++)
|
||||
{
|
||||
for (int z = 0; z < sz; z++)
|
||||
{
|
||||
for (int w = 0; w < sw; w++)
|
||||
{
|
||||
float* pixel = pixels + (w * (sx * sy * sz) + z * (sx * sy) + y * sx + x) * 4;
|
||||
Color col = value_tex4d->getPixel(x, y, z, w);
|
||||
pixel[0] = (float)col.r;
|
||||
pixel[1] = (float)col.g;
|
||||
pixel[2] = (float)col.b;
|
||||
pixel[3] = (float)col.a;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
functions->glTexImage3D(GL_TEXTURE_3D, 0, GL_RGBA, sx, sy, sz * sw, 0, GL_RGBA, GL_FLOAT, pixels);
|
||||
delete[] pixels;
|
||||
}
|
||||
}
|
67
src/render/opengl/OpenGLVariable.h
Normal file
67
src/render/opengl/OpenGLVariable.h
Normal file
|
@ -0,0 +1,67 @@
|
|||
#ifndef OPENGLVARIABLE_H
|
||||
#define OPENGLVARIABLE_H
|
||||
|
||||
#include "opengl_global.h"
|
||||
|
||||
#include <QColor>
|
||||
#include <QVector3D>
|
||||
#include <QMatrix4x4>
|
||||
|
||||
namespace paysages {
|
||||
namespace opengl {
|
||||
|
||||
/*!
|
||||
* \brief OpenGL variable that can be bound to a uniform for shaders.
|
||||
*/
|
||||
class OpenGLVariable
|
||||
{
|
||||
public:
|
||||
typedef enum {
|
||||
TYPE_NONE,
|
||||
TYPE_TEXTURE_2D,
|
||||
TYPE_TEXTURE_3D,
|
||||
TYPE_TEXTURE_4D,
|
||||
TYPE_FLOAT,
|
||||
TYPE_VECTOR3,
|
||||
TYPE_MATRIX4,
|
||||
TYPE_COLOR
|
||||
} OpenGLVariableType;
|
||||
|
||||
public:
|
||||
OpenGLVariable(const std::string &name);
|
||||
|
||||
void apply(OpenGLShaderProgram *program, int &texture_unit);
|
||||
|
||||
void set(const Texture2D *texture);
|
||||
void set(const Texture3D *texture);
|
||||
void set(const Texture4D *texture);
|
||||
void set(float value);
|
||||
void set(const Vector3 &vector);
|
||||
void set(const QVector3D &vector);
|
||||
void set(const Matrix4 &matrix);
|
||||
void set(const QMatrix4x4 &matrix);
|
||||
void set(const Color &color);
|
||||
|
||||
protected:
|
||||
void uploadTexture(OpenGLRenderer* renderer);
|
||||
|
||||
private:
|
||||
std::string name;
|
||||
OpenGLVariableType type;
|
||||
|
||||
float value_float;
|
||||
QColor value_color;
|
||||
QVector3D value_vector3;
|
||||
QMatrix4x4 value_matrix4;
|
||||
const Texture2D* value_tex2d;
|
||||
const Texture3D* value_tex3d;
|
||||
const Texture4D* value_tex4d;
|
||||
|
||||
bool texture_toupload;
|
||||
unsigned int texture_id;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif // OPENGLVARIABLE_H
|
56
src/render/opengl/OpenGLWater.cpp
Normal file
56
src/render/opengl/OpenGLWater.cpp
Normal file
|
@ -0,0 +1,56 @@
|
|||
#include "OpenGLWater.h"
|
||||
|
||||
#include "OpenGLRenderer.h"
|
||||
#include "OpenGLShaderProgram.h"
|
||||
#include "OpenGLSharedState.h"
|
||||
#include "WaterRenderer.h"
|
||||
#include "Scenery.h"
|
||||
#include "WaterDefinition.h"
|
||||
#include "SurfaceMaterial.h"
|
||||
|
||||
OpenGLWater::OpenGLWater(OpenGLRenderer *renderer):
|
||||
OpenGLPart(renderer)
|
||||
{
|
||||
vertices = new float[4 * 3];
|
||||
}
|
||||
|
||||
OpenGLWater::~OpenGLWater()
|
||||
{
|
||||
delete[] vertices;
|
||||
}
|
||||
|
||||
void OpenGLWater::initialize()
|
||||
{
|
||||
program = createShader("water");
|
||||
program->addVertexSource("water");
|
||||
program->addFragmentSource("bruneton");
|
||||
program->addFragmentSource("tonemapping");
|
||||
program->addFragmentSource("fadeout");
|
||||
program->addFragmentSource("water");
|
||||
|
||||
setVertex(0, -1.0f, 0.0f, -1.0f);
|
||||
setVertex(1, -1.0f, 0.0f, 1.0f);
|
||||
setVertex(2, 1.0f, 0.0f, -1.0f);
|
||||
setVertex(3, 1.0f, 0.0f, 1.0f);
|
||||
}
|
||||
|
||||
void OpenGLWater::update()
|
||||
{
|
||||
double water_height = renderer->getWaterRenderer()->getHeightInfo().max_height;
|
||||
renderer->getSharedState()->set("waterHeight", water_height);
|
||||
|
||||
Color water_color = renderer->getScenery()->getWater()->material->_rgb;
|
||||
renderer->getSharedState()->set("waterColor", water_color);
|
||||
}
|
||||
|
||||
void OpenGLWater::render()
|
||||
{
|
||||
program->drawTriangleStrip(vertices, 4);
|
||||
}
|
||||
|
||||
void OpenGLWater::setVertex(int i, float x, float y, float z)
|
||||
{
|
||||
vertices[i * 3] = x;
|
||||
vertices[i * 3 + 1] = y;
|
||||
vertices[i * 3 + 2] = z;
|
||||
}
|
31
src/render/opengl/OpenGLWater.h
Normal file
31
src/render/opengl/OpenGLWater.h
Normal file
|
@ -0,0 +1,31 @@
|
|||
#ifndef OPENGLWATER_H
|
||||
#define OPENGLWATER_H
|
||||
|
||||
#include "opengl_global.h"
|
||||
|
||||
#include "OpenGLPart.h"
|
||||
|
||||
namespace paysages {
|
||||
namespace opengl {
|
||||
|
||||
class OPENGLSHARED_EXPORT OpenGLWater: public OpenGLPart
|
||||
{
|
||||
public:
|
||||
OpenGLWater(OpenGLRenderer* renderer);
|
||||
virtual ~OpenGLWater();
|
||||
|
||||
virtual void initialize() override;
|
||||
virtual void update() override;
|
||||
virtual void render() override;
|
||||
|
||||
private:
|
||||
void setVertex(int i, float x, float y, float z);
|
||||
|
||||
OpenGLShaderProgram* program;
|
||||
float* vertices;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif // OPENGLWATER_H
|
155
src/render/opengl/VertexArray.h
Normal file
155
src/render/opengl/VertexArray.h
Normal file
|
@ -0,0 +1,155 @@
|
|||
#ifndef VERTEXARRAY_H
|
||||
#define VERTEXARRAY_H
|
||||
|
||||
#include "opengl_global.h"
|
||||
|
||||
#include OPENGL_FUNCTIONS_INCLUDE
|
||||
#include <cassert>
|
||||
#include <QOpenGLShaderProgram>
|
||||
|
||||
namespace paysages {
|
||||
namespace opengl {
|
||||
|
||||
/*!
|
||||
* Wrapper for OpenGL vertex arrays.
|
||||
*/
|
||||
template <typename Vertex> class VertexArray
|
||||
{
|
||||
public:
|
||||
VertexArray()
|
||||
{
|
||||
ready = false;
|
||||
changed = false;
|
||||
vertex_count = 1;
|
||||
vertices = new Vertex[1];
|
||||
index_count = 1;
|
||||
indices = new unsigned short[1];
|
||||
}
|
||||
|
||||
~VertexArray()
|
||||
{
|
||||
delete[] vertices;
|
||||
delete[] indices;
|
||||
}
|
||||
|
||||
inline int getVertexCount() {return vertex_count;}
|
||||
inline int getIndexCount() {return index_count;}
|
||||
inline bool isReady() {return ready;}
|
||||
inline bool isChanged() {return changed;}
|
||||
|
||||
void setVertexCount(int count)
|
||||
{
|
||||
assert(count > 0 and count <= 16384);
|
||||
|
||||
delete[] vertices;
|
||||
vertices = new Vertex[count];
|
||||
|
||||
vertex_count = count;
|
||||
}
|
||||
|
||||
void setGridSize(int edge_vertex_count)
|
||||
{
|
||||
assert(edge_vertex_count >= 2);
|
||||
|
||||
setVertexCount(edge_vertex_count * edge_vertex_count);
|
||||
}
|
||||
|
||||
void setVertex(int position, const Vertex &vertex)
|
||||
{
|
||||
assert(position >= 0 and position < vertex_count);
|
||||
|
||||
vertices[position] = vertex;
|
||||
|
||||
changed = true;
|
||||
}
|
||||
|
||||
void setGridVertex(int edge_vertex_count, int x, int y, const Vertex &vertex)
|
||||
{
|
||||
setVertex(y * edge_vertex_count + x, vertex);
|
||||
}
|
||||
|
||||
void setAutoGridIndices(int edge_vertex_count, int stride=1)
|
||||
{
|
||||
assert(stride >= 1);
|
||||
|
||||
delete[] indices;
|
||||
int cell_count = edge_vertex_count - 1;
|
||||
|
||||
index_count = (cell_count / stride) * (cell_count / stride) * 6;
|
||||
indices = new unsigned short[index_count];
|
||||
|
||||
int idx = 0;
|
||||
for (int y = 0; y < cell_count; y += stride)
|
||||
{
|
||||
for (int x = 0; x < cell_count; x += stride)
|
||||
{
|
||||
int base = y * edge_vertex_count + x;
|
||||
indices[idx++] = base;
|
||||
indices[idx++] = base + edge_vertex_count * stride;
|
||||
indices[idx++] = base + stride;
|
||||
indices[idx++] = base + stride;
|
||||
indices[idx++] = base + edge_vertex_count * stride;
|
||||
indices[idx++] = base + edge_vertex_count * stride + stride;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Vertex getVertex(int position)
|
||||
{
|
||||
assert(position >= 0 and position < vertex_count);
|
||||
|
||||
return vertices[position];
|
||||
}
|
||||
|
||||
Vertex getVertexByIndex(unsigned short index)
|
||||
{
|
||||
assert(index >= 0 and index < index_count);
|
||||
|
||||
return getVertex(indices[index]);
|
||||
}
|
||||
|
||||
Vertex getGridVertex(int edge_vertex_count, int x, int y)
|
||||
{
|
||||
return getVertex(y * edge_vertex_count + x);
|
||||
}
|
||||
|
||||
unsigned short getIndex(int position)
|
||||
{
|
||||
assert(position >= 0 and position < index_count);
|
||||
|
||||
return indices[position];
|
||||
}
|
||||
|
||||
void render(QOpenGLShaderProgram* program, OpenGLFunctions* functions)
|
||||
{
|
||||
size_t ptr = (size_t)vertices;
|
||||
|
||||
GLuint vertex = program->attributeLocation("vertex");
|
||||
program->setAttributeArray(vertex, GL_FLOAT, (void*)(ptr + offsetof(Vertex, location)), 3, sizeof(Vertex));
|
||||
program->enableAttributeArray(vertex);
|
||||
|
||||
GLuint uv = program->attributeLocation("uv");
|
||||
program->setAttributeArray(uv, GL_FLOAT, (void*)(ptr + offsetof(Vertex, uv)), 2, sizeof(Vertex));
|
||||
program->enableAttributeArray(uv);
|
||||
|
||||
functions->glDrawElements(GL_TRIANGLES, index_count, GL_UNSIGNED_SHORT, indices);
|
||||
|
||||
program->disableAttributeArray(vertex);
|
||||
program->disableAttributeArray(uv);
|
||||
}
|
||||
|
||||
private:
|
||||
bool ready;
|
||||
bool changed;
|
||||
|
||||
int vertex_count;
|
||||
Vertex* vertices;
|
||||
|
||||
int index_count;
|
||||
unsigned short* indices;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif // VERTEXARRAY_H
|
|
@ -11,51 +11,12 @@
|
|||
#include "WaterDefinition.h"
|
||||
#include "SurfaceMaterial.h"
|
||||
#include "CameraDefinition.h"
|
||||
#include "ExplorerChunkSky.h"
|
||||
#include "ExplorerChunkTerrain.h"
|
||||
#include "TerrainRenderer.h"
|
||||
#include "WaterRenderer.h"
|
||||
#include "Scenery.h"
|
||||
#include "LightingManager.h"
|
||||
|
||||
class ChunkMaintenanceThread : public QThread
|
||||
{
|
||||
public:
|
||||
|
||||
ChunkMaintenanceThread(WidgetExplorer* wanderer)
|
||||
{
|
||||
_wanderer = wanderer;
|
||||
_running = true;
|
||||
}
|
||||
|
||||
void askStop()
|
||||
{
|
||||
_running = false;
|
||||
}
|
||||
|
||||
static inline void usleep(unsigned long us)
|
||||
{
|
||||
QThread::usleep(us);
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
void run()
|
||||
{
|
||||
while (_running)
|
||||
{
|
||||
_wanderer->performChunksMaintenance();
|
||||
QThread::usleep(10000);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
bool _running;
|
||||
WidgetExplorer* _wanderer;
|
||||
};
|
||||
|
||||
static QVector<ChunkMaintenanceThread*> _threads;
|
||||
|
||||
WidgetExplorer::WidgetExplorer(QWidget *parent, CameraDefinition* camera, Scenery* scenery) :
|
||||
QGLWidget(parent)
|
||||
{
|
||||
|
@ -67,13 +28,6 @@ QGLWidget(parent)
|
|||
camera->copy(_current_camera);
|
||||
|
||||
_renderer = new OpenGLRenderer(scenery);
|
||||
_renderer->prepare();
|
||||
_renderer->render_quality = 3;
|
||||
_renderer->getLightingManager()->setSpecularity(false);
|
||||
_renderer->disableClouds();
|
||||
|
||||
_inited = false;
|
||||
_updated = false;
|
||||
|
||||
_average_frame_time = 0.05;
|
||||
_quality = 3;
|
||||
|
@ -85,111 +39,10 @@ QGLWidget(parent)
|
|||
|
||||
WidgetExplorer::~WidgetExplorer()
|
||||
{
|
||||
stopRendering();
|
||||
|
||||
for (int i = 0; i < _chunks.count(); i++)
|
||||
{
|
||||
delete _chunks[i];
|
||||
}
|
||||
delete _current_camera;
|
||||
delete _renderer;
|
||||
}
|
||||
|
||||
void WidgetExplorer::startRendering()
|
||||
{
|
||||
// Add terrain
|
||||
int chunks = 20;
|
||||
double size = 400.0;
|
||||
double chunksize = size / (double) chunks;
|
||||
double start = -size / 2.0;
|
||||
double water_height = _renderer->getWaterRenderer()->getHeightInfo().base_height;
|
||||
for (int i = 0; i < chunks; i++)
|
||||
{
|
||||
for (int j = 0; j < chunks; j++)
|
||||
{
|
||||
ExplorerChunkTerrain* chunk = new ExplorerChunkTerrain(_renderer, start + chunksize * (double) i, start + chunksize * (double) j, chunksize, chunks, water_height);
|
||||
_chunks.append(chunk);
|
||||
_updateQueue.append(chunk);
|
||||
}
|
||||
}
|
||||
|
||||
// Add skybox
|
||||
for (int orientation = 0; orientation < 5; orientation++)
|
||||
{
|
||||
ExplorerChunkSky* chunk = new ExplorerChunkSky(_renderer, 500.0, (SkyboxOrientation) orientation);
|
||||
_chunks.append(chunk);
|
||||
_updateQueue.append(chunk);
|
||||
}
|
||||
|
||||
// Start rendering workers
|
||||
int nbcore;
|
||||
_alive = true;
|
||||
|
||||
nbcore = QThread::idealThreadCount();
|
||||
if (nbcore < 1)
|
||||
{
|
||||
nbcore = 1;
|
||||
}
|
||||
|
||||
for (int i = 0; i < nbcore; i++)
|
||||
{
|
||||
_threads.append(new ChunkMaintenanceThread(this));
|
||||
}
|
||||
for (int i = 0; i < _threads.count(); i++)
|
||||
{
|
||||
_threads[i]->start();
|
||||
}
|
||||
}
|
||||
|
||||
void WidgetExplorer::stopRendering()
|
||||
{
|
||||
for (int i = 0; i < _threads.count(); i++)
|
||||
{
|
||||
_threads[i]->askStop();
|
||||
}
|
||||
_alive = false;
|
||||
for (int i = 0; i < _threads.count(); i++)
|
||||
{
|
||||
_threads[i]->wait();
|
||||
}
|
||||
}
|
||||
|
||||
bool _cmpChunks(const BaseExplorerChunk* c1, const BaseExplorerChunk* c2)
|
||||
{
|
||||
return c1->priority > c2->priority;
|
||||
}
|
||||
|
||||
void WidgetExplorer::performChunksMaintenance()
|
||||
{
|
||||
BaseExplorerChunk* chunk;
|
||||
|
||||
_lock_chunks.lock();
|
||||
if (_updateQueue.count() > 0)
|
||||
{
|
||||
chunk = _updateQueue.takeFirst();
|
||||
_lock_chunks.unlock();
|
||||
}
|
||||
else
|
||||
{
|
||||
_lock_chunks.unlock();
|
||||
return;
|
||||
}
|
||||
|
||||
if (chunk->maintain())
|
||||
{
|
||||
if (!_alive)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_updated = true;
|
||||
}
|
||||
|
||||
_lock_chunks.lock();
|
||||
_updateQueue.append(chunk);
|
||||
_lock_chunks.unlock();
|
||||
}
|
||||
|
||||
void WidgetExplorer::resetCamera()
|
||||
{
|
||||
_base_camera->copy(_current_camera);
|
||||
|
@ -332,25 +185,7 @@ void WidgetExplorer::wheelEvent(QWheelEvent* event)
|
|||
|
||||
void WidgetExplorer::timerEvent(QTimerEvent*)
|
||||
{
|
||||
if (!_inited)
|
||||
{
|
||||
_inited = true;
|
||||
startRendering();
|
||||
}
|
||||
|
||||
if (_updated)
|
||||
{
|
||||
_updated = false;
|
||||
updateGL();
|
||||
}
|
||||
|
||||
for (int i = 0; i < _chunks.count(); i++)
|
||||
{
|
||||
_chunks[i]->updatePriority(_current_camera);
|
||||
}
|
||||
_lock_chunks.lock();
|
||||
qSort(_updateQueue.begin(), _updateQueue.end(), _cmpChunks);
|
||||
_lock_chunks.unlock();
|
||||
updateGL();
|
||||
}
|
||||
|
||||
void WidgetExplorer::initializeGL()
|
||||
|
@ -366,46 +201,18 @@ void WidgetExplorer::resizeGL(int w, int h)
|
|||
|
||||
void WidgetExplorer::paintGL()
|
||||
{
|
||||
GLenum error_code;
|
||||
QTime start_time;
|
||||
double frame_time;
|
||||
WaterDefinition* water = _renderer->getScenery()->getWater();
|
||||
|
||||
// Don't do this at each frame, only on camera change
|
||||
_renderer->getScenery()->setCamera(_current_camera);
|
||||
_renderer->getScenery()->getCamera(_current_camera);
|
||||
_renderer->cameraChangeEvent(_current_camera);
|
||||
|
||||
start_time = QTime::currentTime();
|
||||
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glLoadIdentity();
|
||||
Vector3 camera_location = _current_camera->getLocation();
|
||||
Vector3 camera_target = _current_camera->getTarget();
|
||||
Vector3 camera_up = _current_camera->getUpVector();
|
||||
gluLookAt(camera_location.x, camera_location.y, camera_location.z, camera_target.x, camera_target.y, camera_target.z, camera_up.x, camera_up.y, camera_up.z);
|
||||
|
||||
// Background
|
||||
glClearColor(0.0, 0.0, 0.0, 0.0);
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
|
||||
// Render water
|
||||
double water_height = _renderer->getTerrainRenderer()->getWaterHeight();
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
glColor3f(water->material->_rgb.r, water->material->_rgb.g, water->material->_rgb.b);
|
||||
glBegin(GL_QUADS);
|
||||
glVertex3f(camera_location.x - 500.0, water_height, camera_location.z - 500.0);
|
||||
glVertex3f(camera_location.x - 500.0, water_height, camera_location.z + 500.0);
|
||||
glVertex3f(camera_location.x + 500.0, water_height, camera_location.z + 500.0);
|
||||
glVertex3f(camera_location.x + 500.0, water_height, camera_location.z - 500.0);
|
||||
glEnd();
|
||||
|
||||
// Render chunks
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
for (int i = 0; i < _chunks.count(); i++)
|
||||
{
|
||||
glColor3f(1.0, 1.0, 1.0);
|
||||
_chunks[i]->render(this);
|
||||
}
|
||||
_renderer->paint();
|
||||
|
||||
frame_time = 0.001 * (double) start_time.msecsTo(QTime::currentTime());
|
||||
|
||||
|
@ -422,16 +229,11 @@ void WidgetExplorer::paintGL()
|
|||
}
|
||||
|
||||
// Messages
|
||||
if (!_inited)
|
||||
/*if (!_inited)
|
||||
{
|
||||
glColor3f(0.0, 0.0, 0.0);
|
||||
renderText(6, height() - 10, tr("Please wait while loading scene..."));
|
||||
glColor3f(1.0, 1.0, 1.0);
|
||||
renderText(5, height() - 9, tr("Please wait while loading scene..."));
|
||||
}
|
||||
|
||||
while ((error_code = glGetError()) != GL_NO_ERROR)
|
||||
{
|
||||
qDebug("[OpenGL] ERROR : %s", (const char*)gluErrorString(error_code));
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
|
|
@ -5,8 +5,6 @@
|
|||
|
||||
#include <QGLWidget>
|
||||
|
||||
#include <QMutex>
|
||||
|
||||
namespace paysages {
|
||||
namespace opengl {
|
||||
|
||||
|
@ -17,8 +15,6 @@ public:
|
|||
WidgetExplorer(QWidget* parent, CameraDefinition* camera, Scenery* scenery);
|
||||
~WidgetExplorer();
|
||||
|
||||
void performChunksMaintenance();
|
||||
|
||||
public slots:
|
||||
void resetCamera();
|
||||
void validateCamera();
|
||||
|
@ -35,20 +31,10 @@ protected:
|
|||
void paintGL();
|
||||
|
||||
private:
|
||||
void startRendering();
|
||||
void stopRendering();
|
||||
|
||||
CameraDefinition* _current_camera;
|
||||
CameraDefinition* _base_camera;
|
||||
|
||||
OpenGLRenderer* _renderer;
|
||||
bool _inited;
|
||||
bool _updated;
|
||||
|
||||
QVector<BaseExplorerChunk*> _chunks;
|
||||
QList<BaseExplorerChunk*> _updateQueue;
|
||||
bool _alive;
|
||||
QMutex _lock_chunks;
|
||||
|
||||
double _average_frame_time;
|
||||
int _quality;
|
||||
|
|
|
@ -13,20 +13,33 @@ DEFINES += OPENGL_LIBRARY
|
|||
|
||||
include(../../common.pri)
|
||||
|
||||
unix:LIBS += -lGLU
|
||||
|
||||
SOURCES += \
|
||||
OpenGLRenderer.cpp \
|
||||
BaseExplorerChunk.cpp \
|
||||
ExplorerChunkSky.cpp \
|
||||
ExplorerChunkTerrain.cpp \
|
||||
WidgetExplorer.cpp
|
||||
WidgetExplorer.cpp \
|
||||
OpenGLShaderProgram.cpp \
|
||||
OpenGLPart.cpp \
|
||||
OpenGLSkybox.cpp \
|
||||
OpenGLWater.cpp \
|
||||
OpenGLSharedState.cpp \
|
||||
OpenGLVariable.cpp \
|
||||
OpenGLTerrain.cpp
|
||||
|
||||
HEADERS +=\
|
||||
opengl_global.h \
|
||||
OpenGLRenderer.h \
|
||||
BaseExplorerChunk.h \
|
||||
ExplorerChunkSky.h \
|
||||
ExplorerChunkTerrain.h \
|
||||
WidgetExplorer.h
|
||||
WidgetExplorer.h \
|
||||
OpenGLShaderProgram.h \
|
||||
OpenGLPart.h \
|
||||
OpenGLSkybox.h \
|
||||
OpenGLWater.h \
|
||||
OpenGLSharedState.h \
|
||||
OpenGLVariable.h \
|
||||
OpenGLTerrain.h \
|
||||
VertexArray.h
|
||||
|
||||
unix:!symbian {
|
||||
maemo5 {
|
||||
|
@ -60,3 +73,18 @@ else:win32:CONFIG(debug, debug|release): LIBS += -L$$OUT_PWD/../software/debug/
|
|||
else:unix: LIBS += -L$$OUT_PWD/../software/ -lpaysages_render_software
|
||||
INCLUDEPATH += $$PWD/../software
|
||||
DEPENDPATH += $$PWD/../software
|
||||
|
||||
RESOURCES += \
|
||||
shaders/resources.qrc
|
||||
|
||||
OTHER_FILES += \
|
||||
shaders/skybox.frag \
|
||||
shaders/skybox.vert \
|
||||
shaders/water.vert \
|
||||
shaders/water.frag \
|
||||
shaders/bruneton.frag \
|
||||
shaders/bruneton.frag \
|
||||
shaders/tonemapping.frag \
|
||||
shaders/terrain.frag \
|
||||
shaders/terrain.vert \
|
||||
shaders/fadeout.frag
|
||||
|
|
|
@ -15,9 +15,21 @@ namespace paysages {
|
|||
namespace opengl {
|
||||
class WidgetExplorer;
|
||||
class OpenGLRenderer;
|
||||
class BaseExplorerChunk;
|
||||
class OpenGLShaderProgram;
|
||||
class OpenGLSharedState;
|
||||
class OpenGLVariable;
|
||||
class OpenGLSkybox;
|
||||
class OpenGLWater;
|
||||
class OpenGLTerrain;
|
||||
class ExplorerChunkTerrain;
|
||||
template <typename Vertex> class VertexArray;
|
||||
}
|
||||
}
|
||||
using namespace paysages::opengl;
|
||||
|
||||
//#define OpenGLFunctions QOpenGLFunctions_3_2_Core
|
||||
#define OpenGLFunctions QOpenGLFunctions_3_0
|
||||
#define OPENGL_FUNCTIONS_INCLUDE <OpenGLFunctions>
|
||||
class OpenGLFunctions;
|
||||
|
||||
#endif // OPENGL_GLOBAL_H
|
||||
|
|
211
src/render/opengl/shaders/bruneton.frag
Normal file
211
src/render/opengl/shaders/bruneton.frag
Normal file
|
@ -0,0 +1,211 @@
|
|||
const float GROUND_OFFSET = 0.5;
|
||||
const float Rg = 6360.0;
|
||||
const float Rt = 6420.0;
|
||||
const float RL = 6421.0;
|
||||
const float ISun = 100.0;
|
||||
const float AVERAGE_GROUND_REFLECTANCE = 0.1;
|
||||
const float HR = 8.0;
|
||||
const vec3 betaR = vec3(5.8e-3, 1.35e-2, 3.31e-2);
|
||||
const float HM = 1.2;
|
||||
const vec3 betaMSca = vec3(4e-3);
|
||||
const vec3 betaMEx = vec3(4e-3 / 0.9);
|
||||
const float mieG = 0.8;
|
||||
const float SPHERE_SIZE = 20000.0;
|
||||
const float WORLD_SCALING = 0.05;
|
||||
const float SUN_DISTANCE = 149597870.0;
|
||||
const float SUN_DISTANCE_SCALED = (SUN_DISTANCE / WORLD_SCALING);
|
||||
const float SUN_RADIUS = 6.955e5;
|
||||
const float SUN_RADIUS_SCALED = (SUN_RADIUS / WORLD_SCALING);
|
||||
const float M_PI = 3.141592657;
|
||||
|
||||
const int RES_MU = 128;
|
||||
const int RES_MU_S = 32;
|
||||
const int RES_R = 32;
|
||||
const int RES_NU = 8;
|
||||
|
||||
uniform float waterHeight;
|
||||
uniform vec3 cameraLocation;
|
||||
uniform vec3 sunDirection;
|
||||
uniform vec4 sunColor;
|
||||
const float sunRadius = 1.0; // TODO -> uniform
|
||||
|
||||
varying vec3 unprojected;
|
||||
|
||||
uniform sampler2D transmittanceTexture;
|
||||
uniform sampler3D inscatterTexture;
|
||||
|
||||
vec4 texture4D(sampler3D tex, float r, float mu, float muS, float nu)
|
||||
{
|
||||
if (r < Rg + 0.00000001) r = Rg + 0.00000001;
|
||||
float H = sqrt(Rt * Rt - Rg * Rg);
|
||||
float rho = sqrt(r * r - Rg * Rg);
|
||||
float rmu = r * mu;
|
||||
float delta = rmu * rmu - r * r + Rg * Rg;
|
||||
vec4 cst = (rmu < 0.0 && delta > 0.0) ? vec4(1.0, 0.0, 0.0, 0.5 - 0.5 / float(RES_MU)) : vec4(-1.0, H * H, H, 0.5 + 0.5 / float(RES_MU));
|
||||
float uR = 0.5 / float(RES_R) + rho / H * (1.0 - 1.0 / float(RES_R));
|
||||
float uMu = cst.a + (rmu * cst.r + sqrt(delta + cst.g)) / (rho + cst.b) * (0.5 - 1.0 / float(RES_MU));
|
||||
float uMuS = 0.5 / float(RES_MU_S) + (atan(max(muS, -0.1975) * tan(1.26 * 1.1)) / 1.1 + (1.0 - 0.26)) * 0.5 * (1.0 - 1.0 / float(RES_MU_S));
|
||||
|
||||
float sr = 1.0 / float(RES_R);
|
||||
int br = int(floor(uR / sr));
|
||||
vec4 r1 = texture3D(tex, vec3(uMu, uMuS, float(br) * sr + nu * sr));
|
||||
vec4 r2 = texture3D(tex, vec3(uMu, uMuS, float(br + 1) * sr + nu * sr));
|
||||
return mix(r1, r2, (uR - float(br) * sr) / sr);
|
||||
}
|
||||
|
||||
float _limit(float r, float mu)
|
||||
{
|
||||
float dout = -r * mu + sqrt(r * r * (mu * mu - 1.0) + RL * RL);
|
||||
float delta2 = r * r * (mu * mu - 1.0) + Rg * Rg;
|
||||
if (delta2 >= 0.0)
|
||||
{
|
||||
float din = -r * mu - sqrt(delta2);
|
||||
if (din >= 0.0) {
|
||||
dout = min(dout, din);
|
||||
}
|
||||
}
|
||||
return dout;
|
||||
}
|
||||
|
||||
vec2 _getTransmittanceUV(float r, float mu)
|
||||
{
|
||||
if (r < Rg + 0.00000001) r = Rg + 0.00000001;
|
||||
float dr = (r - Rg) / (Rt - Rg);
|
||||
return vec2(atan((mu + 0.15) / (1.0 + 0.15) * tan(1.5)) / 1.5, sqrt(dr));
|
||||
}
|
||||
|
||||
vec4 _transmittance(float r, float mu)
|
||||
{
|
||||
vec2 uv = _getTransmittanceUV(r, mu);
|
||||
return texture2D(transmittanceTexture, uv);
|
||||
}
|
||||
|
||||
vec4 _transmittanceWithShadow(float r, float mu)
|
||||
{
|
||||
return mu < -sqrt(1.0 - (Rg / r) * (Rg / r)) ? vec4(0.0) : _transmittance(r, mu);
|
||||
}
|
||||
|
||||
vec4 _sunTransmittance(vec3 v, vec3 s, float r, float mu, float radius)
|
||||
{
|
||||
vec4 transmittance = r <= Rt ? _transmittanceWithShadow(r, mu) : vec4(1.0); /* T(x,xo) */
|
||||
float d = _limit(r, mu);
|
||||
radius *= (1.0 + 25.0 * d / Rt); /* Inflating due to lens effect near horizon */
|
||||
float isun = step(cos(radius * M_PI / 180.0), dot(v, s)) * ISun; /* Lsun */
|
||||
transmittance.r *= isun;
|
||||
transmittance.g *= isun;
|
||||
transmittance.b *= isun;
|
||||
transmittance.a = 1.0;
|
||||
return transmittance; /* Eq (9) */
|
||||
}
|
||||
|
||||
float phaseFunctionR(float mu) {
|
||||
return (3.0 / (16.0 * M_PI)) * (1.0 + mu * mu);
|
||||
}
|
||||
|
||||
float phaseFunctionM(float mu) {
|
||||
return 1.5 * 1.0 / (4.0 * M_PI) * (1.0 - mieG*mieG) * pow(1.0 + (mieG*mieG) - 2.0*mieG*mu, -3.0/2.0) * (1.0 + mu * mu) / (2.0 + mieG*mieG);
|
||||
}
|
||||
|
||||
float opticalDepth(float H, float r, float mu, float d) {
|
||||
float a = sqrt((0.5/H)*r);
|
||||
vec2 a01 = a*vec2(mu, mu + d / r);
|
||||
vec2 a01s = sign(a01);
|
||||
vec2 a01sq = a01*a01;
|
||||
float x = a01s.y > a01s.x ? exp(a01sq.x) : 0.0;
|
||||
vec2 y = a01s / (2.3193*abs(a01) + sqrt(1.52*a01sq + 4.0)) * vec2(1.0, exp(-d/H*(d/(2.0*r)+mu)));
|
||||
return sqrt((6.2831*H)*r) * exp((Rg-r)/H) * (x + dot(y, vec2(1.0, -1.0)));
|
||||
}
|
||||
|
||||
vec3 analyticTransmittance(float r, float mu, float d) {
|
||||
return exp(- betaR * opticalDepth(HR, r, mu, d) - betaMEx * opticalDepth(HM, r, mu, d));
|
||||
}
|
||||
|
||||
vec3 getMie(vec4 rayMie) { // rayMie.rgb=C*, rayMie.w=Cm,r
|
||||
return rayMie.rgb * rayMie.w / max(rayMie.r, 1e-4) * (betaR.r / betaR);
|
||||
}
|
||||
|
||||
vec3 _getInscatterColor(inout vec3 x, inout float t, vec3 v, vec3 s, out float r, out float mu, out vec3 attenuation) {
|
||||
vec3 result;
|
||||
r = length(x);
|
||||
mu = dot(x, v) / r;
|
||||
float d = -r * mu - sqrt(r * r * (mu * mu - 1.0) + Rt * Rt);
|
||||
if (d > 0.0) { // if x in space and ray intersects atmosphere
|
||||
// move x to nearest intersection of ray with top atmosphere boundary
|
||||
x += d * v;
|
||||
t -= d;
|
||||
mu = (r * mu + d) / Rt;
|
||||
r = Rt;
|
||||
}
|
||||
if (r <= Rt) { // if ray intersects atmosphere
|
||||
float nu = dot(v, s);
|
||||
float muS = dot(x, s) / r;
|
||||
float phaseR = phaseFunctionR(nu);
|
||||
float phaseM = phaseFunctionM(nu);
|
||||
vec4 inscatter = max(texture4D(inscatterTexture, r, mu, muS, nu), 0.0);
|
||||
if (t > 0.0) {
|
||||
vec3 x0 = x + t * v;
|
||||
float r0 = length(x0);
|
||||
float rMu0 = dot(x0, v);
|
||||
float mu0 = rMu0 / r0;
|
||||
float muS0 = dot(x0, s) / r0;
|
||||
// avoids imprecision problems in transmittance computations based on textures
|
||||
attenuation = analyticTransmittance(r, mu, t);
|
||||
if (r0 > Rg + 0.001) {
|
||||
// computes S[L]-T(x,x0)S[L]|x0
|
||||
inscatter = max(inscatter - attenuation.rgbr * texture4D(inscatterTexture, r0, mu0, muS0, nu), 0.0);
|
||||
// avoids imprecision problems near horizon by interpolating between two points above and below horizon
|
||||
const float EPS = 0.02;
|
||||
float muHoriz = -sqrt(1.0 - (Rg / r) * (Rg / r));
|
||||
if (abs(mu - muHoriz) < EPS) {
|
||||
float a = ((mu - muHoriz) + EPS) / (2.0 * EPS);
|
||||
|
||||
mu = muHoriz - EPS;
|
||||
r0 = sqrt(r * r + t * t + 2.0 * r * t * mu);
|
||||
mu0 = (r * mu + t) / r0;
|
||||
vec4 inScatter0 = texture4D(inscatterTexture, r, mu, muS, nu);
|
||||
vec4 inScatter1 = texture4D(inscatterTexture, r0, mu0, muS0, nu);
|
||||
vec4 inScatterA = max(inScatter0 - attenuation.rgbr * inScatter1, 0.0);
|
||||
|
||||
mu = muHoriz + EPS;
|
||||
r0 = sqrt(r * r + t * t + 2.0 * r * t * mu);
|
||||
mu0 = (r * mu + t) / r0;
|
||||
inScatter0 = texture4D(inscatterTexture, r, mu, muS, nu);
|
||||
inScatter1 = texture4D(inscatterTexture, r0, mu0, muS0, nu);
|
||||
vec4 inScatterB = max(inScatter0 - attenuation.rgbr * inScatter1, 0.0);
|
||||
|
||||
inscatter = mix(inScatterA, inScatterB, a);
|
||||
}
|
||||
}
|
||||
}
|
||||
// avoids imprecision problems in Mie scattering when sun is below horizon
|
||||
inscatter.w *= smoothstep(0.00, 0.02, muS);
|
||||
result = max(inscatter.rgb * phaseR + getMie(inscatter) * phaseM, 0.0);
|
||||
} else { // x in space and ray looking in space
|
||||
result = vec3(0.0);
|
||||
}
|
||||
return result * ISun;
|
||||
}
|
||||
|
||||
vec4 applyAerialPerspective(vec4 base)
|
||||
{
|
||||
float yoffset = GROUND_OFFSET - waterHeight;
|
||||
vec3 camera = vec3(cameraLocation.x, max(cameraLocation.y + yoffset, 0.0), cameraLocation.z);
|
||||
vec3 location = vec3(unprojected.x, max(unprojected.y + yoffset, 0.0), unprojected.z);
|
||||
vec3 x = vec3(0.0, Rg + camera.y * WORLD_SCALING, 0.0);
|
||||
vec3 v = normalize(location - camera);
|
||||
vec3 s = normalize(sunDirection * SUN_DISTANCE_SCALED - x);
|
||||
|
||||
if (v.y == 0.0)
|
||||
{
|
||||
v.y = -0.000001;
|
||||
}
|
||||
|
||||
float r = length(x);
|
||||
float mu = dot(x, v) / r;
|
||||
float t = length(location - camera) * WORLD_SCALING;
|
||||
|
||||
vec3 attenuation;
|
||||
vec3 inscattering = _getInscatterColor(x, t, v, s, r, mu, attenuation);
|
||||
|
||||
return base * vec4(attenuation, 0.0) + vec4(inscattering, 0.0);
|
||||
}
|
8
src/render/opengl/shaders/fadeout.frag
Normal file
8
src/render/opengl/shaders/fadeout.frag
Normal file
|
@ -0,0 +1,8 @@
|
|||
uniform float viewDistance;
|
||||
|
||||
float distanceFadeout()
|
||||
{
|
||||
vec3 camera = vec3(cameraLocation.x, 0.0, cameraLocation.z);
|
||||
vec3 location = vec3(unprojected.x, 0.0, unprojected.z);
|
||||
return mix(1.0, 0.0, clamp((length(location - camera) - viewDistance * 0.8) / (viewDistance * 0.2), 0.0, 1.0));
|
||||
}
|
13
src/render/opengl/shaders/resources.qrc
Normal file
13
src/render/opengl/shaders/resources.qrc
Normal file
|
@ -0,0 +1,13 @@
|
|||
<RCC>
|
||||
<qresource prefix="/shaders">
|
||||
<file>skybox.frag</file>
|
||||
<file>skybox.vert</file>
|
||||
<file>water.frag</file>
|
||||
<file>water.vert</file>
|
||||
<file>bruneton.frag</file>
|
||||
<file>tonemapping.frag</file>
|
||||
<file>terrain.frag</file>
|
||||
<file>terrain.vert</file>
|
||||
<file>fadeout.frag</file>
|
||||
</qresource>
|
||||
</RCC>
|
19
src/render/opengl/shaders/skybox.frag
Normal file
19
src/render/opengl/shaders/skybox.frag
Normal file
|
@ -0,0 +1,19 @@
|
|||
void main(void)
|
||||
{
|
||||
float yoffset = GROUND_OFFSET - waterHeight;
|
||||
vec3 camera = vec3(cameraLocation.x, max(cameraLocation.y + yoffset, 0.0), cameraLocation.z);
|
||||
vec3 location = vec3(unprojected.x, max(unprojected.y + yoffset, 0.0), unprojected.z);
|
||||
vec3 x = vec3(0.0, Rg + camera.y * WORLD_SCALING, 0.0);
|
||||
vec3 v = normalize(location - camera);
|
||||
vec3 s = normalize(sunDirection * SUN_DISTANCE_SCALED - x);
|
||||
|
||||
float r = length(x);
|
||||
float mu = dot(x, v) / r;
|
||||
float t = -r * mu - sqrt(r * r * (mu * mu - 1.0) + Rg * Rg);
|
||||
|
||||
vec4 sunTransmittance = _sunTransmittance(v, s, r, mu, sunRadius);
|
||||
vec3 attenuation;
|
||||
vec3 inscattering = _getInscatterColor(x, t, v, s, r, mu, attenuation);
|
||||
|
||||
gl_FragColor = applyToneMapping(sunTransmittance + vec4(inscattering, 0.0));
|
||||
}
|
10
src/render/opengl/shaders/skybox.vert
Normal file
10
src/render/opengl/shaders/skybox.vert
Normal file
|
@ -0,0 +1,10 @@
|
|||
attribute highp vec4 vertex;
|
||||
uniform highp mat4 viewMatrix;
|
||||
uniform vec3 cameraLocation;
|
||||
varying vec3 unprojected;
|
||||
|
||||
void main(void)
|
||||
{
|
||||
unprojected = cameraLocation + vertex.xyz * 500.0;
|
||||
gl_Position = viewMatrix * vec4(unprojected, 1.0);
|
||||
}
|
13
src/render/opengl/shaders/terrain.frag
Normal file
13
src/render/opengl/shaders/terrain.frag
Normal file
|
@ -0,0 +1,13 @@
|
|||
uniform sampler2D groundTexture;
|
||||
varying vec2 texcoord;
|
||||
|
||||
void main(void)
|
||||
{
|
||||
gl_FragColor = texture2D(groundTexture, texcoord);
|
||||
|
||||
gl_FragColor = applyAerialPerspective(gl_FragColor);
|
||||
|
||||
gl_FragColor = applyToneMapping(gl_FragColor);
|
||||
|
||||
gl_FragColor.a = distanceFadeout();
|
||||
}
|
12
src/render/opengl/shaders/terrain.vert
Normal file
12
src/render/opengl/shaders/terrain.vert
Normal file
|
@ -0,0 +1,12 @@
|
|||
attribute highp vec4 vertex;
|
||||
attribute highp vec2 uv;
|
||||
uniform highp mat4 viewMatrix;
|
||||
varying vec3 unprojected;
|
||||
varying vec2 texcoord;
|
||||
|
||||
void main(void)
|
||||
{
|
||||
unprojected = vertex.xyz;
|
||||
texcoord = uv;
|
||||
gl_Position = viewMatrix * vertex;
|
||||
}
|
32
src/render/opengl/shaders/tonemapping.frag
Normal file
32
src/render/opengl/shaders/tonemapping.frag
Normal file
|
@ -0,0 +1,32 @@
|
|||
uniform float exposure;
|
||||
|
||||
float _uncharted2Tonemap(float x)
|
||||
{
|
||||
float A = 0.15;
|
||||
float B = 0.50;
|
||||
float C = 0.10;
|
||||
float D = 0.20;
|
||||
float E = 0.02;
|
||||
float F = 0.30;
|
||||
|
||||
return ((x * (A * x + C * B) + D * E) / (x * (A * x + B) + D * F)) - E / F;
|
||||
}
|
||||
|
||||
vec4 applyToneMapping(vec4 color)
|
||||
{
|
||||
return vec4(((color * exposure) / (1.0 + color * exposure)).rgb, 1.0);
|
||||
}
|
||||
|
||||
/*vec4 applyToneMapping(vec4 color)
|
||||
{
|
||||
float W = 11.2;
|
||||
float white_scale = 1.0 / _uncharted2Tonemap(W);
|
||||
vec4 result;
|
||||
|
||||
result.r = pow(_uncharted2Tonemap(color.r * exposure) * white_scale, 1.0 / 2.2);
|
||||
result.g = pow(_uncharted2Tonemap(color.g * exposure) * white_scale, 1.0 / 2.2);
|
||||
result.b = pow(_uncharted2Tonemap(color.b * exposure) * white_scale, 1.0 / 2.2);
|
||||
result.a = 1.0;
|
||||
|
||||
return result;
|
||||
}*/
|
12
src/render/opengl/shaders/water.frag
Normal file
12
src/render/opengl/shaders/water.frag
Normal file
|
@ -0,0 +1,12 @@
|
|||
uniform vec4 waterColor;
|
||||
|
||||
void main(void)
|
||||
{
|
||||
gl_FragColor = waterColor;
|
||||
|
||||
gl_FragColor = applyAerialPerspective(gl_FragColor);
|
||||
|
||||
gl_FragColor = applyToneMapping(gl_FragColor);
|
||||
|
||||
gl_FragColor.a = distanceFadeout();
|
||||
}
|
11
src/render/opengl/shaders/water.vert
Normal file
11
src/render/opengl/shaders/water.vert
Normal file
|
@ -0,0 +1,11 @@
|
|||
attribute highp vec4 vertex;
|
||||
uniform highp mat4 viewMatrix;
|
||||
uniform float waterHeight;
|
||||
uniform vec3 cameraLocation;
|
||||
varying vec3 unprojected;
|
||||
|
||||
void main(void)
|
||||
{
|
||||
unprojected = vec3(cameraLocation.x + vertex.x * 500.0, vertex.y + waterHeight, cameraLocation.z + vertex.z * 500.0);
|
||||
gl_Position = viewMatrix * vec4(unprojected, 1.0);
|
||||
}
|
|
@ -934,7 +934,7 @@ static Color _sunColor(Vector3 v, Vector3 s, double r, double mu, double radius)
|
|||
{
|
||||
Color transmittance = r <= Rt ? _transmittanceWithShadow(r, mu) : COLOR_WHITE; /* T(x,xo) */
|
||||
double d = _limit(r, mu);
|
||||
radius *= (1.0 + 10.0 * d / Rt); /* Inflating due to lens effect near horizon */
|
||||
radius *= (1.0 + 25.0 * d / Rt); /* Inflating due to lens effect near horizon */
|
||||
double isun = step(cos(radius * M_PI / 180.0), v.dotProduct(s)) * ISun; /* Lsun */
|
||||
transmittance.r *= isun;
|
||||
transmittance.g *= isun;
|
||||
|
@ -1268,3 +1268,18 @@ void AtmosphereModelBruneton::fillLightingStatus(LightStatus *status, const Vect
|
|||
|
||||
status->pushComponent(irradiance);
|
||||
}
|
||||
|
||||
Texture2D *AtmosphereModelBruneton::getTextureTransmittance() const
|
||||
{
|
||||
return _transmittanceTexture;
|
||||
}
|
||||
|
||||
Texture2D *AtmosphereModelBruneton::getTextureIrradiance() const
|
||||
{
|
||||
return _irradianceTexture;
|
||||
}
|
||||
|
||||
Texture4D *AtmosphereModelBruneton::getTextureInscatter() const
|
||||
{
|
||||
return _inscatterTexture;
|
||||
}
|
||||
|
|
|
@ -17,6 +17,11 @@ public:
|
|||
AtmosphereResult applyAerialPerspective(Vector3 location, const Color &base);
|
||||
void fillLightingStatus(LightStatus *status, const Vector3 &normal, int opaque);
|
||||
|
||||
/* Functions to get access to internal textures (for opengl shaders) */
|
||||
Texture2D* getTextureTransmittance() const;
|
||||
Texture2D* getTextureIrradiance() const;
|
||||
Texture4D* getTextureInscatter() const;
|
||||
|
||||
private:
|
||||
SoftwareRenderer* parent;
|
||||
};
|
||||
|
|
|
@ -39,6 +39,8 @@ public:
|
|||
virtual AtmosphereResult applyAerialPerspective(Vector3 location, Color base) override;
|
||||
virtual AtmosphereResult getSkyColor(Vector3 direction) override;
|
||||
|
||||
inline const AtmosphereModelBruneton* getModel() const {return model;}
|
||||
|
||||
private:
|
||||
AtmosphereModelBruneton* model;
|
||||
};
|
||||
|
|
1
src/system/Logs.cpp
Normal file
1
src/system/Logs.cpp
Normal file
|
@ -0,0 +1 @@
|
|||
#include "Logs.h"
|
9
src/system/Logs.h
Normal file
9
src/system/Logs.h
Normal file
|
@ -0,0 +1,9 @@
|
|||
#ifndef LOGS_H
|
||||
#define LOGS_H
|
||||
|
||||
#include "system_global.h"
|
||||
|
||||
#define logWarning qWarning
|
||||
#define logError qCritical
|
||||
|
||||
#endif // LOGS_H
|
55
src/system/ParallelPool.cpp
Normal file
55
src/system/ParallelPool.cpp
Normal file
|
@ -0,0 +1,55 @@
|
|||
#include "ParallelPool.h"
|
||||
|
||||
#include "System.h"
|
||||
#include "Thread.h"
|
||||
|
||||
static void* _threadFunction(void* data)
|
||||
{
|
||||
ParallelPool* pool = (ParallelPool*)data;
|
||||
pool->work();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ParallelPool::ParallelPool()
|
||||
{
|
||||
running = false;
|
||||
}
|
||||
|
||||
ParallelPool::~ParallelPool()
|
||||
{
|
||||
if (running)
|
||||
{
|
||||
interrupt();
|
||||
}
|
||||
for (auto thread : threads)
|
||||
{
|
||||
thread->join();
|
||||
delete thread;
|
||||
}
|
||||
threads.clear();
|
||||
}
|
||||
|
||||
void ParallelPool::start(int thread_count)
|
||||
{
|
||||
if (running)
|
||||
{
|
||||
qCritical("Starting an already started parallel pool !");
|
||||
return;
|
||||
}
|
||||
running = true;
|
||||
if (thread_count < 0)
|
||||
{
|
||||
thread_count = System::getCoreCount();
|
||||
}
|
||||
for (int i = 0; i < thread_count; i++)
|
||||
{
|
||||
Thread* thread = new Thread(_threadFunction);
|
||||
thread->start(this);
|
||||
threads.push_back(thread);
|
||||
}
|
||||
}
|
||||
|
||||
void ParallelPool::interrupt()
|
||||
{
|
||||
running = false;
|
||||
}
|
43
src/system/ParallelPool.h
Normal file
43
src/system/ParallelPool.h
Normal file
|
@ -0,0 +1,43 @@
|
|||
#ifndef PARALLELPOOL_H
|
||||
#define PARALLELPOOL_H
|
||||
|
||||
#include "system_global.h"
|
||||
|
||||
namespace paysages {
|
||||
namespace system {
|
||||
|
||||
/*!
|
||||
* Pool to handle a group of threads doing the same task.
|
||||
*/
|
||||
class ParallelPool
|
||||
{
|
||||
public:
|
||||
ParallelPool();
|
||||
virtual ~ParallelPool();
|
||||
|
||||
/*!
|
||||
* Start the effective work.
|
||||
*/
|
||||
void start(int thread_count=-1);
|
||||
|
||||
/*!
|
||||
* Method called from each thread to do actual work.
|
||||
*/
|
||||
virtual void work() = 0;
|
||||
|
||||
/*!
|
||||
* Method called once to interrupt all threads.
|
||||
*/
|
||||
virtual void interrupt();
|
||||
|
||||
protected:
|
||||
bool running;
|
||||
|
||||
private:
|
||||
std::vector<Thread*> threads;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif // PARALLELPOOL_H
|
|
@ -23,7 +23,9 @@ SOURCES += \
|
|||
ParallelWork.cpp \
|
||||
ParallelQueue.cpp \
|
||||
CacheFile.cpp \
|
||||
PictureWriter.cpp
|
||||
PictureWriter.cpp \
|
||||
Logs.cpp \
|
||||
ParallelPool.cpp
|
||||
|
||||
HEADERS += \
|
||||
system_global.h \
|
||||
|
@ -36,7 +38,9 @@ HEADERS += \
|
|||
ParallelWork.h \
|
||||
ParallelQueue.h \
|
||||
CacheFile.h \
|
||||
PictureWriter.h
|
||||
PictureWriter.h \
|
||||
Logs.h \
|
||||
ParallelPool.h
|
||||
|
||||
unix:!symbian {
|
||||
maemo5 {
|
||||
|
|
|
@ -15,6 +15,7 @@ namespace system {
|
|||
class PackStream;
|
||||
class ParallelQueue;
|
||||
class ParallelWork;
|
||||
class ParallelPool;
|
||||
class Thread;
|
||||
class Mutex;
|
||||
}
|
||||
|
|
100
src/tests/VertexArray_Test.cpp
Normal file
100
src/tests/VertexArray_Test.cpp
Normal file
|
@ -0,0 +1,100 @@
|
|||
#include "BaseTestCase.h"
|
||||
|
||||
#include "VertexArray.h"
|
||||
|
||||
class TestVertex
|
||||
{
|
||||
public:
|
||||
float uv[2];
|
||||
int loc[3];
|
||||
|
||||
bool operator==(const TestVertex &other) const
|
||||
{
|
||||
return other.uv[0] == uv[0]
|
||||
and other.uv[1] == uv[1]
|
||||
and other.loc[0] == loc[0]
|
||||
and other.loc[1] == loc[1]
|
||||
and other.loc[2] == loc[2];
|
||||
}
|
||||
};
|
||||
|
||||
TEST(VertexArray, grid)
|
||||
{
|
||||
VertexArray<TestVertex> array;
|
||||
|
||||
array.setGridSize(3);
|
||||
|
||||
ASSERT_EQ(9, array.getVertexCount());
|
||||
|
||||
TestVertex v1 = {{0.1, 0.2}, {1, 2, 3}};
|
||||
TestVertex vgot;
|
||||
|
||||
array.setGridVertex(3, 1, 2, v1);
|
||||
vgot = array.getGridVertex(3, 1, 2);
|
||||
EXPECT_EQ(v1, vgot);
|
||||
vgot = array.getVertex(7);
|
||||
EXPECT_EQ(v1, vgot);
|
||||
}
|
||||
|
||||
TEST(VertexArray, gridIndices)
|
||||
{
|
||||
VertexArray<TestVertex> array;
|
||||
|
||||
array.setGridSize(3);
|
||||
|
||||
array.setAutoGridIndices(3);
|
||||
ASSERT_EQ(24, array.getIndexCount());
|
||||
|
||||
EXPECT_EQ(0, array.getIndex(0));
|
||||
EXPECT_EQ(3, array.getIndex(1));
|
||||
EXPECT_EQ(1, array.getIndex(2));
|
||||
|
||||
EXPECT_EQ(1, array.getIndex(3));
|
||||
EXPECT_EQ(3, array.getIndex(4));
|
||||
EXPECT_EQ(4, array.getIndex(5));
|
||||
|
||||
EXPECT_EQ(1, array.getIndex(6));
|
||||
EXPECT_EQ(4, array.getIndex(7));
|
||||
EXPECT_EQ(2, array.getIndex(8));
|
||||
|
||||
EXPECT_EQ(2, array.getIndex(9));
|
||||
EXPECT_EQ(4, array.getIndex(10));
|
||||
EXPECT_EQ(5, array.getIndex(11));
|
||||
|
||||
EXPECT_EQ(3, array.getIndex(12));
|
||||
EXPECT_EQ(6, array.getIndex(13));
|
||||
EXPECT_EQ(4, array.getIndex(14));
|
||||
}
|
||||
|
||||
TEST(VertexArray, gridIndicesStride)
|
||||
{
|
||||
VertexArray<TestVertex> array;
|
||||
|
||||
array.setGridSize(5);
|
||||
|
||||
array.setAutoGridIndices(5, 1);
|
||||
ASSERT_EQ(96, array.getIndexCount());
|
||||
|
||||
array.setAutoGridIndices(5, 2);
|
||||
ASSERT_EQ(24, array.getIndexCount());
|
||||
|
||||
EXPECT_EQ(0, array.getIndex(0));
|
||||
EXPECT_EQ(10, array.getIndex(1));
|
||||
EXPECT_EQ(2, array.getIndex(2));
|
||||
|
||||
EXPECT_EQ(2, array.getIndex(3));
|
||||
EXPECT_EQ(10, array.getIndex(4));
|
||||
EXPECT_EQ(12, array.getIndex(5));
|
||||
|
||||
EXPECT_EQ(2, array.getIndex(6));
|
||||
EXPECT_EQ(12, array.getIndex(7));
|
||||
EXPECT_EQ(4, array.getIndex(8));
|
||||
|
||||
EXPECT_EQ(4, array.getIndex(9));
|
||||
EXPECT_EQ(12, array.getIndex(10));
|
||||
EXPECT_EQ(14, array.getIndex(11));
|
||||
|
||||
EXPECT_EQ(10, array.getIndex(12));
|
||||
EXPECT_EQ(20, array.getIndex(13));
|
||||
EXPECT_EQ(12, array.getIndex(14));
|
||||
}
|
|
@ -17,7 +17,8 @@ SOURCES += main.cpp \
|
|||
Bruneton_Test.cpp \
|
||||
Camera_Test.cpp \
|
||||
Clouds_Test.cpp \
|
||||
FluidMediumManager_Test.cpp
|
||||
FluidMediumManager_Test.cpp \
|
||||
VertexArray_Test.cpp
|
||||
|
||||
HEADERS += \
|
||||
BaseTestCase.h
|
||||
|
@ -51,3 +52,9 @@ else:win32:CONFIG(debug, debug|release): LIBS += -L$$OUT_PWD/../render/software/
|
|||
else:unix: LIBS += -L$$OUT_PWD/../render/software/ -lpaysages_render_software
|
||||
INCLUDEPATH += $$PWD/../render/software
|
||||
DEPENDPATH += $$PWD/../render/software
|
||||
|
||||
win32:CONFIG(release, debug|release): LIBS += -L$$OUT_PWD/../render/opengl/release/ -lpaysages_render_opengl
|
||||
else:win32:CONFIG(debug, debug|release): LIBS += -L$$OUT_PWD/../render/opengl/debug/ -lpaysages_render_opengl
|
||||
else:unix: LIBS += -L$$OUT_PWD/../render/opengl/ -lpaysages_render_opengl
|
||||
INCLUDEPATH += $$PWD/../render/opengl
|
||||
DEPENDPATH += $$PWD/../render/opengl
|
||||
|
|
Loading…
Reference in a new issue