1
0
mirror of https://github.com/rwengine/openrw.git synced 2024-11-25 11:52:40 +01:00

Initial rendering refactor

This commit is contained in:
Daniel Evans 2014-08-22 14:29:46 +01:00
parent 4d78cacd84
commit 668848952b
13 changed files with 638 additions and 361 deletions

View File

@ -203,7 +203,7 @@ public:
/**
* The vehicle colour palettes
*/
std::vector<glm::vec3> vehicleColours;
std::vector<glm::u8vec3> vehicleColours;
/**
* The vehicle colours for each vehicle type

View File

@ -21,8 +21,8 @@ public:
VehicleDataHandle vehicle;
VehicleInfoHandle info;
glm::vec3 colourPrimary;
glm::vec3 colourSecondary;
glm::u8vec3 colourPrimary;
glm::u8vec3 colourSecondary;
std::map<size_t, GameObject*> seatOccupants;
@ -44,8 +44,8 @@ public:
ModelHandle* model,
VehicleDataHandle data,
VehicleInfoHandle info,
const glm::vec3& prim,
const glm::vec3& sec);
const glm::u8vec3& prim,
const glm::u8vec3& sec);
virtual ~VehicleObject();

View File

@ -8,6 +8,8 @@
#include <render/ViewCamera.hpp>
#include <render/OpenGLRenderer.hpp>
class Model;
class ModelFrame;
class GameWorld;
@ -24,6 +26,8 @@ class CutsceneObject;
class Animator;
class InventoryItem;
class Renderer;
/**
* @brief Implements high level drawing logic and low level draw commands
*
@ -35,13 +39,16 @@ class GameRenderer
/** Pointer to the world instance */
GameWorld* engine;
/** Data required to queue transparent objects for delayed rendering */
/** The low-level drawing interface to use */
Renderer* renderer;
/** Stores data for deferring transparent objects */
struct RQueueEntry {
Model* model;
size_t g;
size_t sg;
glm::mat4 matrix;
float opacity;
Renderer::DrawParameters dp;
GameObject* object;
};
@ -56,18 +63,6 @@ class GameRenderer
*/
bool renderFrame(Model* m, ModelFrame* f, const glm::mat4& matrix, GameObject* object, float opacity, bool queueTransparent = true);
/**
* @brief renders a model's subgeometry
* @param model
* @param g
* @param sg
* @param matrix
* @param object
* @param queueTransparent
* @return @see renderFrame(
*/
bool renderSubgeometry(Model* model, size_t g, size_t sg, const glm::mat4& matrix, float opacity, GameObject* object, bool queueTransparent = true);
/** Transparent objects are queued into this list */
std::vector<RQueueEntry> transparentDrawQueue;
@ -149,14 +144,10 @@ public:
size_t geoms;
/** @todo Clean up all these shader program and location variables */
GLuint worldProgram;
GLint uniTexture;
GLuint ubiScene, ubiObject;
GLuint uboScene, uboObject;
Renderer::ShaderProgram* worldProg;
Renderer::ShaderProgram* skyProg;
Renderer::ShaderProgram* waterProg;
GLuint skyProgram;
GLuint waterProgram, waterMVP, waterHeight, waterTexture, waterSize, waterTime, waterPosition, waterWave;
GLint skyUniView, skyUniProj, skyUniTop, skyUniBottom;
GLuint particleProgram;
GLuint ssRectProgram;
@ -165,6 +156,9 @@ public:
GLuint skydomeVBO, skydomeIBO, debugVBO;
GLuint debugTex;
DrawBuffer skyDbuff;
GeometryBuffer skyGbuff;
/**
* Renders the world using the parameters of the passed Camera.
* Note: The camera's near and far planes are overriden by weather effects.
@ -233,38 +227,6 @@ public:
/** Adds a particle to the rendering */
void addParticle(const FXParticle& particle);
static GLuint currentUBO;
/**
* Uploads data from T into the specified UBO
*/
template<class T> void uploadUBO(GLuint buffer, const T& data)
{
if( currentUBO != buffer ) {
glBindBuffer(GL_UNIFORM_BUFFER, buffer);
currentUBO = buffer;
}
glBufferData(GL_UNIFORM_BUFFER, sizeof(T), &data, GL_DYNAMIC_DRAW);
}
};
struct SceneUniformData {
glm::mat4 projection;
glm::mat4 view;
glm::vec4 ambient;
glm::vec4 dynamic;
glm::vec4 fogColour;
glm::vec4 campos;
float fogStart;
float fogEnd;
};
struct ObjectUniformData {
glm::mat4 model;
glm::vec4 colour;
float diffuse;
float ambient;
float visibility;
};
#endif

View File

@ -0,0 +1,169 @@
#pragma once
#ifndef _OPENGLRENDERER_HPP_
#define _OPENGLRENDERER_HPP_
#include <engine/RWTypes.hpp>
#include <render/DrawBuffer.hpp>
#include <render/GeometryBuffer.hpp>
typedef std::uint32_t RenderIndex;
struct VertexP3
{
glm::vec3 position;
static const AttributeList vertex_attributes() {
return {
{ATRS_Position, 3, sizeof(VertexP3), 0ul},
};
}
};
/// @todo normalize this to have the same interface as VertexP3
struct VertexP2 {
static const AttributeList vertex_attributes() {
return {
{ATRS_Position, 2, sizeof(VertexP2), 0ul}
};
}
float x, y;
};
class Renderer
{
public:
struct DrawParameters
{
GLuint texture; /// @todo replace with texture handle.
glm::u8vec4 colour;
float ambient;
float diffuse;
size_t count; /// The number of indicies to draw
unsigned int start; /// Start index.
};
struct ObjectUniformData {
glm::mat4 model;
glm::vec4 colour;
float diffuse;
float ambient;
float visibility;
};
struct SceneUniformData {
glm::mat4 projection;
glm::mat4 view;
glm::vec4 ambient;
glm::vec4 dynamic;
glm::vec4 fogColour;
glm::vec4 campos;
float fogStart;
float fogEnd;
};
class ShaderProgram {
// This just provides an opaque handle for external users.
};
virtual std::string getIDString() const = 0;
virtual ShaderProgram* createShader(const std::string& vert, const std::string& frag) = 0;
virtual void useProgram(ShaderProgram* p) = 0;
/// @todo dont use GLint in the interface.
virtual void setProgramBlockBinding(ShaderProgram* p, const std::string& name, GLint point) = 0;
virtual void setUniformTexture(ShaderProgram*p, const std::string& name, GLint tex) = 0;
virtual void setUniform(ShaderProgram*p, const std::string& name, const glm::vec4& v) = 0;
virtual void setUniform(ShaderProgram*p, const std::string& name, const glm::vec3& v) = 0;
virtual void setUniform(ShaderProgram*p, const std::string& name, const glm::vec2& v) = 0;
virtual void setUniform(ShaderProgram*p, const std::string& name, float f) = 0;
virtual void clear(const glm::vec4& colour, bool clearColour = true, bool clearDepth = true) = 0;
virtual void setSceneParameters(const SceneUniformData& data) = 0;
virtual void draw(const glm::mat4& model, DrawBuffer* draw, const DrawParameters& p) = 0;
virtual void drawArrays(const glm::mat4& model, DrawBuffer* draw, const DrawParameters& p) = 0;
};
class OpenGLRenderer : public Renderer
{
public:
class OpenGLShaderProgram : public ShaderProgram {
GLuint program;
std::map<std::string, GLint> uniforms;
public:
OpenGLShaderProgram(GLuint p)
: program(p)
{ }
GLuint getName() const { return program; }
GLint getUniformLocation(const std::string& name) {
auto c = uniforms.find(name.c_str());
GLint loc = -1;
if( c == uniforms.end() ) {
loc = glGetUniformLocation(program, name.c_str());
uniforms[name] = loc;
}
else {
loc = c->second;
}
return loc;
}
};
OpenGLRenderer();
std::string getIDString() const;
ShaderProgram* createShader(const std::string &vert, const std::string &frag);
void setProgramBlockBinding(ShaderProgram* p, const std::string &name, GLint point);
void setUniformTexture(ShaderProgram* p, const std::string &name, GLint tex);
void setUniform(ShaderProgram* p, const std::string& name, const glm::vec4& m);
void setUniform(ShaderProgram* p, const std::string& name, const glm::vec3& m);
void setUniform(ShaderProgram* p, const std::string& name, const glm::vec2& m);
void setUniform(ShaderProgram* p, const std::string& name, float f);
void useProgram(ShaderProgram* p);
void clear(const glm::vec4 &colour, bool clearColour, bool clearDepth);
void setSceneParameters(const SceneUniformData &data);
void draw(const glm::mat4& model, DrawBuffer* draw, const DrawParameters& p);
void drawArrays(const glm::mat4& model, DrawBuffer* draw, const DrawParameters& p);
private:
DrawBuffer* currentDbuff;
void useDrawBuffer(DrawBuffer* dbuff);
GLuint currentTexture;
void useTexture(GLuint tex);
OpenGLShaderProgram* currentProgram;
GLuint currentUBO;
template<class T> void uploadUBO(GLuint buffer, const T& data)
{
if( currentUBO != buffer ) {
glBindBuffer(GL_UNIFORM_BUFFER, buffer);
currentUBO = buffer;
}
glBufferData(GL_UNIFORM_BUFFER, sizeof(T), &data, GL_DYNAMIC_DRAW);
}
GLuint UBOObject;
GLuint UBOScene;
};
/// @todo remove these from here
GLuint compileShader(GLenum type, const char *source);
GLuint compileProgram(const char* vertex, const char* fragment);
#endif

View File

@ -280,10 +280,10 @@ void GameData::loadCarcols(const std::string& path)
std::stringstream ss(line);
if( std::getline(ss, r, ',') && std::getline(ss, g, ',') && std::getline(ss, b)) {
vehicleColours.push_back(glm::vec3(
atoi(r.c_str())/255.f,
atoi(g.c_str())/255.f,
atoi(b.c_str())/255.f
vehicleColours.push_back(glm::u8vec3(
atoi(r.c_str()),
atoi(g.c_str()),
atoi(b.c_str())
));
}
}

View File

@ -116,6 +116,7 @@ bool GameWorld::load()
void GameWorld::logInfo(const std::string& info)
{
log.push_back({LogEntry::Info, gameTime, info});
std::cout << info << std::endl;
}
void GameWorld::logError(const std::string& error)
@ -418,7 +419,7 @@ VehicleObject *GameWorld::createVehicle(const uint16_t id, const glm::vec3& pos,
gameData.loadTXD(vti->second->textureName + ".txd");
}
glm::vec3 prim = glm::vec3(1.f), sec = glm::vec3(0.5f);
glm::u8vec3 prim(255), sec(128);
auto palit = gameData.vehiclePalettes.find(vti->second->modelName); // modelname is conveniently lowercase (usually)
if(palit != gameData.vehiclePalettes.end() && palit->second.size() > 0 ) {
std::uniform_int_distribution<int> uniform(0, palit->second.size()-1);

View File

@ -246,6 +246,7 @@ void LoaderDFF::readGeometry(Model *model, const RWBStream &stream)
sizeof(uint32_t) * sg.numIndices,
sg.indices.data());
}
}
void LoaderDFF::readMaterialList(Model *model, const RWBStream &stream)

View File

@ -7,7 +7,7 @@
#include <render/Model.hpp>
#include <engine/Animator.hpp>
VehicleObject::VehicleObject(GameWorld* engine, const glm::vec3& pos, const glm::quat& rot, ModelHandle* model, VehicleDataHandle data, VehicleInfoHandle info, const glm::vec3& prim, const glm::vec3& sec)
VehicleObject::VehicleObject(GameWorld* engine, const glm::vec3& pos, const glm::quat& rot, ModelHandle* model, VehicleDataHandle data, VehicleInfoHandle info, const glm::u8vec3& prim, const glm::u8vec3& sec)
: GameObject(engine, pos, rot, model),
steerAngle(0.f), throttle(0.f), brake(0.f), handbrake(false),
vehicle(data), info(info), colourPrimary(prim),

View File

@ -23,8 +23,6 @@
#include <cmath>
#include <glm/gtc/type_ptr.hpp>
GLuint GameRenderer::currentUBO = 0;
const size_t skydomeSegments = 8, skydomeRows = 10;
struct WaterVertex {
@ -69,16 +67,6 @@ struct ParticleVert {
GeometryBuffer particleGeom;
DrawBuffer particleDraw;
struct VertexP2 {
static const AttributeList vertex_attributes() {
return {
{ATRS_Position, 2, sizeof(VertexP2), 0ul}
};
}
float x, y;
};
std::vector<VertexP2> sspaceRect = {
{-1.f, -1.f},
{ 1.f, -1.f},
@ -89,98 +77,18 @@ std::vector<VertexP2> sspaceRect = {
GeometryBuffer ssRectGeom;
DrawBuffer ssRectDraw;
GLuint compileShader(GLenum type, const char *source)
{
GLuint shader = glCreateShader(type);
glShaderSource(shader, 1, &source, NULL);
glCompileShader(shader);
GLint status;
glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
if( status != GL_TRUE ) {
std::cerr << "[OGL] Shader Compilation Failed" << std::endl;
}
GLint len;
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &len);
if( len > 1 ) {
GLchar *buffer = new GLchar[len];
glGetShaderInfoLog(shader, len, NULL, buffer);
GLint sourceLen;
glGetShaderiv(shader, GL_SHADER_SOURCE_LENGTH, &sourceLen);
GLchar *sourceBuff = new GLchar[sourceLen];
glGetShaderSource(shader, sourceLen, nullptr, sourceBuff);
std::cerr << "[OGL] Shader InfoLog(" << shader << "):\n" << buffer << "\nSource:\n" << sourceBuff << std::endl;
delete[] buffer;
delete[] sourceBuff;
}
if (status != GL_TRUE) {
exit(1);
}
return shader;
}
GLuint compileProgram(const char* vertex, const char* fragment)
{
GLuint vertexShader = compileShader(GL_VERTEX_SHADER, vertex);
GLuint fragmentShader = compileShader(GL_FRAGMENT_SHADER, fragment);
GLuint prog = glCreateProgram();
glAttachShader(prog, vertexShader);
glAttachShader(prog, fragmentShader);
glLinkProgram(prog);
GLint status;
glGetProgramiv(prog, GL_LINK_STATUS, &status);
if( status != GL_TRUE ) {
std::cerr << "[OGL] Program Link Failed" << std::endl;
}
GLint len;
glGetProgramiv(prog, GL_INFO_LOG_LENGTH, &len);
if( len > 1 ) {
GLchar *buffer = new GLchar[len];
glGetProgramInfoLog(prog, len, NULL, buffer);
std::cerr << "[OGL] Program InfoLog(" << prog << "):\n" << buffer << std::endl;
delete[] buffer;
}
if (status != GL_TRUE) {
exit(1);
}
glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);
return prog;
}
GameRenderer::GameRenderer(GameWorld* engine)
: engine(engine), _renderAlpha(0.f)
: engine(engine), renderer(new OpenGLRenderer), _renderAlpha(0.f)
{
worldProgram = compileProgram(GameShaders::WorldObject::VertexShader,
GameShaders::WorldObject::FragmentShader);
engine->logInfo("[DRAW] " + renderer->getIDString());
uniTexture = glGetUniformLocation(worldProgram, "texture");
ubiScene = glGetUniformBlockIndex(worldProgram, "SceneData");
ubiObject = glGetUniformBlockIndex(worldProgram, "ObjectData");
worldProg = renderer->createShader(
GameShaders::WorldObject::VertexShader,
GameShaders::WorldObject::FragmentShader);
glGenBuffers(1, &uboScene);
glGenBuffers(1, &uboObject);
glUniformBlockBinding(worldProgram, ubiScene, 1);
glUniformBlockBinding(worldProgram, ubiObject, 2);
glBindBufferBase(GL_UNIFORM_BUFFER, 1, uboScene);
glBindBufferBase(GL_UNIFORM_BUFFER, 2, uboObject);
renderer->setUniformTexture(worldProg, "texture", 0);
renderer->setProgramBlockBinding(worldProg, "SceneData", 1);
renderer->setProgramBlockBinding(worldProg, "ObjectData", 2);
particleProgram = compileProgram(GameShaders::WorldObject::VertexShader,
GameShaders::Particle::FragmentShader);
@ -189,27 +97,23 @@ GameRenderer::GameRenderer(GameWorld* engine)
ubiScene = glGetUniformBlockIndex(particleProgram, "SceneData");
ubiObject = glGetUniformBlockIndex(particleProgram, "ObjectData");*/
glUniformBlockBinding(particleProgram, ubiScene, 1);
glUniformBlockBinding(particleProgram, ubiObject, 2);
//glUniformBlockBinding(particleProgram, ubiScene, 1);
//glUniformBlockBinding(particleProgram, ubiObject, 2);
skyProgram = compileProgram(GameShaders::Sky::VertexShader,
GameShaders::Sky::FragmentShader);
skyProg = renderer->createShader(
GameShaders::Sky::VertexShader,
GameShaders::Sky::FragmentShader);
skyUniView = glGetUniformLocation(skyProgram, "view");
skyUniProj = glGetUniformLocation(skyProgram, "proj");
skyUniTop = glGetUniformLocation(skyProgram, "TopColor");
skyUniBottom = glGetUniformLocation(skyProgram, "BottomColor");
renderer->setProgramBlockBinding(skyProg, "SceneData", 1);
waterProgram = compileProgram(GameShaders::WaterHQ::VertexShader,
GameShaders::WaterHQ::FragmentShader);
waterProg = renderer->createShader(
GameShaders::WaterHQ::VertexShader,
GameShaders::WaterHQ::FragmentShader);
waterHeight = glGetUniformLocation(waterProgram, "height");
waterTexture = glGetUniformLocation(waterProgram, "texture");
waterSize = glGetUniformLocation(waterProgram, "size");
waterMVP = glGetUniformLocation(waterProgram, "MVP");
waterTime = glGetUniformLocation(waterProgram, "time");
waterPosition = glGetUniformLocation(waterProgram, "worldP");
waterWave = glGetUniformLocation(waterProgram, "waveParams");
renderer->setUniformTexture(waterProg, "texture", 0);
renderer->setProgramBlockBinding(waterProg, "SceneData", 1);
renderer->setProgramBlockBinding(waterProg, "ObjectData", 2);
glGenVertexArrays( 1, &vao );
@ -240,28 +144,29 @@ GameRenderer::GameRenderer(GameWorld* engine)
waterHQDraw.setFaceType(GL_TRIANGLES);
// And our skydome while we're at it.
glGenBuffers(1, &skydomeVBO);
glBindBuffer(GL_ARRAY_BUFFER, skydomeVBO);
// Create the skydome
size_t segments = skydomeSegments, rows = skydomeRows;
float R = 1.f/(float)(rows-1);
float S = 1.f/(float)(segments-1);
std::vector<glm::vec3> skydomeBuff;
skydomeBuff.resize(rows * segments);
std::vector<VertexP3> skydomeVerts;
skydomeVerts.resize(rows * segments);
for( size_t r = 0, i = 0; r < rows; ++r) {
for( size_t s = 0; s < segments; ++s) {
skydomeBuff[i++] = glm::vec3(
skydomeVerts[i++].position = glm::vec3(
cos(2.f * M_PI * s * S) * cos(M_PI_2 * r * R),
sin(2.f * M_PI * s * S) * cos(M_PI_2 * r * R),
sin(M_PI_2 * r * R)
);
}
}
glBufferData(GL_ARRAY_BUFFER, sizeof(skydomeBuff), skydomeBuff.data(), GL_STATIC_DRAW);
skyGbuff.uploadVertices(skydomeVerts);
skyDbuff.addGeometry(&skyGbuff);
skyDbuff.setFaceType(GL_TRIANGLES);
glGenBuffers(1, &skydomeIBO);
GLushort skydomeIndBuff[rows*segments*6];
GLuint skydomeIndBuff[rows*segments*6];
for( size_t r = 0, i = 0; r < (rows-1); ++r ) {
for( size_t s = 0; s < (segments-1); ++s ) {
skydomeIndBuff[i++] = r * segments + s;
@ -275,6 +180,8 @@ GameRenderer::GameRenderer(GameWorld* engine)
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, skydomeIBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(skydomeIndBuff), skydomeIndBuff, GL_STATIC_DRAW);
glBindVertexArray(0);
glGenBuffers(1, &debugVBO);
glGenTextures(1, &debugTex);
glGenVertexArrays(1, &debugVAO);
@ -341,33 +248,31 @@ void GameRenderer::renderWorld(const ViewCamera &camera, float alpha)
_camera.frustum.near = engine->state.cameraNear;
_camera.frustum.far = weather.farClipping;
glUseProgram(worldProgram);
auto view = _camera.getView();
auto proj = _camera.frustum.projection();
uploadUBO<SceneUniformData>(
uboScene,
{
proj,
view,
glm::vec4{ambient, 0.0f},
glm::vec4{dynamic, 0.0f},
glm::vec4(skyBottom, 1.f),
glm::vec4(camera.position, 0.f),
weather.fogStart,
camera.frustum.far
});
Renderer::SceneUniformData sceneParams {
proj,
view,
glm::vec4{ambient, 0.0f},
glm::vec4{dynamic, 0.0f},
glm::vec4(skyBottom, 1.f),
glm::vec4(camera.position, 0.f),
weather.fogStart,
camera.frustum.far
};
glClearColor(skyBottom.r, skyBottom.g, skyBottom.b, 1.f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
renderer->setSceneParameters(sceneParams);
renderer->clear(glm::vec4(skyBottom, 1.f));
_camera.frustum.update(proj * view);
rendered = culled = geoms = frames = 0;
renderer->useProgram(worldProg);
glActiveTexture(GL_TEXTURE0);
glUniform1i(uniTexture, 0);
for( GameObject* object : engine->objects ) {
switch(object->type()) {
@ -398,36 +303,36 @@ void GameRenderer::renderWorld(const ViewCamera &camera, float alpha)
it != transparentDrawQueue.end();
++it)
{
glBindVertexArray(it->model->geometries[it->g]->dbuff.getVAOName());
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, it->model->geometries[it->g]->EBO);
renderSubgeometry(it->model, it->g, it->sg, it->matrix, it->opacity, it->object, false);
renderer->draw(it->matrix, &it->model->geometries[it->g]->dbuff, it->dp);
}
transparentDrawQueue.clear();
// Draw the water.
glUseProgram( waterProgram );
// TODO: Add some kind of draw distance
renderer->useProgram( waterProg );
float blockLQSize = WATER_WORLD_SIZE/WATER_LQ_DATA_SIZE;
float blockHQSize = WATER_WORLD_SIZE/WATER_HQ_DATA_SIZE;
glm::vec2 waterOffset { -WATER_WORLD_SIZE/2.f, -WATER_WORLD_SIZE/2.f };
glUniform1i(waterTexture, 0);
glUniform2f(waterWave, WATER_SCALE, WATER_HEIGHT);
auto waterTex = engine->gameData.textures[{"water_old",""}];
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, waterTex.texName);
auto camposFlat = glm::vec2(camera.position);
glBindVertexArray( waterHQDraw.getVAOName() );
Renderer::DrawParameters wdp;
wdp.start = 0;
wdp.count = waterHQVerts.size();
wdp.texture = waterTex.texName;
renderer->useProgram(waterProg);
renderer->setSceneParameters(sceneParams);
// Draw High detail water
glUniform1f(waterSize, blockHQSize);
glUniform1f(waterTime, engine->gameTime);
renderer->setUniform(waterProg, "size", blockHQSize);
renderer->setUniform(waterProg, "time", engine->gameTime);
renderer->setUniform(waterProg, "waveParams", glm::vec2(WATER_SCALE, WATER_HEIGHT));
for( int x = 0; x < WATER_HQ_DATA_SIZE; x++ ) {
for( int y = 0; y < WATER_HQ_DATA_SIZE; y++ ) {
auto waterWS = waterOffset + glm::vec2(blockHQSize) * glm::vec2(x, y);
@ -441,18 +346,18 @@ void GameRenderer::renderWorld(const ViewCamera &camera, float alpha)
if( hI >= NO_WATER_INDEX ) continue;
float h = engine->gameData.waterHeights[hI];
glUniform1f(waterHeight, h);
auto MVP = proj * view;
glUniform2fv(waterPosition, 1, glm::value_ptr(waterWS));
glUniformMatrix4fv(waterMVP, 1, GL_FALSE, glm::value_ptr(MVP));
glDrawArrays(waterHQDraw.getFaceType(), 0, waterHQVerts.size());
glm::mat4 m;
m = glm::translate(m, glm::vec3(waterWS, h));
renderer->drawArrays(m, &waterHQDraw, wdp);
}
}
glBindVertexArray( waterLQDraw.getVAOName() );
glUniform2f(waterWave, 0.0f, 0.0f);
glUniform1f(waterSize, blockLQSize);
wdp.count = waterLQVerts.size();
renderer->setUniform(waterProg, "size", blockLQSize);
renderer->setUniform(waterProg, "waveParams", glm::vec2(0.f));
for( int x = 0; x < WATER_LQ_DATA_SIZE; x++ ) {
for( int y = 0; y < WATER_LQ_DATA_SIZE; y++ ) {
auto waterWS = waterOffset + glm::vec2(blockLQSize) * glm::vec2(x, y);
@ -467,28 +372,24 @@ void GameRenderer::renderWorld(const ViewCamera &camera, float alpha)
if( hI >= NO_WATER_INDEX ) continue;
float h = engine->gameData.waterHeights[hI];
glUniform1f(waterHeight, h);
auto MVP = proj * view;
glUniform2fv(waterPosition, 1, glm::value_ptr(waterWS));
glUniformMatrix4fv(waterMVP, 1, GL_FALSE, glm::value_ptr(MVP));
glDrawArrays(waterLQDraw.getFaceType(), 0, 4);
glm::mat4 m;
m = glm::translate(m, glm::vec3(waterWS, h));
renderer->drawArrays(m, &waterLQDraw, wdp);
}
}
glBindVertexArray( vao );
glUseProgram(skyProgram);
Renderer::DrawParameters dp;
dp.start = 0;
dp.count = skydomeSegments * skydomeRows * 6;
glBindBuffer(GL_ARRAY_BUFFER, skydomeVBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, skydomeIBO);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(0);
glUniformMatrix4fv(skyUniView, 1, GL_FALSE, glm::value_ptr(view));
glUniformMatrix4fv(skyUniProj, 1, GL_FALSE, glm::value_ptr(proj));
glUniform4f(skyUniTop, skyTop.r, skyTop.g, skyTop.b, 1.f);
glUniform4f(skyUniBottom, skyBottom.r, skyBottom.g, skyBottom.b, 1.f);
renderer->useProgram(skyProg);
renderer->setUniform(skyProg, "TopColor", glm::vec4(skyTop, 1.f));
renderer->setUniform(skyProg, "BottomColor", glm::vec4(skyBottom, 1.f));
glDrawElements(GL_TRIANGLES, skydomeSegments * skydomeRows * 6, GL_UNSIGNED_SHORT, NULL);
renderer->draw(glm::mat4(), &skyDbuff, dp);
renderParticles();
@ -871,18 +772,70 @@ void GameRenderer::renderItem(InventoryItem *item, const glm::mat4 &modelMatrix)
void GameRenderer::renderGeometry(Model* model, size_t g, const glm::mat4& modelMatrix, float opacity, GameObject* object)
{
geoms++;
glBindVertexArray(model->geometries[g]->dbuff.getVAOName());
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, model->geometries[g]->EBO);
for(size_t sg = 0; sg < model->geometries[g]->subgeom.size(); ++sg)
{
if(opacity < 1.f || ! renderSubgeometry(model, g, sg, modelMatrix, opacity, object)) {
// If rendering was rejected, queue for later.
Model::SubGeometry& subgeom = model->geometries[g]->subgeom[sg];
bool abortTransparent = false;
Renderer::DrawParameters dp;
dp.colour = {255, 255, 255, 255};
dp.count = subgeom.numIndices;
dp.start = subgeom.start;
dp.texture = 0;
if (model->geometries[g]->materials.size() > subgeom.material) {
Model::Material& mat = model->geometries[g]->materials[subgeom.material];
if(mat.textures.size() > 0 ) {
auto& tC = mat.textures[0].name;
auto& tA = mat.textures[0].alphaName;
auto t = engine->gameData.textures.find({tC, tA});
if(t != engine->gameData.textures.end()) {
TextureInfo& tex = t->second;
if(tex.transparent) {
abortTransparent = true;
}
dp.texture = tex.texName;
}
}
if( (model->geometries[g]->flags & RW::BSGeometry::ModuleMaterialColor) == RW::BSGeometry::ModuleMaterialColor) {
dp.colour = mat.colour;
if( object && object->type() == GameObject::Vehicle ) {
auto vehicle = static_cast<VehicleObject*>(object);
if( dp.colour.r == 60 && dp.colour.g == 255 && dp.colour.b == 0 ) {
dp.colour = glm::u8vec4(vehicle->colourPrimary, 255);
}
else if( dp.colour.r == 255 && dp.colour.g == 0 && dp.colour.b == 175 ) {
dp.colour = glm::u8vec4(vehicle->colourSecondary, 255);
}
}
}
dp.colour.a *= opacity;
if( dp.colour.a < 255 ) {
abortTransparent = true;
}
dp.diffuse = mat.diffuseIntensity;
dp.ambient = mat.ambientIntensity;
}
rendered++;
if( abortTransparent ) {
transparentDrawQueue.push_back(
{model, g, sg, modelMatrix, opacity, object}
{model, g, sg, modelMatrix, dp, object}
);
}
else {
renderer->draw(modelMatrix, &model->geometries[g]->dbuff, dp);
}
}
}
@ -943,12 +896,12 @@ void GameRenderer::renderParticles()
m[3][2] =-glm::dot(u, p);
m = glm::scale(glm::inverse(m), glm::vec3(part.size, 1.f));
uploadUBO<ObjectUniformData>(
/*uploadUBO<ObjectUniformData>(
uboObject, {
m,
part.colour,
1.f, 1.f, 1.f
});
});*/
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
}
@ -963,6 +916,7 @@ bool GameRenderer::renderFrame(Model* m, ModelFrame* f, const glm::mat4& matrix,
{
frames++;
auto localmatrix = matrix;
bool vis = true;
if(object && object->animator) {
bool animFixed = false;
@ -970,26 +924,26 @@ bool GameRenderer::renderFrame(Model* m, ModelFrame* f, const glm::mat4& matrix,
animFixed = static_cast<CharacterObject*>(object)->isAnimationFixed();
}
localmatrix *= object->animator->getFrameMatrix(f, _renderAlpha, animFixed);
vis = object->animator->getFrameVisibility(f);
}
else {
localmatrix *= f->getTransform();
}
bool vis = (object == nullptr || object->animator == nullptr) ||
object->animator->getFrameVisibility(f);
if( vis ) {
for(size_t g : f->getGeometries()) {
RW::BSGeometryBounds& bounds = m->geometries[g]->geometryBounds;
/// @todo fix culling animating objects?
for(size_t g : f->getGeometries()) {
if(!vis ) continue;
glm::vec3 boundpos = bounds.center + glm::vec3(matrix[3]);
if(! _camera.frustum.intersects(boundpos, bounds.radius)) {
culled++;
continue;
}
RW::BSGeometryBounds& bounds = m->geometries[g]->geometryBounds;
/// @todo fix culling animating objects?
glm::vec3 boundpos = bounds.center + glm::vec3(matrix[3]);
if( (!object || !object->animator) && ! _camera.frustum.intersects(boundpos, bounds.radius)) {
continue;
renderGeometry(m, g, localmatrix, opacity, object);
}
renderGeometry(m, g, localmatrix, opacity, object);
}
for(ModelFrame* c : f->getChildren()) {
@ -998,78 +952,6 @@ bool GameRenderer::renderFrame(Model* m, ModelFrame* f, const glm::mat4& matrix,
return true;
}
bool GameRenderer::renderSubgeometry(Model* model, size_t g, size_t sg, const glm::mat4& matrix, float opacity, GameObject* object, bool queueTransparent)
{
auto& subgeom = model->geometries[g]->subgeom[sg];
/*
* model matrix,
* material diffuse
* material ambient
* materialcolour
*/
ObjectUniformData oudata {
matrix,
glm::vec4(1.f),
1.f, 1.f, opacity
};
if (model->geometries[g]->materials.size() > subgeom.material) {
Model::Material& mat = model->geometries[g]->materials[subgeom.material];
if(mat.textures.size() > 0 ) {
auto& tC = mat.textures[0].name;
auto& tA = mat.textures[0].alphaName;
auto t = engine->gameData.textures.find({tC, tA});
if(t != engine->gameData.textures.end()) {
TextureInfo& tex = t->second;
if(tex.transparent && queueTransparent) {
return false;
}
glBindTexture(GL_TEXTURE_2D, tex.texName);
}
else {
// Texture pair is missing?
}
}
else {
glBindTexture(GL_TEXTURE_2D, 0);
}
if( (model->geometries[g]->flags & RW::BSGeometry::ModuleMaterialColor) == RW::BSGeometry::ModuleMaterialColor) {
auto col = mat.colour;
if(col.a < 255 && queueTransparent) return false;
if( object && object->type() == GameObject::Vehicle ) {
auto vehicle = static_cast<VehicleObject*>(object);
if( col.r == 60 && col.g == 255 && col.b == 0 ) {
oudata.colour = glm::vec4(vehicle->colourPrimary, 1.f);
}
else if( col.r == 255 && col.g == 0 && col.b == 175 ) {
oudata.colour = glm::vec4(vehicle->colourSecondary, 1.f);
}
else {
oudata.colour = {col.r/255.f, col.g/255.f, col.b/255.f, col.a/255.f};
}
}
else {
oudata.colour = {col.r/255.f, col.g/255.f, col.b/255.f, col.a/255.f};
}
}
oudata.diffuse = mat.diffuseIntensity;
oudata.ambient = mat.ambientIntensity;
}
uploadUBO(uboObject, oudata);
rendered++;
glDrawElements(model->geometries[g]->dbuff.getFaceType(),
subgeom.numIndices, GL_UNSIGNED_INT, (void*)(sizeof(uint32_t) * subgeom.start));
return true;
}
void GameRenderer::renderModel(Model* model, const glm::mat4& modelMatrix, GameObject* object, Animator *animator)
{
renderFrame(model, model->frames[model->rootFrameIdx], modelMatrix, object, 1.f);
@ -1077,7 +959,7 @@ void GameRenderer::renderModel(Model* model, const glm::mat4& modelMatrix, GameO
void GameRenderer::renderPaths()
{
glActiveTexture(GL_TEXTURE0);
/*glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, debugTex);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
@ -1152,7 +1034,7 @@ void GameRenderer::renderPaths()
pedlines.clear();
carlines.clear();
glBindVertexArray( 0 );
glBindVertexArray( 0 );*/
}
void GameRenderer::renderLetterbox()

View File

@ -9,18 +9,38 @@ const char* WaterHQ::VertexShader = R"(
layout(location = 0) in vec2 position;
out vec2 TexCoords;
uniform float height;
layout(std140) uniform SceneData {
mat4 projection;
mat4 view;
vec4 ambient;
vec4 dynamic;
vec4 fogColor;
vec4 campos;
float fogStart;
float fogEnd;
};
layout(std140) uniform ObjectData {
mat4 model;
vec4 colour;
float diffusefac;
float ambientfac;
float visibility;
};
uniform float size;
uniform mat4 MVP;
uniform float time;
uniform vec2 worldP;
uniform vec2 waveParams;
void main()
{
vec2 p = worldP + position * size;
float waveHeight = (1.0+sin(time + (p.x + p.y) * waveParams.x)) * waveParams.y;
mat4 MVP = projection * view;
vec4 vp = model * vec4(position * size, 0.0, 1.0);
vp.z = (1.0+sin(time + (vp.x + vp.y) * waveParams.x)) * waveParams.y;
TexCoords = position * 2.0;
gl_Position = MVP * vec4(p, height + waveHeight, 1.0);
gl_Position = MVP * vp;
})";
const char* WaterHQ::FragmentShader = R"(
@ -36,14 +56,26 @@ void main() {
const char* Sky::VertexShader = R"(
#version 130
in vec3 position;
uniform mat4 view;
uniform mat4 proj;
#extension GL_ARB_explicit_attrib_location : enable
#extension GL_ARB_uniform_buffer_object : enable
layout(std140) uniform SceneData {
mat4 projection;
mat4 view;
vec4 ambient;
vec4 dynamic;
vec4 fogColor;
vec4 campos;
float fogStart;
float fogEnd;
};
layout(location = 0) in vec3 position;
out vec3 Position;
uniform float Far;
void main() {
Position = position;
vec4 viewsp = proj * mat4(mat3(view)) * vec4(position, 1.0);
vec4 viewsp = projection * mat4(mat3(view)) * vec4(position, 1.0);
viewsp.z = viewsp.w - 0.000001;
gl_Position = viewsp;
})";
@ -67,7 +99,6 @@ const char* WorldObject::VertexShader = R"(
#version 130
#extension GL_ARB_explicit_attrib_location : enable
#extension GL_ARB_uniform_buffer_object : enable
#extension GL_ARB_gpu_shader5 : enable
layout(location = 0) in vec3 position;
layout(location = 1) in vec3 normal;
layout(location = 2) in vec4 _colour;

View File

@ -0,0 +1,231 @@
#include <render/OpenGLRenderer.hpp>
#include <GL/glew.h>
#include <glm/gtc/type_ptr.hpp>
#include <sstream>
#include <iostream>
GLuint compileShader(GLenum type, const char *source)
{
GLuint shader = glCreateShader(type);
glShaderSource(shader, 1, &source, NULL);
glCompileShader(shader);
GLint status;
glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
if( status != GL_TRUE ) {
std::cerr << "[OGL] Shader Compilation Failed" << std::endl;
}
GLint len;
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &len);
if( len > 1 ) {
GLchar *buffer = new GLchar[len];
glGetShaderInfoLog(shader, len, NULL, buffer);
GLint sourceLen;
glGetShaderiv(shader, GL_SHADER_SOURCE_LENGTH, &sourceLen);
GLchar *sourceBuff = new GLchar[sourceLen];
glGetShaderSource(shader, sourceLen, nullptr, sourceBuff);
std::cerr << "[OGL] Shader InfoLog(" << shader << "):\n" << buffer << "\nSource:\n" << sourceBuff << std::endl;
delete[] buffer;
delete[] sourceBuff;
}
if (status != GL_TRUE) {
exit(1);
}
return shader;
}
GLuint compileProgram(const char* vertex, const char* fragment)
{
GLuint vertexShader = compileShader(GL_VERTEX_SHADER, vertex);
GLuint fragmentShader = compileShader(GL_FRAGMENT_SHADER, fragment);
GLuint prog = glCreateProgram();
glAttachShader(prog, vertexShader);
glAttachShader(prog, fragmentShader);
glLinkProgram(prog);
GLint status;
glGetProgramiv(prog, GL_LINK_STATUS, &status);
if( status != GL_TRUE ) {
std::cerr << "[OGL] Program Link Failed" << std::endl;
}
GLint len;
glGetProgramiv(prog, GL_INFO_LOG_LENGTH, &len);
if( len > 1 ) {
GLchar *buffer = new GLchar[len];
glGetProgramInfoLog(prog, len, NULL, buffer);
std::cerr << "[OGL] Program InfoLog(" << prog << "):\n" << buffer << std::endl;
delete[] buffer;
}
if (status != GL_TRUE) {
exit(1);
}
glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);
return prog;
}
void OpenGLRenderer::useDrawBuffer(DrawBuffer* dbuff)
{
if( dbuff != currentDbuff )
{
glBindVertexArray(dbuff->getVAOName());
currentDbuff = dbuff;
}
}
void OpenGLRenderer::useTexture(GLuint tex)
{
if( tex != currentTexture )
{
glBindTexture(GL_TEXTURE_2D, tex);
currentTexture = tex;
}
}
void OpenGLRenderer::useProgram(Renderer::ShaderProgram* p)
{
if( p != currentProgram )
{
currentProgram = static_cast<OpenGLShaderProgram*>(p);
glUseProgram( currentProgram->getName() );
}
}
OpenGLRenderer::OpenGLRenderer()
: currentDbuff(nullptr), currentTexture(0), currentProgram(nullptr)
{
glGenBuffers(1, &UBOScene);
glGenBuffers(1, &UBOObject);
glBindBufferBase(GL_UNIFORM_BUFFER, 1, UBOScene);
glBindBufferBase(GL_UNIFORM_BUFFER, 2, UBOObject);
}
std::string OpenGLRenderer::getIDString() const
{
std::stringstream ss;
ss << "OpenGL Renderer";
ss << " Version: " << glGetString(GL_VERSION);
ss << " (GLSL " << glGetString(GL_SHADING_LANGUAGE_VERSION) << ")";
ss << " Vendor: " << glGetString(GL_VENDOR);
return ss.str();
}
Renderer::ShaderProgram* OpenGLRenderer::createShader(const std::string& vert, const std::string& frag)
{
return new OpenGLShaderProgram(
compileProgram(vert.c_str(), frag.c_str()));
}
void OpenGLRenderer::setProgramBlockBinding(Renderer::ShaderProgram* p, const std::string& name, GLint point)
{
OpenGLShaderProgram* glsh = static_cast<OpenGLShaderProgram*>(p);
auto ubi = glGetUniformBlockIndex(glsh->getName(), name.c_str());
glUniformBlockBinding(glsh->getName(), ubi, point);
}
void OpenGLRenderer::setUniformTexture(Renderer::ShaderProgram* p, const std::string& name, GLint tex)
{
useProgram(p);
glUniform1i(currentProgram->getUniformLocation(name), tex);
}
void OpenGLRenderer::setUniform(Renderer::ShaderProgram* p, const std::string& name, const glm::vec4& m)
{
useProgram(p);
glUniform4fv(currentProgram->getUniformLocation(name.c_str()), 1, glm::value_ptr(m));
}
void OpenGLRenderer::setUniform(Renderer::ShaderProgram* p, const std::string& name, const glm::vec3& m)
{
useProgram(p);
glUniform3fv(currentProgram->getUniformLocation(name.c_str()), 1, glm::value_ptr(m));
}
void OpenGLRenderer::setUniform(Renderer::ShaderProgram* p, const std::string& name, const glm::vec2& m)
{
useProgram(p);
glUniform2fv(currentProgram->getUniformLocation(name.c_str()), 1, glm::value_ptr(m));
}
void OpenGLRenderer::setUniform(Renderer::ShaderProgram* p, const std::string& name, float f)
{
glUniform1fv(currentProgram->getUniformLocation(name.c_str()), 1, &f);
}
void OpenGLRenderer::clear(const glm::vec4& colour, bool clearColour, bool clearDepth)
{
auto flags = 0;
if( clearColour ) {
flags |= GL_COLOR_BUFFER_BIT;
glClearColor(colour.r, colour.g, colour.b, colour.a);
}
if( clearDepth ) {
flags |= GL_DEPTH_BUFFER_BIT;
}
glClear(flags);
}
void OpenGLRenderer::setSceneParameters(const Renderer::SceneUniformData& data)
{
uploadUBO(UBOScene, data);
}
void OpenGLRenderer::draw(const glm::mat4& model, DrawBuffer* draw, const Renderer::DrawParameters& p)
{
useDrawBuffer(draw);
useTexture(p.texture);
ObjectUniformData oudata {
model,
glm::vec4(p.colour.r/255.f, p.colour.g/255.f, p.colour.b/255.f, 1.f),
1.f,
1.f,
p.colour.a/255.f
};
uploadUBO(UBOObject, oudata);
glDrawElements(draw->getFaceType(), p.count, GL_UNSIGNED_INT,
(void*) (sizeof(RenderIndex) * p.start));
}
void OpenGLRenderer::drawArrays(const glm::mat4& model, DrawBuffer* draw, const Renderer::DrawParameters& p)
{
useDrawBuffer(draw);
useTexture(p.texture);
ObjectUniformData oudata {
model,
glm::vec4(p.colour.r/255.f, p.colour.g/255.f, p.colour.b/255.f, 1.f),
1.f,
1.f,
p.colour.a/255.f
};
uploadUBO(UBOObject, oudata);
glDrawArrays(draw->getFaceType(), p.start, p.count);
}

View File

@ -185,7 +185,7 @@ void init(std::string gtapath)
gta->gameTime = 0.f;
debugDrawer = new DebugDraw;
debugDrawer->setShaderProgram(gta->renderer.worldProgram);
//debugDrawer->setShaderProgram(gta->renderer.worldProgram);
debugDrawer->setDebugMode(btIDebugDraw::DBG_DrawWireframe);
gta->dynamicsWorld->setDebugDrawer(debugDrawer);
@ -302,24 +302,24 @@ void render(float alpha)
case 0: break;
case 1: {
glUseProgram(gta->renderer.worldProgram);
gta->renderer.uploadUBO<ObjectUniformData>(
//glUseProgram(gta->renderer.worldProgram);
/*gta->renderer.uploadUBO<ObjectUniformData>(
gta->renderer.uboObject, {
glm::mat4(),
glm::vec4(1.f),
1.f, 1.f
});
});*/
gta->renderer.renderPaths();
break;
}
case 2: {
glUseProgram(gta->renderer.worldProgram);
gta->renderer.uploadUBO<ObjectUniformData>(
//glUseProgram(gta->renderer.worldProgram);
/*gta->renderer.uploadUBO<ObjectUniformData>(
gta->renderer.uboObject, {
glm::mat4(),
glm::vec4(1.f),
1.f, 1.f
});
});*/
gta->dynamicsWorld->debugDrawWorld();
debugDrawer->drawAllLines();

View File

@ -84,7 +84,7 @@ void ViewerWidget::paintGL()
glm::mat4 m;
glUseProgram(r.worldProgram);
//glUseProgram(r.worldProgram);
ViewCamera vc;
@ -97,8 +97,8 @@ void ViewerWidget::paintGL()
glm::vec3 eye(sin(viewAngles.x) * cos(viewAngles.y), cos(viewAngles.x) * cos(viewAngles.y), sin(viewAngles.y));
glm::mat4 view = glm::lookAt(eye * viewDistance, glm::vec3(0.f, 0.f, 0.f), glm::vec3(0.f, 0.f, 1.f));
r.uploadUBO<SceneUniformData>(r.uboScene,
{ proj, view, glm::vec4(1.f), glm::vec4(1.f), glm::vec4(1.f), glm::vec4(0.f), 90.f, vc.frustum.far });
//r.uploadUBO<SceneUniformData>(r.uboScene,
//{ proj, view, glm::vec4(1.f), glm::vec4(1.f), glm::vec4(1.f), glm::vec4(0.f), 90.f, vc.frustum.far });
if( dummyObject->model->model ) {
gworld->renderer.renderModel(dummyObject->model->model, m, dummyObject);