1
0
mirror of https://github.com/rwengine/openrw.git synced 2024-09-15 06:52:34 +02:00

clang-format files in rwengine/src/render

This commit is contained in:
Daniel Evans 2016-09-09 21:13:20 +01:00
parent 1e4d7ea133
commit e888d04303
20 changed files with 2763 additions and 2965 deletions

View File

@ -6,108 +6,93 @@
#include <iostream>
DebugDraw::DebugDraw()
: shaderProgram(nullptr)
{
lineBuff = new GeometryBuffer;
dbuff = new DrawBuffer;
dbuff->setFaceType(GL_LINES);
DebugDraw::DebugDraw() : shaderProgram(nullptr) {
lineBuff = new GeometryBuffer;
dbuff = new DrawBuffer;
dbuff->setFaceType(GL_LINES);
glGenTextures(1, &texture);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture);
int img = 0xFFFFFFFF;
glTexImage2D(
GL_TEXTURE_2D, 0, GL_RGBA, 1, 1,
0, GL_RGBA, GL_UNSIGNED_BYTE, &img
);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture);
int img = 0xFFFFFFFF;
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE,
&img);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
maxlines = 0;
}
DebugDraw::~DebugDraw()
{
delete dbuff;
delete lineBuff;
DebugDraw::~DebugDraw() {
delete dbuff;
delete lineBuff;
}
void DebugDraw::drawLine(const btVector3 &from, const btVector3 &to, const btVector3 &color)
{
btVector3 c = color * 255;
lines.push_back({
glm::vec3(from.getX(), from.getY(), from.getZ()),
glm::vec3(0.f),
glm::vec2(0.f),
glm::u8vec4(c.getX(), c.getY(), c.getZ(), 255)
});
lines.push_back({
glm::vec3(to.getX(), to.getY(), to.getZ()),
glm::vec3(0.f),
glm::vec2(0.f),
glm::u8vec4(c.getX(), c.getY(), c.getZ(), 255)
});
void DebugDraw::drawLine(const btVector3 &from, const btVector3 &to,
const btVector3 &color) {
btVector3 c = color * 255;
lines.push_back({glm::vec3(from.getX(), from.getY(), from.getZ()),
glm::vec3(0.f), glm::vec2(0.f),
glm::u8vec4(c.getX(), c.getY(), c.getZ(), 255)});
lines.push_back({glm::vec3(to.getX(), to.getY(), to.getZ()), glm::vec3(0.f),
glm::vec2(0.f),
glm::u8vec4(c.getX(), c.getY(), c.getZ(), 255)});
}
void DebugDraw::drawContactPoint(const btVector3 &pointOnB, const btVector3 &normalOnB, btScalar distance, int lifeTime, const btVector3 &color)
{
RW_UNUSED(pointOnB);
RW_UNUSED(normalOnB);
RW_UNUSED(distance);
RW_UNUSED(lifeTime);
RW_UNUSED(color);
void DebugDraw::drawContactPoint(const btVector3 &pointOnB,
const btVector3 &normalOnB, btScalar distance,
int lifeTime, const btVector3 &color) {
RW_UNUSED(pointOnB);
RW_UNUSED(normalOnB);
RW_UNUSED(distance);
RW_UNUSED(lifeTime);
RW_UNUSED(color);
}
void DebugDraw::flush(GameRenderer* renderer)
{
if(lines.size() == 0) {
return;
}
renderer->getRenderer()->useProgram(shaderProgram);
lineBuff->uploadVertices(lines);
dbuff->addGeometry(lineBuff);
void DebugDraw::flush(GameRenderer *renderer) {
if (lines.size() == 0) {
return;
}
Renderer::DrawParameters dp;
dp.textures = {texture};
dp.ambient = 1.f;
dp.colour = glm::u8vec4(255, 255, 255, 255);
dp.start = 0;
dp.count = lines.size();
dp.diffuse = 1.f;
renderer->getRenderer()->drawArrays(glm::mat4(1.f), dbuff, dp);
renderer->getRenderer()->invalidate();
glUseProgram(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glBindVertexArray( 0 );
renderer->getRenderer()->useProgram(shaderProgram);
lines.clear();
lineBuff->uploadVertices(lines);
dbuff->addGeometry(lineBuff);
Renderer::DrawParameters dp;
dp.textures = {texture};
dp.ambient = 1.f;
dp.colour = glm::u8vec4(255, 255, 255, 255);
dp.start = 0;
dp.count = lines.size();
dp.diffuse = 1.f;
renderer->getRenderer()->drawArrays(glm::mat4(1.f), dbuff, dp);
renderer->getRenderer()->invalidate();
glUseProgram(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glBindVertexArray(0);
lines.clear();
}
void DebugDraw::reportErrorWarning(const char *warningString)
{
std::cerr << warningString << std::endl;
void DebugDraw::reportErrorWarning(const char *warningString) {
std::cerr << warningString << std::endl;
}
void DebugDraw::draw3dText(const btVector3 &location, const char *textString)
{
RW_UNUSED(location);
std::cout << textString << std::endl;
void DebugDraw::draw3dText(const btVector3 &location, const char *textString) {
RW_UNUSED(location);
std::cout << textString << std::endl;
}
void DebugDraw::setDebugMode(int debugMode)
{
this->debugMode = debugMode;
void DebugDraw::setDebugMode(int debugMode) {
this->debugMode = debugMode;
}
int DebugDraw::getDebugMode() const
{
return debugMode;
int DebugDraw::getDebugMode() const {
return debugMode;
}

View File

@ -1,37 +1,39 @@
#pragma once
#include <LinearMath/btIDebugDraw.h>
#include <render/GameRenderer.hpp>
#include <data/Model.hpp>
#include <render/GameRenderer.hpp>
class DebugDraw : public btIDebugDraw
{
class DebugDraw : public btIDebugDraw {
public:
DebugDraw();
~DebugDraw();
DebugDraw();
~DebugDraw();
void drawLine(const btVector3 &from, const btVector3 &to, const btVector3 &color);
void drawContactPoint(const btVector3 &pointOnB, const btVector3 &normalOnB, btScalar distance, int lifeTime, const btVector3 &color);
void reportErrorWarning(const char *warningString);
void draw3dText(const btVector3 &location, const char *textString);
void setDebugMode(int debugMode);
int getDebugMode() const;
void drawLine(const btVector3 &from, const btVector3 &to,
const btVector3 &color);
void drawContactPoint(const btVector3 &pointOnB, const btVector3 &normalOnB,
btScalar distance, int lifeTime,
const btVector3 &color);
void reportErrorWarning(const char *warningString);
void draw3dText(const btVector3 &location, const char *textString);
void setDebugMode(int debugMode);
int getDebugMode() const;
void flush(GameRenderer* renderer);
void flush(GameRenderer *renderer);
void setShaderProgram(Renderer::ShaderProgram* shaderProgram) {
this->shaderProgram = shaderProgram;
}
void setShaderProgram(Renderer::ShaderProgram *shaderProgram) {
this->shaderProgram = shaderProgram;
}
protected:
int debugMode;
int debugMode;
std::vector<Model::GeometryVertex> lines;
size_t maxlines;
GeometryBuffer* lineBuff;
DrawBuffer* dbuff;
std::vector<Model::GeometryVertex> lines;
size_t maxlines;
GeometryBuffer *lineBuff;
DrawBuffer *dbuff;
Renderer::ShaderProgram* shaderProgram;
Renderer::ShaderProgram *shaderProgram;
GLuint texture;
GLuint texture;
};

File diff suppressed because it is too large Load Diff

View File

@ -42,155 +42,160 @@ class Renderer;
* Rendering of object types is handled by drawWorld, calling the respective
* render function for each object.
*/
class GameRenderer
{
/** Game data to use for rendering */
GameData* data;
class GameRenderer {
/** Game data to use for rendering */
GameData* data;
/** Logger to output messages */
Logger* logger;
/** Logger to output messages */
Logger* logger;
/** 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;
Renderer::DrawParameters dp;
GameObject* object;
};
/**
* @brief renders a model's frame.
* @param m
* @param f
* @param matrix
* @param object
* @param queueTransparent abort the draw if the frame contains transparent materials
* @return True if the frame was drawn, false if it should be queued
*/
bool renderFrame(Model* m, ModelFrame* f, const glm::mat4& matrix, GameObject* object, float opacity, bool queueTransparent = true);
/** The low-level drawing interface to use */
Renderer* renderer;
// Temporary variables used during rendering
float _renderAlpha;
GameWorld* _renderWorld;
/** Internal non-descript VAOs */
GLuint vao, debugVAO;
/** Camera values passed to renderWorld() */
ViewCamera _camera;
ViewCamera cullingCamera;
bool cullOverride;
GLuint framebufferName;
GLuint fbTextures[2];
GLuint fbRenderBuffers[1];
Renderer::ShaderProgram* postProg;
/// Texture used to replace textures missing from the data
GLuint m_missingTexture;
public:
GameRenderer(Logger* log, GameData* data);
~GameRenderer();
/** Number of culling events */
size_t culled;
/** @todo Clean up all these shader program and location variables */
Renderer::ShaderProgram* worldProg;
Renderer::ShaderProgram* skyProg;
Renderer::ShaderProgram* particleProg;
GLuint ssRectProgram;
GLint ssRectTexture, ssRectColour, ssRectSize, ssRectOffset;
GLuint skydomeVBO, skydomeIBO, debugVBO;
GLuint debugTex;
DrawBuffer skyDbuff;
GeometryBuffer skyGbuff;
DrawBuffer cylinderBuffer;
GeometryBuffer cylinderGeometry;
GameData* getData() const { return data; }
GLuint getMissingTexture() const { return m_missingTexture; }
/** Stores data for deferring transparent objects */
struct RQueueEntry {
Model* model;
size_t g;
size_t sg;
glm::mat4 matrix;
Renderer::DrawParameters dp;
GameObject* object;
};
/**
* Renders the world using the parameters of the passed Camera.
* Note: The camera's near and far planes are overriden by weather effects.
*
* - draws all objects (instances, vehicles etc.)
* - draws particles
* - draws water surfaces
* - draws the skybox
* @brief renders a model's frame.
* @param m
* @param f
* @param matrix
* @param object
* @param queueTransparent abort the draw if the frame contains transparent
* materials
* @return True if the frame was drawn, false if it should be queued
*/
void renderWorld(GameWorld* world, const ViewCamera &camera, float alpha);
/**
* Renders the effects (Particles, Lighttrails etc)
*/
void renderEffects(GameWorld* world);
bool renderFrame(Model* m, ModelFrame* f, const glm::mat4& matrix,
GameObject* object, float opacity,
bool queueTransparent = true);
/**
* @brief Draws the current on screen text.
*/
void drawOnScreenText();
// Temporary variables used during rendering
float _renderAlpha;
GameWorld* _renderWorld;
/**
* @brief Draws a texture on the screen
*/
void drawTexture(TextureData* texture, glm::vec4 extents);
void drawColour(const glm::vec4& colour, glm::vec4 extents);
/** Internal non-descript VAOs */
GLuint vao, debugVAO;
/**
* Renders a model (who'd have thought)
*/
void renderModel(Model*, const glm::mat4& modelMatrix, GameObject* = nullptr);
/** Camera values passed to renderWorld() */
ViewCamera _camera;
ViewCamera cullingCamera;
bool cullOverride;
void renderGeometry(Model*, size_t geom, const glm::mat4& modelMatrix, float opacity, GameObject* = nullptr);
/** Renders the area indicator */
void renderAreaIndicator(const AreaIndicatorInfo* info);
GLuint framebufferName;
GLuint fbTextures[2];
GLuint fbRenderBuffers[1];
Renderer::ShaderProgram* postProg;
/** method for rendering AI debug information */
void renderPaths();
/// Texture used to replace textures missing from the data
GLuint m_missingTexture;
/** Increases cinematic value */
void renderLetterbox();
public:
GameRenderer(Logger* log, GameData* data);
~GameRenderer();
void setupRender();
void renderPostProcess();
/** Number of culling events */
size_t culled;
Renderer* getRenderer()
{
return renderer;
}
void setViewport(int w, int h);
/** @todo Clean up all these shader program and location variables */
Renderer::ShaderProgram* worldProg;
Renderer::ShaderProgram* skyProg;
Renderer::ShaderProgram* particleProg;
void setCullOverride(bool override, const ViewCamera& cullCamera)
{
cullingCamera = cullCamera;
cullOverride = override;
}
MapRenderer map;
WaterRenderer water;
TextRenderer text;
GLuint ssRectProgram;
GLint ssRectTexture, ssRectColour, ssRectSize, ssRectOffset;
// Profiling data
Renderer::ProfileInfo profObjects;
Renderer::ProfileInfo profSky;
Renderer::ProfileInfo profWater;
Renderer::ProfileInfo profEffects;
GLuint skydomeVBO, skydomeIBO, debugVBO;
GLuint debugTex;
DrawBuffer skyDbuff;
GeometryBuffer skyGbuff;
DrawBuffer cylinderBuffer;
GeometryBuffer cylinderGeometry;
GameData* getData() const {
return data;
}
GLuint getMissingTexture() const {
return m_missingTexture;
}
/**
* Renders the world using the parameters of the passed Camera.
* Note: The camera's near and far planes are overriden by weather effects.
*
* - draws all objects (instances, vehicles etc.)
* - draws particles
* - draws water surfaces
* - draws the skybox
*/
void renderWorld(GameWorld* world, const ViewCamera& camera, float alpha);
/**
* Renders the effects (Particles, Lighttrails etc)
*/
void renderEffects(GameWorld* world);
/**
* @brief Draws the current on screen text.
*/
void drawOnScreenText();
/**
* @brief Draws a texture on the screen
*/
void drawTexture(TextureData* texture, glm::vec4 extents);
void drawColour(const glm::vec4& colour, glm::vec4 extents);
/**
* Renders a model (who'd have thought)
*/
void renderModel(Model*, const glm::mat4& modelMatrix,
GameObject* = nullptr);
void renderGeometry(Model*, size_t geom, const glm::mat4& modelMatrix,
float opacity, GameObject* = nullptr);
/** Renders the area indicator */
void renderAreaIndicator(const AreaIndicatorInfo* info);
/** method for rendering AI debug information */
void renderPaths();
/** Increases cinematic value */
void renderLetterbox();
void setupRender();
void renderPostProcess();
Renderer* getRenderer() {
return renderer;
}
void setViewport(int w, int h);
void setCullOverride(bool override, const ViewCamera& cullCamera) {
cullingCamera = cullCamera;
cullOverride = override;
}
MapRenderer map;
WaterRenderer water;
TextRenderer text;
// Profiling data
Renderer::ProfileInfo profObjects;
Renderer::ProfileInfo profSky;
Renderer::ProfileInfo profWater;
Renderer::ProfileInfo profEffects;
};
#endif

View File

@ -268,7 +268,6 @@ void main()
outColour = c * tint;
})";
const char* ScreenSpaceRect::VertexShader = R"(
#version 330
@ -325,5 +324,4 @@ void main()
vec4 c = texture(colour, TexCoords);
outColour = c;
})";
}

View File

@ -2,11 +2,11 @@
#ifndef _GAMESHADERS_HPP_
#define _GAMESHADERS_HPP_
#define SHADER_VF(Name) \
struct Name {\
static const char* VertexShader;\
static const char* FragmentShader;\
}
#define SHADER_VF(Name) \
struct Name { \
static const char* VertexShader; \
static const char* FragmentShader; \
}
/**
* @brief collection of shaders to make managing them a little easier.
@ -24,18 +24,18 @@ SHADER_VF(WaterHQ);
SHADER_VF(Mask3D);
struct Sky {
static const char* VertexShader;
static const char* FragmentShader;
static const char* VertexShader;
static const char* FragmentShader;
};
struct WorldObject {
static const char* VertexShader;
static const char* FragmentShader;
static const char* VertexShader;
static const char* FragmentShader;
};
/** @brief Particle effect shaders, uses WorldObject::VertexShader */
struct Particle {
static const char* FragmentShader;
static const char* FragmentShader;
};
/**
@ -44,12 +44,11 @@ struct Particle {
* Used to draw black bars, splash screens, fading etc.
*/
struct ScreenSpaceRect {
static const char* VertexShader;
static const char* FragmentShader;
static const char* VertexShader;
static const char* FragmentShader;
};
SHADER_VF(DefaultPostProcess);
}
#endif

View File

@ -1,10 +1,10 @@
#include <render/MapRenderer.hpp>
#include <render/GameShaders.hpp>
#include <engine/GameWorld.hpp>
#include <ai/PlayerController.hpp>
#include <engine/GameData.hpp>
#include <engine/GameState.hpp>
#include <ai/PlayerController.hpp>
#include <engine/GameWorld.hpp>
#include <objects/CharacterObject.hpp>
#include <render/GameShaders.hpp>
#include <render/MapRenderer.hpp>
const char* MapVertexShader = R"(
#version 330
@ -37,262 +37,248 @@ void main()
outColour = vec4(colour.rgb + c.rgb, colour.a * c.a);
})";
MapRenderer::MapRenderer(Renderer* renderer, GameData* _data)
: data(_data), renderer(renderer)
{
rectGeom.uploadVertices<VertexP2>({
{-.5f, -.5f},
{ .5f, -.5f},
{ .5f, .5f},
{-.5f, .5f}
});
rect.addGeometry(&rectGeom);
rect.setFaceType(GL_TRIANGLE_FAN);
: data(_data), renderer(renderer) {
rectGeom.uploadVertices<VertexP2>(
{{-.5f, -.5f}, {.5f, -.5f}, {.5f, .5f}, {-.5f, .5f}});
rect.addGeometry(&rectGeom);
rect.setFaceType(GL_TRIANGLE_FAN);
std::vector<VertexP2> circleVerts;
circleVerts.push_back({0.f, 0.f});
for (int v = 0; v < 181; ++v) {
circleVerts.push_back({
0.5f * glm::cos(2*(v/180.f)*glm::pi<float>()),
0.5f * glm::sin(2*(v/180.f)*glm::pi<float>())
});
}
circleGeom.uploadVertices(circleVerts);
circle.addGeometry(&circleGeom);
circle.setFaceType(GL_TRIANGLE_FAN);
rectProg = renderer->createShader(
MapVertexShader,
MapFragmentShader
);
renderer->setUniform(rectProg, "colour", glm::vec4(1.f));
std::vector<VertexP2> circleVerts;
circleVerts.push_back({0.f, 0.f});
for (int v = 0; v < 181; ++v) {
circleVerts.push_back(
{0.5f * glm::cos(2 * (v / 180.f) * glm::pi<float>()),
0.5f * glm::sin(2 * (v / 180.f) * glm::pi<float>())});
}
circleGeom.uploadVertices(circleVerts);
circle.addGeometry(&circleGeom);
circle.setFaceType(GL_TRIANGLE_FAN);
rectProg = renderer->createShader(MapVertexShader, MapFragmentShader);
renderer->setUniform(rectProg, "colour", glm::vec4(1.f));
}
#define GAME_MAP_SIZE 4000
void MapRenderer::draw(GameWorld* world, const MapInfo& mi)
{
renderer->pushDebugGroup("Map");
renderer->useProgram(rectProg);
void MapRenderer::draw(GameWorld* world, const MapInfo& mi) {
renderer->pushDebugGroup("Map");
renderer->useProgram(rectProg);
// World out the number of units per tile
glm::vec2 worldSize(GAME_MAP_SIZE);
const int mapBlockLine = 8;
glm::vec2 tileSize = worldSize / (float)mapBlockLine;
// Determine the scale to show the right number of world units on the screen
float worldScale = mi.screenSize / mi.worldSize;
// World out the number of units per tile
glm::vec2 worldSize(GAME_MAP_SIZE);
const int mapBlockLine = 8;
glm::vec2 tileSize = worldSize / (float)mapBlockLine;
// Determine the scale to show the right number of world units on the screen
float worldScale = mi.screenSize / mi.worldSize;
auto proj = renderer->get2DProjection();
glm::mat4 view, model;
renderer->setUniform(rectProg, "proj", proj);
renderer->setUniform(rectProg, "model", glm::mat4());
renderer->setUniform(rectProg, "colour", glm::vec4(0.f, 0.f, 0.f, 1.f));
auto proj = renderer->get2DProjection();
glm::mat4 view, model;
renderer->setUniform(rectProg, "proj", proj);
renderer->setUniform(rectProg, "model", glm::mat4());
renderer->setUniform(rectProg, "colour", glm::vec4(0.f, 0.f, 0.f, 1.f));
view = glm::translate(view, glm::vec3(mi.screenPosition, 0.f));
view = glm::translate(view, glm::vec3(mi.screenPosition, 0.f));
if (mi.clipToSize)
{
glBindVertexArray( circle.getVAOName() );
glBindTexture(GL_TEXTURE_2D, 0);
glm::mat4 circleView = glm::scale(view, glm::vec3(mi.screenSize));
renderer->setUniform(rectProg, "view", circleView);
glEnable(GL_STENCIL_TEST);
glStencilFunc(GL_ALWAYS, 1, 0xFF);
glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
glStencilMask(0xFF);
glColorMask(0x00, 0x00, 0x00, 0x00);
glDrawArrays(GL_TRIANGLE_FAN, 0, 182);
glColorMask(0xFF, 0xFF, 0xFF, 0xFF);
glStencilFunc(GL_EQUAL, 1, 0xFF);
}
if (mi.clipToSize) {
glBindVertexArray(circle.getVAOName());
glBindTexture(GL_TEXTURE_2D, 0);
glm::mat4 circleView = glm::scale(view, glm::vec3(mi.screenSize));
renderer->setUniform(rectProg, "view", circleView);
glEnable(GL_STENCIL_TEST);
glStencilFunc(GL_ALWAYS, 1, 0xFF);
glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
glStencilMask(0xFF);
glColorMask(0x00, 0x00, 0x00, 0x00);
glDrawArrays(GL_TRIANGLE_FAN, 0, 182);
glColorMask(0xFF, 0xFF, 0xFF, 0xFF);
glStencilFunc(GL_EQUAL, 1, 0xFF);
}
view = glm::scale(view, glm::vec3(worldScale));
view = glm::rotate(view, mi.rotation, glm::vec3(0.f, 0.f, 1.f));
view = glm::translate(view, glm::vec3(glm::vec2(-1.f, 1.f) * mi.worldCenter, 0.f));
renderer->setUniform(rectProg, "view", view);
view = glm::scale(view, glm::vec3(worldScale));
view = glm::rotate(view, mi.rotation, glm::vec3(0.f, 0.f, 1.f));
view = glm::translate(
view, glm::vec3(glm::vec2(-1.f, 1.f) * mi.worldCenter, 0.f));
renderer->setUniform(rectProg, "view", view);
glBindVertexArray( rect.getVAOName() );
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, 0);
glBindVertexArray(rect.getVAOName());
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, 0);
// radar00 = -x, +y
// incrementing in X, then Y
int initX = -(mapBlockLine/2);
int initY = -(mapBlockLine/2);
// radar00 = -x, +y
// incrementing in X, then Y
for( int m = 0; m < MAP_BLOCK_SIZE; ++m )
{
std::string num = (m < 10 ? "0" : "");
std::string name = "radar" + num + std::to_string(m);
auto texture = world->data->textures[{name,""}];
glBindTexture(GL_TEXTURE_2D, texture->getName());
int mX = initX + (m % mapBlockLine);
int mY = initY + (m / mapBlockLine);
auto tc = glm::vec2(mX, mY) * tileSize + glm::vec2(tileSize/2.f);
glm::mat4 tilemodel = model;
tilemodel = glm::translate( tilemodel, glm::vec3( tc, 0.f ) );
tilemodel = glm::scale( tilemodel, glm::vec3( tileSize, 1.f ) );
renderer->setUniform(rectProg, "model", tilemodel);
glDrawArrays( GL_TRIANGLE_FAN, 0, 4 );
}
int initX = -(mapBlockLine / 2);
int initY = -(mapBlockLine / 2);
// From here on out we will work in screenspace
renderer->setUniform(rectProg, "view", glm::mat4());
for (int m = 0; m < MAP_BLOCK_SIZE; ++m) {
std::string num = (m < 10 ? "0" : "");
std::string name = "radar" + num + std::to_string(m);
auto texture = world->data->textures[{name, ""}];
if (mi.clipToSize) {
glDisable(GL_STENCIL_TEST);
// We only need the outer ring if we're clipping.
glBlendFuncSeparate(GL_DST_COLOR, GL_ZERO, GL_ONE, GL_ZERO);
TextureData::Handle radarDisc = data->findTexture("radardisc");
glBindTexture(GL_TEXTURE_2D, texture->getName());
glm::mat4 model;
model = glm::translate(model, glm::vec3(mi.screenPosition, 0.0f));
model = glm::scale(model, glm::vec3(mi.screenSize*1.07));
renderer->setUniform(rectProg, "model", model);
glBindTexture(GL_TEXTURE_2D, radarDisc->getName());
glDrawArrays( GL_TRIANGLE_FAN, 0, 4 );
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ZERO);
}
int mX = initX + (m % mapBlockLine);
int mY = initY + (m / mapBlockLine);
// Draw the player blip
auto player = world->pedestrianPool.find(world->state->playerObject);
if( player )
{
glm::vec2 plyblip(player->getPosition());
float hdg = glm::roll(player->getRotation());
drawBlip(
plyblip, view, mi,
"radar_centre", glm::vec4(0.0f, 0.0f, 0.0f, 1.0f), 18.0f, mi.rotation - hdg
);
}
auto tc = glm::vec2(mX, mY) * tileSize + glm::vec2(tileSize / 2.f);
drawBlip(
mi.worldCenter + glm::vec2(0.f, mi.worldSize), view, mi,
"radar_north", glm::vec4(0.0f, 0.0f, 0.0f, 1.0f), 24.f
);
for(auto& radarBlip : world->state->radarBlips)
{
const auto& blip = radarBlip.second;
glm::mat4 tilemodel = model;
tilemodel = glm::translate(tilemodel, glm::vec3(tc, 0.f));
tilemodel = glm::scale(tilemodel, glm::vec3(tileSize, 1.f));
auto dm = blip.display;
if( dm == BlipData::Hide || dm == BlipData::MarkerOnly ) {
continue;
}
renderer->setUniform(rectProg, "model", tilemodel);
glm::vec2 blippos( blip.coord );
if( blip.target > 0 )
{
GameObject* object = world->getBlipTarget(blip);
if( object )
{
blippos = glm::vec2( object->getPosition() );
}
}
const auto& texture = blip.texture;
if (!texture.empty()) {
drawBlip(blippos, view, mi, texture, glm::vec4(0.0f, 0.0f, 0.0f, 1.0f), 18.0f);
} else {
// Colours from http://www.gtamodding.com/wiki/0165 (colors not specific to that opcode!)
uint32_t rgbaValue;
switch(blip.colour) {
case 0: // RED
rgbaValue = blip.dimmed ? 0x7F0000FF : 0x712B49FF;
break;
case 1: // GREEN
rgbaValue = blip.dimmed ? 0x007F00FF : 0x5FA06AFF;
break;
case 2: // BLUE
rgbaValue = blip.dimmed ? 0x00007FFF : 0x80A7F3FF;
break;
case 3: // WHITE
rgbaValue = blip.dimmed ? 0x7F7F7FFF : 0xE1E1E1FF;
break;
case 4: // YELLOW
rgbaValue = blip.dimmed ? 0x7F7F00FF : 0xFFFF00FF;
break;
case 5: // PURPLE
rgbaValue = blip.dimmed ? 0x7F007FFF : 0xFF00FFFF;
break;
case 6: // CYAN
rgbaValue = blip.dimmed ? 0x007F7FFF : 0x00FFFFFF;
break;
default: // Extended mode (Dimming ignored)
rgbaValue = blip.colour;
break;
}
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
}
glm::vec4 colour(
(rgbaValue >> 24) / 255.0f,
((rgbaValue >> 16) & 0xFF) / 255.0f,
((rgbaValue >> 8) & 0xFF) / 255.0f,
1.0f // Note: Alpha is not controlled by blip
);
// From here on out we will work in screenspace
renderer->setUniform(rectProg, "view", glm::mat4());
drawBlip(blippos, view, mi, colour, blip.size * 2.0f);
}
}
if (mi.clipToSize) {
glDisable(GL_STENCIL_TEST);
// We only need the outer ring if we're clipping.
glBlendFuncSeparate(GL_DST_COLOR, GL_ZERO, GL_ONE, GL_ZERO);
TextureData::Handle radarDisc = data->findTexture("radardisc");
glBindVertexArray( 0 );
glBindTexture(GL_TEXTURE_2D, 0);
glUseProgram(0);
/// @TODO migrate to using the renderer
renderer->invalidate();
renderer->popDebugGroup();
glm::mat4 model;
model = glm::translate(model, glm::vec3(mi.screenPosition, 0.0f));
model = glm::scale(model, glm::vec3(mi.screenSize * 1.07));
renderer->setUniform(rectProg, "model", model);
glBindTexture(GL_TEXTURE_2D, radarDisc->getName());
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE,
GL_ZERO);
}
// Draw the player blip
auto player = world->pedestrianPool.find(world->state->playerObject);
if (player) {
glm::vec2 plyblip(player->getPosition());
float hdg = glm::roll(player->getRotation());
drawBlip(plyblip, view, mi, "radar_centre",
glm::vec4(0.0f, 0.0f, 0.0f, 1.0f), 18.0f, mi.rotation - hdg);
}
drawBlip(mi.worldCenter + glm::vec2(0.f, mi.worldSize), view, mi,
"radar_north", glm::vec4(0.0f, 0.0f, 0.0f, 1.0f), 24.f);
for (auto& radarBlip : world->state->radarBlips) {
const auto& blip = radarBlip.second;
auto dm = blip.display;
if (dm == BlipData::Hide || dm == BlipData::MarkerOnly) {
continue;
}
glm::vec2 blippos(blip.coord);
if (blip.target > 0) {
GameObject* object = world->getBlipTarget(blip);
if (object) {
blippos = glm::vec2(object->getPosition());
}
}
const auto& texture = blip.texture;
if (!texture.empty()) {
drawBlip(blippos, view, mi, texture,
glm::vec4(0.0f, 0.0f, 0.0f, 1.0f), 18.0f);
} else {
// Colours from http://www.gtamodding.com/wiki/0165 (colors not
// specific to that opcode!)
uint32_t rgbaValue;
switch (blip.colour) {
case 0: // RED
rgbaValue = blip.dimmed ? 0x7F0000FF : 0x712B49FF;
break;
case 1: // GREEN
rgbaValue = blip.dimmed ? 0x007F00FF : 0x5FA06AFF;
break;
case 2: // BLUE
rgbaValue = blip.dimmed ? 0x00007FFF : 0x80A7F3FF;
break;
case 3: // WHITE
rgbaValue = blip.dimmed ? 0x7F7F7FFF : 0xE1E1E1FF;
break;
case 4: // YELLOW
rgbaValue = blip.dimmed ? 0x7F7F00FF : 0xFFFF00FF;
break;
case 5: // PURPLE
rgbaValue = blip.dimmed ? 0x7F007FFF : 0xFF00FFFF;
break;
case 6: // CYAN
rgbaValue = blip.dimmed ? 0x007F7FFF : 0x00FFFFFF;
break;
default: // Extended mode (Dimming ignored)
rgbaValue = blip.colour;
break;
}
glm::vec4 colour((rgbaValue >> 24) / 255.0f,
((rgbaValue >> 16) & 0xFF) / 255.0f,
((rgbaValue >> 8) & 0xFF) / 255.0f,
1.0f // Note: Alpha is not controlled by blip
);
drawBlip(blippos, view, mi, colour, blip.size * 2.0f);
}
}
glBindVertexArray(0);
glBindTexture(GL_TEXTURE_2D, 0);
glUseProgram(0);
/// @TODO migrate to using the renderer
renderer->invalidate();
renderer->popDebugGroup();
}
void MapRenderer::prepareBlip(const glm::vec2& coord, const glm::mat4& view, const MapInfo& mi, const std::string& texture, glm::vec4 colour, float size, float heading)
{
glm::vec2 adjustedCoord = coord;
if (mi.clipToSize)
{
float maxDist = mi.worldSize/2.f;
float centerDist = glm::distance(coord, mi.worldCenter);
if (centerDist > maxDist) {
adjustedCoord = mi.worldCenter + ((coord - mi.worldCenter)/centerDist)*maxDist;
}
}
void MapRenderer::prepareBlip(const glm::vec2& coord, const glm::mat4& view,
const MapInfo& mi, const std::string& texture,
glm::vec4 colour, float size, float heading) {
glm::vec2 adjustedCoord = coord;
if (mi.clipToSize) {
float maxDist = mi.worldSize / 2.f;
float centerDist = glm::distance(coord, mi.worldCenter);
if (centerDist > maxDist) {
adjustedCoord = mi.worldCenter +
((coord - mi.worldCenter) / centerDist) * maxDist;
}
}
glm::vec3 viewPos(view * glm::vec4(glm::vec2(1.f,-1.f)*adjustedCoord, 0.f, 1.f));
glm::mat4 model;
model = glm::translate(model, viewPos);
model = glm::scale(model, glm::vec3(size));
model = glm::rotate(model, heading, glm::vec3(0.f, 0.f, 1.f));
renderer->setUniform(rectProg, "model", model);
glm::vec3 viewPos(
view * glm::vec4(glm::vec2(1.f, -1.f) * adjustedCoord, 0.f, 1.f));
glm::mat4 model;
model = glm::translate(model, viewPos);
model = glm::scale(model, glm::vec3(size));
model = glm::rotate(model, heading, glm::vec3(0.f, 0.f, 1.f));
renderer->setUniform(rectProg, "model", model);
GLuint tex = 0;
if ( !texture.empty() )
{
auto sprite= data->findTexture(texture);
tex = sprite->getName();
}
renderer->setUniform(rectProg, "colour", colour);
glBindTexture(GL_TEXTURE_2D, tex);
GLuint tex = 0;
if (!texture.empty()) {
auto sprite = data->findTexture(texture);
tex = sprite->getName();
}
renderer->setUniform(rectProg, "colour", colour);
glDrawArrays( GL_TRIANGLE_FAN, 0, 4 );
glBindTexture(GL_TEXTURE_2D, tex);
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
}
void MapRenderer::drawBlip(const glm::vec2& coord, const glm::mat4& view, const MapInfo& mi, const std::string& texture, glm::vec4 colour, float size, float heading) {
prepareBlip(coord, view, mi, texture, colour, size, heading);
glBindVertexArray( rect.getVAOName() );
glDrawArrays( GL_TRIANGLE_FAN, 0, 4 );
void MapRenderer::drawBlip(const glm::vec2& coord, const glm::mat4& view,
const MapInfo& mi, const std::string& texture,
glm::vec4 colour, float size, float heading) {
prepareBlip(coord, view, mi, texture, colour, size, heading);
glBindVertexArray(rect.getVAOName());
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
}
void MapRenderer::drawBlip(const glm::vec2& coord, const glm::mat4& view, const MapInfo& mi, glm::vec4 colour, float size) {
drawBlip(coord, view, mi, "", colour, size);
// Draw outline
renderer->setUniform(rectProg, "colour", glm::vec4(0.0f, 0.0f, 0.0f, 1.0f));
glDrawArrays( GL_LINE_LOOP, 0, 4 );
void MapRenderer::drawBlip(const glm::vec2& coord, const glm::mat4& view,
const MapInfo& mi, glm::vec4 colour, float size) {
drawBlip(coord, view, mi, "", colour, size);
// Draw outline
renderer->setUniform(rectProg, "colour", glm::vec4(0.0f, 0.0f, 0.0f, 1.0f));
glDrawArrays(GL_LINE_LOOP, 0, 4);
}

View File

@ -9,43 +9,45 @@ class GameWorld;
/**
* Utility class for rendering the world map, in the menu and radar.
*/
class MapRenderer
{
class MapRenderer {
public:
struct MapInfo
{
/// World coordinate center
glm::vec2 worldCenter;
/// World units to fit on the map
float worldSize;
struct MapInfo {
/// World coordinate center
glm::vec2 worldCenter;
/// World units to fit on the map
float worldSize;
/// yaw of the map
float rotation = 0.f;
/// yaw of the map
float rotation = 0.f;
glm::vec2 screenPosition;
float screenSize;
/// Make the map circular, or don't.
bool clipToSize = true;
};
MapRenderer(Renderer* renderer, GameData* data);
void draw(GameWorld* world, const MapInfo& mi);
glm::vec2 screenPosition;
float screenSize;
/// Make the map circular, or don't.
bool clipToSize = true;
};
MapRenderer(Renderer* renderer, GameData* data);
void draw(GameWorld* world, const MapInfo& mi);
private:
GameData* data;
Renderer* renderer;
GeometryBuffer rectGeom;
DrawBuffer rect;
GameData* data;
Renderer* renderer;
GeometryBuffer circleGeom;
DrawBuffer circle;
Renderer::ShaderProgram* rectProg;
void prepareBlip(const glm::vec2& coord, const glm::mat4& view, const MapInfo& mi, const std::string& texture, glm::vec4 colour, float size, float heading);
void drawBlip(const glm::vec2& coord, const glm::mat4& view, const MapInfo& mi, const std::string& texture, glm::vec4 colour, float size, float heading = 0.0f);
void drawBlip(const glm::vec2& coord, const glm::mat4& view, const MapInfo& mi, glm::vec4 colour, float size);
GeometryBuffer rectGeom;
DrawBuffer rect;
GeometryBuffer circleGeom;
DrawBuffer circle;
Renderer::ShaderProgram* rectProg;
void prepareBlip(const glm::vec2& coord, const glm::mat4& view,
const MapInfo& mi, const std::string& texture,
glm::vec4 colour, float size, float heading);
void drawBlip(const glm::vec2& coord, const glm::mat4& view,
const MapInfo& mi, const std::string& texture,
glm::vec4 colour, float size, float heading = 0.0f);
void drawBlip(const glm::vec2& coord, const glm::mat4& view,
const MapInfo& mi, glm::vec4 colour, float size);
};

File diff suppressed because it is too large Load Diff

View File

@ -1,13 +1,13 @@
#ifndef _RWENGINE_OBJECTRENDERER_HPP_
#define _RWENGINE_OBJECTRENDERER_HPP_
#include <glm/glm.hpp>
#include <rw/types.hpp>
#include <render/ViewCamera.hpp>
#include <render/OpenGLRenderer.hpp>
#include <objects/GameObject.hpp>
#include <engine/GameWorld.hpp>
#include <gl/DrawBuffer.hpp>
#include <glm/glm.hpp>
#include <objects/GameObject.hpp>
#include <render/OpenGLRenderer.hpp>
#include <render/ViewCamera.hpp>
#include <rw/types.hpp>
class ProjectileObject;
class PickupObject;
@ -18,61 +18,47 @@ class PickupObject;
* Determines what parts of an object are within a camera frustum and exports
* a list of things to render for the object.
*/
class ObjectRenderer
{
class ObjectRenderer {
public:
ObjectRenderer(GameWorld* world,
const ViewCamera& camera,
float renderAlpha,
GLuint errorTexture)
: m_world (world)
, m_camera(camera)
, m_renderAlpha(renderAlpha)
, m_errorTexture(errorTexture)
{ }
ObjectRenderer(GameWorld* world, const ViewCamera& camera,
float renderAlpha, GLuint errorTexture)
: m_world(world)
, m_camera(camera)
, m_renderAlpha(renderAlpha)
, m_errorTexture(errorTexture) {
}
/**
* @brief buildRenderList
*
* Exports rendering instructions for an object
*/
void buildRenderList(GameObject* object, RenderList& outList);
/**
* @brief buildRenderList
*
* Exports rendering instructions for an object
*/
void buildRenderList(GameObject* object, RenderList& outList);
private:
GameWorld* m_world;
const ViewCamera& m_camera;
float m_renderAlpha;
GLuint m_errorTexture;
GameWorld* m_world;
const ViewCamera& m_camera;
float m_renderAlpha;
GLuint m_errorTexture;
void renderInstance(InstanceObject *instance, RenderList& outList);
void renderCharacter(CharacterObject *pedestrian, RenderList& outList);
void renderVehicle(VehicleObject *vehicle, RenderList& outList);
void renderPickup(PickupObject *pickup, RenderList& outList);
void renderCutsceneObject(CutsceneObject *cutscene, RenderList& outList);
void renderProjectile(ProjectileObject *projectile, RenderList& outList);
void renderInstance(InstanceObject* instance, RenderList& outList);
void renderCharacter(CharacterObject* pedestrian, RenderList& outList);
void renderVehicle(VehicleObject* vehicle, RenderList& outList);
void renderPickup(PickupObject* pickup, RenderList& outList);
void renderCutsceneObject(CutsceneObject* cutscene, RenderList& outList);
void renderProjectile(ProjectileObject* projectile, RenderList& outList);
void renderItem(InventoryItem *item,
const glm::mat4 &modelMatrix,
RenderList& outList);
void renderWheel(VehicleObject* vehicle,
Model* model,
const glm::mat4 &matrix,
const std::string& name,
RenderList& outList);
void renderItem(InventoryItem* item, const glm::mat4& modelMatrix,
RenderList& outList);
void renderWheel(VehicleObject* vehicle, Model* model,
const glm::mat4& matrix, const std::string& name,
RenderList& outList);
bool renderFrame(Model* m,
ModelFrame* f,
const glm::mat4& matrix,
GameObject* object,
float opacity,
RenderList& outList);
bool renderFrame(Model* m, ModelFrame* f, const glm::mat4& matrix,
GameObject* object, float opacity, RenderList& outList);
void renderGeometry(Model* model,
size_t g,
const glm::mat4& modelMatrix,
float opacity,
GameObject* object,
RenderList& outList);
void renderGeometry(Model* model, size_t g, const glm::mat4& modelMatrix,
float opacity, GameObject* object, RenderList& outList);
};
#endif

View File

@ -1,159 +1,146 @@
#include <render/OpenGLRenderer.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <render/OpenGLRenderer.hpp>
#include <sstream>
#include <iostream>
#include <sstream>
GLuint compileShader(GLenum type, const char *source)
{
GLuint shader = glCreateShader(type);
glShaderSource(shader, 1, &source, NULL);
glCompileShader(shader);
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);
GLint status;
glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
if( status != GL_TRUE ) {
std::cerr << "[OGL] Shader Compilation Failed" << std::endl;
}
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 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);
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;
std::cerr << "[OGL] Shader InfoLog(" << shader << "):\n"
<< buffer << "\nSource:\n"
<< sourceBuff << std::endl;
delete[] buffer;
delete[] sourceBuff;
}
delete[] buffer;
delete[] sourceBuff;
}
if (status != GL_TRUE) {
exit(1);
}
if (status != GL_TRUE) {
exit(1);
}
return shader;
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);
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);
GLint status;
glGetProgramiv(prog, GL_LINK_STATUS, &status);
if( status != GL_TRUE ) {
std::cerr << "[OGL] Program Link Failed" << std::endl;
}
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);
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;
std::cerr << "[OGL] Program InfoLog(" << prog << "):\n"
<< buffer << std::endl;
delete[] buffer;
}
delete[] buffer;
}
if (status != GL_TRUE) {
exit(1);
}
if (status != GL_TRUE) {
exit(1);
}
glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);
glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);
return prog;
return prog;
}
void Renderer::setViewport(const glm::ivec2& vp)
{
viewport = vp;
void Renderer::setViewport(const glm::ivec2& vp) {
viewport = vp;
projection2D = glm::ortho(0.f, (float)viewport.x, (float)viewport.y, 0.f, -1.f, 1.f);
projection2D =
glm::ortho(0.f, (float)viewport.x, (float)viewport.y, 0.f, -1.f, 1.f);
}
void Renderer::swap()
{
drawCounter = 0;
textureCounter = 0;
bufferCounter = 0;
void Renderer::swap() {
drawCounter = 0;
textureCounter = 0;
bufferCounter = 0;
}
int Renderer::getDrawCount()
{
return drawCounter;
int Renderer::getDrawCount() {
return drawCounter;
}
int Renderer::getBufferCount()
{
return bufferCounter;
int Renderer::getBufferCount() {
return bufferCounter;
}
int Renderer::getTextureCount()
{
return textureCounter;
int Renderer::getTextureCount() {
return textureCounter;
}
const Renderer::SceneUniformData& Renderer::getSceneData() const
{
return lastSceneData;
const Renderer::SceneUniformData& Renderer::getSceneData() const {
return lastSceneData;
}
void OpenGLRenderer::useDrawBuffer(DrawBuffer* dbuff)
{
if( dbuff != currentDbuff )
{
glBindVertexArray(dbuff->getVAOName());
currentDbuff = dbuff;
bufferCounter++;
void OpenGLRenderer::useDrawBuffer(DrawBuffer* dbuff) {
if (dbuff != currentDbuff) {
glBindVertexArray(dbuff->getVAOName());
currentDbuff = dbuff;
bufferCounter++;
#if RW_PROFILER
if( currentDebugDepth > 0 )
{
profileInfo[currentDebugDepth-1].buffers++;
}
if (currentDebugDepth > 0) {
profileInfo[currentDebugDepth - 1].buffers++;
}
#endif
}
}
}
void OpenGLRenderer::useTexture(GLuint unit, GLuint tex)
{
if( currentTextures[unit] != tex )
{
glActiveTexture(GL_TEXTURE0 + unit);
glBindTexture(GL_TEXTURE_2D, tex);
currentTextures[unit] = tex;
textureCounter++;
void OpenGLRenderer::useTexture(GLuint unit, GLuint tex) {
if (currentTextures[unit] != tex) {
glActiveTexture(GL_TEXTURE0 + unit);
glBindTexture(GL_TEXTURE_2D, tex);
currentTextures[unit] = tex;
textureCounter++;
#if RW_PROFILER
if( currentDebugDepth > 0 )
{
profileInfo[currentDebugDepth-1].textures++;
}
if (currentDebugDepth > 0) {
profileInfo[currentDebugDepth - 1].textures++;
}
#endif
}
}
}
void OpenGLRenderer::useProgram(Renderer::ShaderProgram* p)
{
if( p != currentProgram )
{
currentProgram = static_cast<OpenGLShaderProgram*>(p);
glUseProgram( currentProgram->getName() );
}
void OpenGLRenderer::useProgram(Renderer::ShaderProgram* p) {
if (p != currentProgram) {
currentProgram = static_cast<OpenGLShaderProgram*>(p);
glUseProgram(currentProgram->getName());
}
}
#if 0
@ -183,186 +170,180 @@ void OpenGLRenderer::uploadUBO<OpenGLRenderer::ObjectUniformData>(GLuint buffer,
#endif
OpenGLRenderer::OpenGLRenderer()
: currentDbuff(nullptr)
, currentProgram(nullptr)
, currentUBO(0)
, maxObjectEntries(0)
, currentObjectEntry(0)
, entryAlignment(0)
, blendEnabled(false)
, depthWriteEnabled(true)
, currentDebugDepth(0)
{
// We need to query for some profiling exts.
ogl_CheckExtensions();
: currentDbuff(nullptr)
, currentProgram(nullptr)
, currentUBO(0)
, maxObjectEntries(0)
, currentObjectEntry(0)
, entryAlignment(0)
, blendEnabled(false)
, depthWriteEnabled(true)
, currentDebugDepth(0) {
// We need to query for some profiling exts.
ogl_CheckExtensions();
glGenBuffers(1, &UBOScene);
glGenBuffers(1, &UBOObject);
glGenBuffers(1, &UBOScene);
glGenBuffers(1, &UBOObject);
glBindBufferBase(GL_UNIFORM_BUFFER, 1, UBOScene);
glBindBufferBase(GL_UNIFORM_BUFFER, 2, UBOObject);
swap();
glBindBufferBase(GL_UNIFORM_BUFFER, 1, UBOScene);
glBindBufferBase(GL_UNIFORM_BUFFER, 2, UBOObject);
GLint maxUBOSize, UBOAlignment;
glGetIntegerv(GL_MAX_UNIFORM_BLOCK_SIZE, &maxUBOSize);
glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &UBOAlignment);
entryAlignment = 128;
maxObjectEntries = maxUBOSize / entryAlignment;
std::cout << "Max UBO Size: " << maxUBOSize << std::endl;
std::cout << "UBO Alignment: " << UBOAlignment << std::endl;
std::cout << "Max batch size: " << maxObjectEntries << std::endl;
swap();
glBindBuffer(GL_UNIFORM_BUFFER, UBOObject);
glBufferData(GL_UNIFORM_BUFFER,
entryAlignment * maxObjectEntries,
NULL,
GL_STREAM_DRAW);
GLint maxUBOSize, UBOAlignment;
glGetIntegerv(GL_MAX_UNIFORM_BLOCK_SIZE, &maxUBOSize);
glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &UBOAlignment);
entryAlignment = 128;
maxObjectEntries = maxUBOSize / entryAlignment;
std::cout << "Max UBO Size: " << maxUBOSize << std::endl;
std::cout << "UBO Alignment: " << UBOAlignment << std::endl;
std::cout << "Max batch size: " << maxObjectEntries << std::endl;
glGenQueries(1, &debugQuery);
glBindBuffer(GL_UNIFORM_BUFFER, UBOObject);
glBufferData(GL_UNIFORM_BUFFER, entryAlignment * maxObjectEntries, NULL,
GL_STREAM_DRAW);
glGenQueries(1, &debugQuery);
}
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();
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()));
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);
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);
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);
void OpenGLRenderer::setUniformTexture(Renderer::ShaderProgram* p,
const std::string& name, GLint tex) {
useProgram(p);
glUniform1i(currentProgram->getUniformLocation(name), tex);
glUniform1i(currentProgram->getUniformLocation(name), tex);
}
void OpenGLRenderer::setUniform(Renderer::ShaderProgram* p, const std::string& name, const glm::mat4& m)
{
useProgram(p);
void OpenGLRenderer::setUniform(Renderer::ShaderProgram* p,
const std::string& name, const glm::mat4& m) {
useProgram(p);
glUniformMatrix4fv(currentProgram->getUniformLocation(name.c_str()), 1, GL_FALSE, glm::value_ptr(m));
glUniformMatrix4fv(currentProgram->getUniformLocation(name.c_str()), 1,
GL_FALSE, glm::value_ptr(m));
}
void OpenGLRenderer::setUniform(Renderer::ShaderProgram* p, const std::string& name, const glm::vec4& m)
{
useProgram(p);
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));
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);
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));
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);
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));
glUniform2fv(currentProgram->getUniformLocation(name.c_str()), 1,
glm::value_ptr(m));
}
void OpenGLRenderer::setUniform(Renderer::ShaderProgram* p, const std::string& name, float f)
{
useProgram(p);
void OpenGLRenderer::setUniform(Renderer::ShaderProgram* p,
const std::string& name, float f) {
useProgram(p);
glUniform1fv(currentProgram->getUniformLocation(name.c_str()), 1, &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);
}
bool depthWriteWasEnabled = depthWriteEnabled;
if( clearDepth ) {
flags |= GL_DEPTH_BUFFER_BIT;
setDepthWrite(true);
}
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);
}
bool depthWriteWasEnabled = depthWriteEnabled;
if (clearDepth) {
flags |= GL_DEPTH_BUFFER_BIT;
setDepthWrite(true);
}
glClear(flags);
glClear(flags);
if(depthWriteWasEnabled != depthWriteEnabled) {
setDepthWrite(depthWriteWasEnabled);
}
if (depthWriteWasEnabled != depthWriteEnabled) {
setDepthWrite(depthWriteWasEnabled);
}
}
void OpenGLRenderer::setSceneParameters(const Renderer::SceneUniformData& data)
{
uploadUBO(UBOScene, data);
lastSceneData = data;
void OpenGLRenderer::setSceneParameters(
const Renderer::SceneUniformData& data) {
uploadUBO(UBOScene, data);
lastSceneData = data;
}
void OpenGLRenderer::setDrawState(const glm::mat4& model, DrawBuffer* draw, const Renderer::DrawParameters& p)
{
useDrawBuffer(draw);
void OpenGLRenderer::setDrawState(const glm::mat4& model, DrawBuffer* draw,
const Renderer::DrawParameters& p) {
useDrawBuffer(draw);
for( GLuint u = 0; u < p.textures.size(); ++u )
{
useTexture(u, p.textures[u]);
}
for (GLuint u = 0; u < p.textures.size(); ++u) {
useTexture(u, p.textures[u]);
}
setBlend(p.blend);
setDepthWrite(p.depthWrite);
setBlend(p.blend);
setDepthWrite(p.depthWrite);
ObjectUniformData oudata {
model,
glm::vec4(p.colour.r/255.f, p.colour.g/255.f, p.colour.b/255.f, p.colour.a/255.f),
1.f,
1.f,
p.visibility
};
uploadUBO(UBOObject, oudata);
ObjectUniformData oudata{model,
glm::vec4(p.colour.r / 255.f, p.colour.g / 255.f,
p.colour.b / 255.f, p.colour.a / 255.f),
1.f, 1.f, p.visibility};
uploadUBO(UBOObject, oudata);
drawCounter++;
drawCounter++;
#if RW_PROFILER
if( currentDebugDepth > 0 )
{
profileInfo[currentDebugDepth-1].draws++;
profileInfo[currentDebugDepth-1].primitives += p.count;
}
if (currentDebugDepth > 0) {
profileInfo[currentDebugDepth - 1].draws++;
profileInfo[currentDebugDepth - 1].primitives += p.count;
}
#endif
}
void OpenGLRenderer::draw(const glm::mat4& model, DrawBuffer* draw, const Renderer::DrawParameters& p)
{
setDrawState(model, draw, p);
void OpenGLRenderer::draw(const glm::mat4& model, DrawBuffer* draw,
const Renderer::DrawParameters& p) {
setDrawState(model, draw, p);
glDrawElements(draw->getFaceType(), p.count, GL_UNSIGNED_INT,
(void*) (sizeof(RenderIndex) * p.start));
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)
{
setDrawState(model, draw, p);
void OpenGLRenderer::drawArrays(const glm::mat4& model, DrawBuffer* draw,
const Renderer::DrawParameters& p) {
setDrawState(model, draw, p);
glDrawArrays(draw->getFaceType(), p.start, p.count);
glDrawArrays(draw->getFaceType(), p.start, p.count);
}
void OpenGLRenderer::drawBatched(const RenderList& list)
{
#if 0 // Needs shader changes
void OpenGLRenderer::drawBatched(const RenderList& list) {
#if 0 // Needs shader changes
// Determine how many batches we need to process the entire list
auto entries = list.size();
glBindBuffer(GL_UNIFORM_BUFFER, UBOObject);
@ -405,71 +386,65 @@ void OpenGLRenderer::drawBatched(const RenderList& list)
}
}
#else
for(auto& ri : list)
{
draw(ri.model, ri.dbuff, ri.drawInfo);
}
for (auto& ri : list) {
draw(ri.model, ri.dbuff, ri.drawInfo);
}
#endif
}
void OpenGLRenderer::invalidate()
{
currentDbuff = nullptr;
currentProgram = nullptr;
currentTextures.clear();
currentUBO = 0;
void OpenGLRenderer::invalidate() {
currentDbuff = nullptr;
currentProgram = nullptr;
currentTextures.clear();
currentUBO = 0;
}
void OpenGLRenderer::pushDebugGroup(const std::string& title)
{
void OpenGLRenderer::pushDebugGroup(const std::string& title) {
#if RW_PROFILER
if( ogl_ext_KHR_debug )
{
glPushDebugGroup(GL_DEBUG_SOURCE_APPLICATION, 0, -1, title.c_str());
ProfileInfo& prof = profileInfo[currentDebugDepth];
prof.buffers = prof.draws = prof.textures = prof.uploads = prof.primitives = 0;
glQueryCounter(debugQuery, GL_TIMESTAMP);
glGetQueryObjectui64v(debugQuery, GL_QUERY_RESULT, &prof.timerStart);
currentDebugDepth++;
assert( currentDebugDepth < MAX_DEBUG_DEPTH );
}
if (ogl_ext_KHR_debug) {
glPushDebugGroup(GL_DEBUG_SOURCE_APPLICATION, 0, -1, title.c_str());
ProfileInfo& prof = profileInfo[currentDebugDepth];
prof.buffers = prof.draws = prof.textures = prof.uploads =
prof.primitives = 0;
glQueryCounter(debugQuery, GL_TIMESTAMP);
glGetQueryObjectui64v(debugQuery, GL_QUERY_RESULT, &prof.timerStart);
currentDebugDepth++;
assert(currentDebugDepth < MAX_DEBUG_DEPTH);
}
#else
RW_UNUSED(title);
RW_UNUSED(title);
#endif
}
const Renderer::ProfileInfo& OpenGLRenderer::popDebugGroup()
{
const Renderer::ProfileInfo& OpenGLRenderer::popDebugGroup() {
#if RW_PROFILER
if( ogl_ext_KHR_debug )
{
glPopDebugGroup();
currentDebugDepth--;
assert( currentDebugDepth >= 0 );
if (ogl_ext_KHR_debug) {
glPopDebugGroup();
currentDebugDepth--;
assert(currentDebugDepth >= 0);
ProfileInfo& prof = profileInfo[currentDebugDepth];
ProfileInfo& prof = profileInfo[currentDebugDepth];
glQueryCounter(debugQuery, GL_TIMESTAMP);
GLuint64 current_time;
glGetQueryObjectui64v(debugQuery, GL_QUERY_RESULT, &current_time);
glQueryCounter(debugQuery, GL_TIMESTAMP);
GLuint64 current_time;
glGetQueryObjectui64v(debugQuery, GL_QUERY_RESULT, &current_time);
prof.duration = current_time - prof.timerStart;
prof.duration = current_time - prof.timerStart;
// Add counters to the parent group
if( currentDebugDepth > 0 )
{
ProfileInfo& p = profileInfo[currentDebugDepth-1];
p.draws += prof.draws;
p.buffers += prof.buffers;
p.primitives += prof.primitives;
p.textures += prof.textures;
p.uploads += prof.uploads;
}
// Add counters to the parent group
if (currentDebugDepth > 0) {
ProfileInfo& p = profileInfo[currentDebugDepth - 1];
p.draws += prof.draws;
p.buffers += prof.buffers;
p.primitives += prof.primitives;
p.textures += prof.textures;
p.uploads += prof.uploads;
}
return prof;
}
return prof;
}
#endif
return profileInfo[0];
return profileInfo[0];
}

View File

@ -2,10 +2,10 @@
#ifndef _OPENGLRENDERER_HPP_
#define _OPENGLRENDERER_HPP_
#include <rw/types.hpp>
#include <gl/DrawBuffer.hpp>
#include <gl/GeometryBuffer.hpp>
#include <glm/vec2.hpp>
#include <rw/types.hpp>
typedef uint64_t RenderKey;
@ -14,309 +14,320 @@ typedef uint64_t RenderKey;
typedef std::uint32_t RenderIndex;
struct VertexP3
{
glm::vec3 position;
struct VertexP3 {
glm::vec3 position;
static const AttributeList vertex_attributes() {
return {
{ATRS_Position, 3, sizeof(VertexP3), 0ul},
};
}
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}
};
}
static const AttributeList vertex_attributes() {
return {{ATRS_Position, 2, sizeof(VertexP2), 0ul}};
}
float x, y;
float x, y;
};
class Renderer
{
class Renderer {
public:
typedef std::vector<GLuint> Textures;
typedef std::vector<GLuint> Textures;
/**
* @brief The DrawParameters struct stores drawing state
*
* The state for texture units, blending and material properties
* are recieved for drawing through this structure.
*
* Since not all draws use the same shaders, material properties
* should be controlled via a different mechanism.
*/
struct DrawParameters {
/// Number of indicies
size_t count;
/// Start index.
unsigned int start;
/// Textures to use
Textures textures;
/// Alpha blending state
bool blend;
// Depth writing state
bool depthWrite;
/// Material
glm::u8vec4 colour;
/// Material
float ambient;
/// Material
float diffuse;
/// Material
float visibility;
/**
* @brief The DrawParameters struct stores drawing state
*
* The state for texture units, blending and material properties
* are recieved for drawing through this structure.
*
* Since not all draws use the same shaders, material properties
* should be controlled via a different mechanism.
*/
struct DrawParameters
{
/// Number of indicies
size_t count;
/// Start index.
unsigned int start;
/// Textures to use
Textures textures;
/// Alpha blending state
bool blend;
// Depth writing state
bool depthWrite;
/// Material
glm::u8vec4 colour;
/// Material
float ambient;
/// Material
float diffuse;
/// Material
float visibility;
// Default state -- should be moved to materials
DrawParameters()
: blend(false)
, depthWrite(true)
, ambient(1.f)
, diffuse(1.f)
, visibility(1.f) {
}
};
// Default state -- should be moved to materials
DrawParameters()
: blend(false)
, depthWrite(true)
, ambient(1.f)
, diffuse(1.f)
, visibility(1.f)
{ }
};
/**
* @brief The RenderInstruction struct Generic Rendering instruction
*
* These are generated by the ObjectRenderer, and passed in to the
* OpenGLRenderer by GameRenderer.
*/
struct RenderInstruction {
RenderKey sortKey;
// Ideally, this would just be an index into a buffer that contains the
// matrix
glm::mat4 model;
DrawBuffer* dbuff;
Renderer::DrawParameters drawInfo;
/**
* @brief The RenderInstruction struct Generic Rendering instruction
*
* These are generated by the ObjectRenderer, and passed in to the
* OpenGLRenderer by GameRenderer.
*/
struct RenderInstruction
{
RenderKey sortKey;
// Ideally, this would just be an index into a buffer that contains the matrix
glm::mat4 model;
DrawBuffer* dbuff;
Renderer::DrawParameters drawInfo;
RenderInstruction(RenderKey key, const glm::mat4& model,
DrawBuffer* dbuff, const Renderer::DrawParameters& dp)
: sortKey(key), model(model), dbuff(dbuff), drawInfo(dp) {
}
};
typedef std::vector<RenderInstruction> RenderList;
RenderInstruction(
RenderKey key,
const glm::mat4& model,
DrawBuffer* dbuff,
const Renderer::DrawParameters& dp)
: sortKey(key)
, model(model)
, dbuff(dbuff)
, drawInfo(dp)
{
struct ObjectUniformData {
glm::mat4 model;
glm::vec4 colour;
float diffuse;
float ambient;
float visibility;
};
}
};
typedef std::vector<RenderInstruction> RenderList;
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.
};
struct ObjectUniformData {
glm::mat4 model;
glm::vec4 colour;
float diffuse;
float ambient;
float visibility;
};
virtual std::string getIDString() const = 0;
struct SceneUniformData {
glm::mat4 projection;
glm::mat4 view;
glm::vec4 ambient;
glm::vec4 dynamic;
glm::vec4 fogColour;
glm::vec4 campos;
float fogStart;
float fogEnd;
};
virtual ShaderProgram* createShader(const std::string& vert,
const std::string& frag) = 0;
class ShaderProgram {
// This just provides an opaque handle for external users.
};
virtual void useProgram(ShaderProgram* p) = 0;
virtual std::string getIDString() const = 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::mat4& m) = 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 ShaderProgram* createShader(const std::string& vert, const std::string& frag) = 0;
virtual void clear(const glm::vec4& colour, bool clearColour = true,
bool clearDepth = true) = 0;
virtual void useProgram(ShaderProgram* p) = 0;
virtual void setSceneParameters(const SceneUniformData& data) = 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::mat4& m) = 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 draw(const glm::mat4& model, DrawBuffer* draw,
const DrawParameters& p) = 0;
virtual void drawArrays(const glm::mat4& model, DrawBuffer* draw,
const DrawParameters& p) = 0;
virtual void clear(const glm::vec4& colour, bool clearColour = true, bool clearDepth = true) = 0;
virtual void drawBatched(const RenderList& list) = 0;
virtual void setSceneParameters(const SceneUniformData& data) = 0;
void setViewport(const glm::ivec2& vp);
const glm::ivec2& getViewport() const {
return viewport;
}
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;
const glm::mat4& get2DProjection() const {
return projection2D;
}
virtual void drawBatched(const RenderList& list) = 0;
virtual void invalidate() = 0;
void setViewport(const glm::ivec2& vp);
const glm::ivec2& getViewport() const { return viewport; }
/**
* Resets all per-frame counters.
*/
void swap();
const glm::mat4& get2DProjection() const { return projection2D; }
/**
* Returns the number of draw calls issued for the current frame.
*/
int getDrawCount();
int getTextureCount();
int getBufferCount();
virtual void invalidate() = 0;
const SceneUniformData& getSceneData() const;
/**
* Resets all per-frame counters.
*/
void swap();
/**
* Returns the number of draw calls issued for the current frame.
*/
int getDrawCount();
int getTextureCount();
int getBufferCount();
const SceneUniformData& getSceneData() const;
/**
* Profiling data returned by popDebugGroup.
* Not all fields will be populated, depending on
* USING(RENDER_PROFILER)
*/
struct ProfileInfo {
GLuint64 timerStart;
GLuint64 duration;
unsigned int primitives;
unsigned int draws;
unsigned int textures;
unsigned int buffers;
unsigned int uploads;
};
/**
* Profiling data returned by popDebugGroup.
* Not all fields will be populated, depending on
* USING(RENDER_PROFILER)
*/
struct ProfileInfo
{
GLuint64 timerStart;
GLuint64 duration;
unsigned int primitives;
unsigned int draws;
unsigned int textures;
unsigned int buffers;
unsigned int uploads;
};
/**
* Signals the start of a debug group
*/
virtual void pushDebugGroup(const std::string& title) = 0;
/**
* Ends the current debug group and returns the profiling information
* for that group. The returned value is valid until the next call to
* pushDebugGroup
*/
virtual const ProfileInfo& popDebugGroup() = 0;
/**
* Signals the start of a debug group
*/
virtual void pushDebugGroup(const std::string& title) = 0;
/**
* Ends the current debug group and returns the profiling information
* for that group. The returned value is valid until the next call to
* pushDebugGroup
*/
virtual const ProfileInfo& popDebugGroup() = 0;
private:
glm::ivec2 viewport;
glm::mat4 projection2D;
glm::ivec2 viewport;
glm::mat4 projection2D;
protected:
int drawCounter;
int textureCounter;
int bufferCounter;
SceneUniformData lastSceneData;
int drawCounter;
int textureCounter;
int bufferCounter;
SceneUniformData lastSceneData;
};
class OpenGLRenderer : public Renderer
{
class OpenGLRenderer : public Renderer {
public:
class OpenGLShaderProgram : public ShaderProgram {
GLuint program;
std::map<std::string, GLint> uniforms;
class OpenGLShaderProgram : public ShaderProgram {
GLuint program;
std::map<std::string, GLint> uniforms;
public:
OpenGLShaderProgram(GLuint p)
: program(p)
{ }
public:
OpenGLShaderProgram(GLuint p) : program(p) {
}
GLuint getName() const { return program; }
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;
}
};
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();
OpenGLRenderer();
std::string getIDString() const override;
std::string getIDString() const override;
ShaderProgram* createShader(const std::string &vert, const std::string &frag) override;
void setProgramBlockBinding(ShaderProgram* p, const std::string &name, GLint point) override;
void setUniformTexture(ShaderProgram* p, const std::string &name, GLint tex) override;
void setUniform(ShaderProgram* p, const std::string& name, const glm::mat4& m) override;
void setUniform(ShaderProgram* p, const std::string& name, const glm::vec4& m) override;
void setUniform(ShaderProgram* p, const std::string& name, const glm::vec3& m) override;
void setUniform(ShaderProgram* p, const std::string& name, const glm::vec2& m) override;
void setUniform(ShaderProgram* p, const std::string& name, float f) override;
void useProgram(ShaderProgram* p) override;
ShaderProgram* createShader(const std::string& vert,
const std::string& frag) override;
void setProgramBlockBinding(ShaderProgram* p, const std::string& name,
GLint point) override;
void setUniformTexture(ShaderProgram* p, const std::string& name,
GLint tex) override;
void setUniform(ShaderProgram* p, const std::string& name,
const glm::mat4& m) override;
void setUniform(ShaderProgram* p, const std::string& name,
const glm::vec4& m) override;
void setUniform(ShaderProgram* p, const std::string& name,
const glm::vec3& m) override;
void setUniform(ShaderProgram* p, const std::string& name,
const glm::vec2& m) override;
void setUniform(ShaderProgram* p, const std::string& name,
float f) override;
void useProgram(ShaderProgram* p) override;
void clear(const glm::vec4 &colour, bool clearColour, bool clearDepth) override;
void clear(const glm::vec4& colour, bool clearColour,
bool clearDepth) override;
void setSceneParameters(const SceneUniformData &data) override;
void setSceneParameters(const SceneUniformData& data) override;
void setDrawState(const glm::mat4& model, DrawBuffer* draw, const DrawParameters& p);
void setDrawState(const glm::mat4& model, DrawBuffer* draw,
const DrawParameters& p);
void draw(const glm::mat4& model, DrawBuffer* draw, const DrawParameters& p) override;
void drawArrays(const glm::mat4& model, DrawBuffer* draw, const DrawParameters& p) override;
void draw(const glm::mat4& model, DrawBuffer* draw,
const DrawParameters& p) override;
void drawArrays(const glm::mat4& model, DrawBuffer* draw,
const DrawParameters& p) override;
void drawBatched(const RenderList& list) override;
void drawBatched(const RenderList& list) override;
void invalidate() override;
void invalidate() override;
virtual void pushDebugGroup(const std::string& title) override;
virtual const ProfileInfo& popDebugGroup() override;
virtual void pushDebugGroup(const std::string& title) override;
virtual const ProfileInfo& popDebugGroup() override;
private:
DrawBuffer* currentDbuff;
DrawBuffer* currentDbuff;
void useDrawBuffer(DrawBuffer* dbuff);
void useDrawBuffer(DrawBuffer* dbuff);
std::map<GLuint,GLuint> currentTextures;
void useTexture(GLuint unit, GLuint tex);
std::map<GLuint, GLuint> currentTextures;
void useTexture(GLuint unit, GLuint tex);
OpenGLShaderProgram* currentProgram;
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 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);
#if RW_PROFILER
if( currentDebugDepth > 0 )
{
profileInfo[currentDebugDepth-1].uploads++;
}
if (currentDebugDepth > 0) {
profileInfo[currentDebugDepth - 1].uploads++;
}
#endif
}
}
GLuint UBOObject;
GLuint maxObjectEntries;
GLuint currentObjectEntry;
GLuint entryAlignment;
GLuint UBOScene;
GLuint UBOObject;
GLuint maxObjectEntries;
GLuint currentObjectEntry;
GLuint entryAlignment;
GLuint UBOScene;
// State Cache
bool blendEnabled;
bool depthWriteEnabled;
// State Cache
bool blendEnabled;
bool depthWriteEnabled;
// Set state
void setBlend(bool enable)
{
RW_UNUSED(enable);
// Set state
void setBlend(bool enable) {
RW_UNUSED(enable);
/// @todo set blendEnabled, currently not possible because other functions keep trashing the state
/// @todo set blendEnabled, currently not possible because other functions keep
/// trashing the state
#if 0
if (enable && !blendEnabled) {
glEnable(GL_BLEND);
@ -326,29 +337,27 @@ private:
blendEnabled = enable;
}
#else
glEnable(GL_BLEND);
glEnable(GL_BLEND);
#endif
}
}
void setDepthWrite(bool enable)
{
if (enable != depthWriteEnabled) {
glDepthMask(enable ? GL_TRUE : GL_FALSE);
depthWriteEnabled = enable;
}
}
void setDepthWrite(bool enable) {
if (enable != depthWriteEnabled) {
glDepthMask(enable ? GL_TRUE : GL_FALSE);
depthWriteEnabled = enable;
}
}
// Debug group profiling timers
ProfileInfo profileInfo[MAX_DEBUG_DEPTH];
GLuint debugQuery;
int currentDebugDepth;
// Debug group profiling timers
ProfileInfo profileInfo[MAX_DEBUG_DEPTH];
GLuint debugQuery;
int currentDebugDepth;
};
/// @todo remove these from here
GLuint compileShader(GLenum type, const char *source);
GLuint compileShader(GLenum type, const char* source);
GLuint compileProgram(const char* vertex, const char* fragment);
typedef Renderer::RenderList RenderList;
#endif

View File

@ -1,28 +1,24 @@
#include "render/TextRenderer.hpp"
#include <render/GameRenderer.hpp>
#include <engine/GameWorld.hpp>
#include <render/GameRenderer.hpp>
#include <algorithm>
#include <cctype>
int charToIndex(uint16_t g)
{
// Correct for the default font maps
/// @todo confirm for JA / RU font maps
return g - 32;
int charToIndex(uint16_t g) {
// Correct for the default font maps
/// @todo confirm for JA / RU font maps
return g - 32;
}
glm::vec4 indexToCoord(int font, int index)
{
float x = int(index % 16);
float y = int(index / 16) + 0.01f;
float fontHeight = ((font == 0) ? 16.f : 13.f);
glm::vec2 gsize( 1.f / 16.f, 1.f / fontHeight );
return glm::vec4( x, y, x + 1, y + 0.98f ) *
glm::vec4( gsize, gsize );
glm::vec4 indexToCoord(int font, int index) {
float x = int(index % 16);
float y = int(index / 16) + 0.01f;
float fontHeight = ((font == 0) ? 16.f : 13.f);
glm::vec2 gsize(1.f / 16.f, 1.f / fontHeight);
return glm::vec4(x, y, x + 1, y + 0.98f) * glm::vec4(gsize, gsize);
}
const char* TextVertexShader = R"(
#version 330
@ -57,264 +53,242 @@ void main()
outColour = vec4(Colour, a);
})";
struct TextVertex
{
glm::vec2 position;
glm::vec2 texcoord;
glm::vec3 colour;
static const AttributeList vertex_attributes() {
return {
{ATRS_Position, 2, sizeof(TextVertex), 0ul},
{ATRS_TexCoord, 2, sizeof(TextVertex), 0ul + sizeof(glm::vec2)},
{ATRS_Colour, 3, sizeof(TextVertex), 0ul + sizeof(glm::vec2) * 2},
};
}
struct TextVertex {
glm::vec2 position;
glm::vec2 texcoord;
glm::vec3 colour;
static const AttributeList vertex_attributes() {
return {
{ATRS_Position, 2, sizeof(TextVertex), 0ul},
{ATRS_TexCoord, 2, sizeof(TextVertex), 0ul + sizeof(glm::vec2)},
{ATRS_Colour, 3, sizeof(TextVertex), 0ul + sizeof(glm::vec2) * 2},
};
}
};
TextRenderer::TextInfo::TextInfo()
: font(0), size(1.f), baseColour({1.f, 1.f, 1.f}), align(Left), wrapX(0)
{
: font(0), size(1.f), baseColour({1.f, 1.f, 1.f}), align(Left), wrapX(0) {
}
TextRenderer::TextRenderer(GameRenderer* renderer)
: renderer(renderer)
{
textShader = renderer->getRenderer()->createShader(
TextVertexShader, TextFragmentShader );
for( int g = 0; g < GAME_GLYPHS; g++ )
{
glyphData[g] = { .9f };
}
glyphData[charToIndex(' ')].widthFrac = 0.4f;
glyphData[charToIndex('-')].widthFrac = 0.5f;
glyphData[charToIndex('\'')].widthFrac = 0.5f;
glyphData[charToIndex('(')].widthFrac = 0.45f;
glyphData[charToIndex(')')].widthFrac = 0.45f;
glyphData[charToIndex(':')].widthFrac = 0.65f;
glyphData[charToIndex('$')].widthFrac = 0.65f;
TextRenderer::TextRenderer(GameRenderer* renderer) : renderer(renderer) {
textShader = renderer->getRenderer()->createShader(TextVertexShader,
TextFragmentShader);
for(char g = '0'; g <= '9'; ++g) {
glyphData[charToIndex(g)].widthFrac = 0.65f;
}
for (int g = 0; g < GAME_GLYPHS; g++) {
glyphData[g] = {.9f};
}
// Assumes contigious a-z character encoding
for(char g = 0; g <= ('z'-'a'); g++)
{
switch( ('a' + g) )
{
case 'i':
glyphData[charToIndex('a' + g)].widthFrac = 0.4f;
glyphData[charToIndex('A' + g)].widthFrac = 0.4f;
break;
case 'l':
glyphData[charToIndex('a' + g)].widthFrac = 0.5f;
glyphData[charToIndex('A' + g)].widthFrac = 0.5f;
break;
case 'm':
glyphData[charToIndex('a' + g)].widthFrac = 1.0f;
glyphData[charToIndex('A' + g)].widthFrac = 1.0f;
break;
case 'w':
glyphData[charToIndex('a' + g)].widthFrac = 1.0f;
glyphData[charToIndex('A' + g)].widthFrac = 1.0f;
break;
default:
glyphData[charToIndex('a' + g)].widthFrac = 0.7f;
glyphData[charToIndex('A' + g)].widthFrac = 0.7f;
break;
}
}
glyphData[charToIndex(' ')].widthFrac = 0.4f;
glyphData[charToIndex('-')].widthFrac = 0.5f;
glyphData[charToIndex('\'')].widthFrac = 0.5f;
glyphData[charToIndex('(')].widthFrac = 0.45f;
glyphData[charToIndex(')')].widthFrac = 0.45f;
glyphData[charToIndex(':')].widthFrac = 0.65f;
glyphData[charToIndex('$')].widthFrac = 0.65f;
for (char g = '0'; g <= '9'; ++g) {
glyphData[charToIndex(g)].widthFrac = 0.65f;
}
// Assumes contigious a-z character encoding
for (char g = 0; g <= ('z' - 'a'); g++) {
switch (('a' + g)) {
case 'i':
glyphData[charToIndex('a' + g)].widthFrac = 0.4f;
glyphData[charToIndex('A' + g)].widthFrac = 0.4f;
break;
case 'l':
glyphData[charToIndex('a' + g)].widthFrac = 0.5f;
glyphData[charToIndex('A' + g)].widthFrac = 0.5f;
break;
case 'm':
glyphData[charToIndex('a' + g)].widthFrac = 1.0f;
glyphData[charToIndex('A' + g)].widthFrac = 1.0f;
break;
case 'w':
glyphData[charToIndex('a' + g)].widthFrac = 1.0f;
glyphData[charToIndex('A' + g)].widthFrac = 1.0f;
break;
default:
glyphData[charToIndex('a' + g)].widthFrac = 0.7f;
glyphData[charToIndex('A' + g)].widthFrac = 0.7f;
break;
}
}
}
TextRenderer::~TextRenderer()
{
TextRenderer::~TextRenderer() {
}
void TextRenderer::setFontTexture(int index, const std::string& texture)
{
if( index < GAME_FONTS )
{
fonts[index] = texture;
}
void TextRenderer::setFontTexture(int index, const std::string& texture) {
if (index < GAME_FONTS) {
fonts[index] = texture;
}
}
void TextRenderer::renderText(const TextRenderer::TextInfo& ti, bool forceColour)
{
renderer->getRenderer()->pushDebugGroup("Text");
renderer->getRenderer()->useProgram(textShader);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glActiveTexture(GL_TEXTURE0);
glm::vec2 coord( 0.f, 0.f );
glm::vec2 alignment = ti.screenPosition;
// We should track real size not just chars.
auto lineLength = 0;
glm::vec2 ss( ti.size );
void TextRenderer::renderText(const TextRenderer::TextInfo& ti,
bool forceColour) {
renderer->getRenderer()->pushDebugGroup("Text");
renderer->getRenderer()->useProgram(textShader);
glm::vec3 colour = glm::vec3(ti.baseColour) * (1/255.f);
glm::vec4 colourBG = glm::vec4(ti.backgroundColour) * (1/255.f);
std::vector<TextVertex> geo;
float maxWidth = 0.f;
float maxHeight = 0.f;
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glActiveTexture(GL_TEXTURE0);
auto text = ti.text;
for (size_t i = 0; i < text.length(); ++i)
{
char16_t c = text[i];
glm::vec2 coord(0.f, 0.f);
glm::vec2 alignment = ti.screenPosition;
// We should track real size not just chars.
auto lineLength = 0;
// Handle any markup changes.
if( c == '~' && text.length() > i + 1 )
{
switch( text[i+1] )
{
case 'g': // Green
text.erase(text.begin()+i, text.begin()+i+3);
colour = glm::vec3(glm::u8vec3(90, 157, 102)) * (1/255.f);
break;
case 'h': // White
text.erase(text.begin()+i, text.begin()+i+3);
colour = glm::vec3(1.f); /// @todo FIXME! Use proper colour!
break;
case 'k': { // Key
text.erase(text.begin()+i, text.begin()+i+3);
// Extract the key name from the /next/ markup
auto keyend = text.find('~', i+1);
auto keyname = text.substr(i+1, keyend-i-1);
// Since we don't have a key map yet, just print out the name
text.erase(text.begin()+i, text.begin()+keyend);
text.insert(i, keyname);
break;
}
case 'l': // Black
text.erase(text.begin()+i, text.begin()+i+3);
colour = glm::vec3(0.f); /// @todo FIXME! Use proper colour!
break;
case 'r': // Red
text.erase(text.begin()+i, text.begin()+i+3);
colour = glm::vec3(1.f, 0.0f, 0.0f); /// @todo FIXME! Use proper colour!
break;
case 'w': // Gray
text.erase(text.begin()+i, text.begin()+i+3);
colour = glm::vec3(0.5f); /// @todo FIXME! Use proper colour!
break;
case 'y': // Yellow
text.erase(text.begin()+i, text.begin()+i+3);
colour = glm::vec3(1.0f, 1.0f, 0.0f); /// @todo FIXME! Use proper colour!
break;
}
c = text[i];
}
glm::vec2 ss(ti.size);
if (forceColour) {
colour = glm::vec3(ti.baseColour) * (1/255.f);
}
int glyph = charToIndex(c);
if( glyph >= GAME_GLYPHS )
{
continue;
}
glm::vec3 colour = glm::vec3(ti.baseColour) * (1 / 255.f);
glm::vec4 colourBG = glm::vec4(ti.backgroundColour) * (1 / 255.f);
std::vector<TextVertex> geo;
// If we're not at the start of the column, check if the current word
// will need to be wrapped
if (ti.wrapX > 0 && coord.x > 0.f && !std::isspace(c))
{
auto wend = std::find_if(std::begin(text)+i,
std::end(text),
[](char x) { return std::isspace(x); });
if (wend != std::end(text))
{
auto word = std::distance(std::begin(text)+i, wend);
if (lineLength + word >= ti.wrapX)
{
coord.x = 0;
coord.y += ss.y;
maxHeight = coord.y + ss.y;
lineLength = 0;
}
}
}
auto& data = glyphData[glyph];
auto tex = indexToCoord(ti.font, glyph);
ss.x = ti.size * data.widthFrac;
tex.z = tex.x + (tex.z - tex.x) * data.widthFrac;
// Handle special chars.
if( c == '\n' )
{
coord.x = 0.f;
coord.y += ss.y;
maxHeight = coord.y + ss.y;
lineLength = 0;
continue;
}
lineLength ++;
float maxWidth = 0.f;
float maxHeight = 0.f;
glm::vec2 p = coord;
coord.x += ss.x;
maxWidth = std::max(coord.x, maxWidth);
geo.push_back({ { p.x, p.y + ss.y }, {tex.x, tex.w}, colour });
geo.push_back({ { p.x + ss.x, p.y + ss.y }, {tex.z, tex.w}, colour });
geo.push_back({ { p.x, p.y }, {tex.x, tex.y}, colour });
geo.push_back({ { p.x + ss.x, p.y }, {tex.z, tex.y}, colour });
geo.push_back({ { p.x, p.y }, {tex.x, tex.y}, colour });
geo.push_back({ { p.x + ss.x, p.y + ss.y }, {tex.z, tex.w}, colour });
}
if ( ti.align == TextInfo::Right )
{
alignment.x -= maxWidth;
}
else if ( ti.align == TextInfo::Center )
{
alignment.x -= (maxWidth / 2.f);
}
auto text = ti.text;
alignment.y -= ti.size * 0.2f;
for (size_t i = 0; i < text.length(); ++i) {
char16_t c = text[i];
// If we need to, draw the background.
if (colourBG.a > 0.f)
{
renderer->drawColour(
colourBG,
glm::vec4(
ti.screenPosition - (ss/3.f),
glm::vec2(maxWidth, maxHeight)+(ss/2.f)));
// Handle any markup changes.
if (c == '~' && text.length() > i + 1) {
switch (text[i + 1]) {
case 'g': // Green
text.erase(text.begin() + i, text.begin() + i + 3);
colour = glm::vec3(glm::u8vec3(90, 157, 102)) * (1 / 255.f);
break;
case 'h': // White
text.erase(text.begin() + i, text.begin() + i + 3);
colour =
glm::vec3(1.f); /// @todo FIXME! Use proper colour!
break;
case 'k': { // Key
text.erase(text.begin() + i, text.begin() + i + 3);
// Extract the key name from the /next/ markup
auto keyend = text.find('~', i + 1);
auto keyname = text.substr(i + 1, keyend - i - 1);
// Since we don't have a key map yet, just print out the
// name
text.erase(text.begin() + i, text.begin() + keyend);
text.insert(i, keyname);
break;
}
case 'l': // Black
text.erase(text.begin() + i, text.begin() + i + 3);
colour =
glm::vec3(0.f); /// @todo FIXME! Use proper colour!
break;
case 'r': // Red
text.erase(text.begin() + i, text.begin() + i + 3);
colour = glm::vec3(
1.f, 0.0f, 0.0f); /// @todo FIXME! Use proper colour!
break;
case 'w': // Gray
text.erase(text.begin() + i, text.begin() + i + 3);
colour =
glm::vec3(0.5f); /// @todo FIXME! Use proper colour!
break;
case 'y': // Yellow
text.erase(text.begin() + i, text.begin() + i + 3);
colour = glm::vec3(
1.0f, 1.0f, 0.0f); /// @todo FIXME! Use proper colour!
break;
}
}
renderer->getRenderer()->setUniform(textShader, "proj", renderer->getRenderer()->get2DProjection());
renderer->getRenderer()->setUniformTexture(textShader, "fontTexture", 0);
renderer->getRenderer()->setUniform(textShader, "alignment", alignment);
gb.uploadVertices(geo);
db.addGeometry(&gb);
db.setFaceType(GL_TRIANGLES);
Renderer::DrawParameters dp;
dp.start = 0;
dp.count = gb.getCount();
auto ftexture = renderer->getData()->findTexture(fonts[ti.font]);
dp.textures = {ftexture->getName()};
dp.depthWrite = false;
renderer->getRenderer()->drawArrays(glm::mat4(), &db, dp);
c = text[i];
}
renderer->getRenderer()->popDebugGroup();
if (forceColour) {
colour = glm::vec3(ti.baseColour) * (1 / 255.f);
}
int glyph = charToIndex(c);
if (glyph >= GAME_GLYPHS) {
continue;
}
// If we're not at the start of the column, check if the current word
// will need to be wrapped
if (ti.wrapX > 0 && coord.x > 0.f && !std::isspace(c)) {
auto wend = std::find_if(std::begin(text) + i, std::end(text),
[](char x) { return std::isspace(x); });
if (wend != std::end(text)) {
auto word = std::distance(std::begin(text) + i, wend);
if (lineLength + word >= ti.wrapX) {
coord.x = 0;
coord.y += ss.y;
maxHeight = coord.y + ss.y;
lineLength = 0;
}
}
}
auto& data = glyphData[glyph];
auto tex = indexToCoord(ti.font, glyph);
ss.x = ti.size * data.widthFrac;
tex.z = tex.x + (tex.z - tex.x) * data.widthFrac;
// Handle special chars.
if (c == '\n') {
coord.x = 0.f;
coord.y += ss.y;
maxHeight = coord.y + ss.y;
lineLength = 0;
continue;
}
lineLength++;
glm::vec2 p = coord;
coord.x += ss.x;
maxWidth = std::max(coord.x, maxWidth);
geo.push_back({{p.x, p.y + ss.y}, {tex.x, tex.w}, colour});
geo.push_back({{p.x + ss.x, p.y + ss.y}, {tex.z, tex.w}, colour});
geo.push_back({{p.x, p.y}, {tex.x, tex.y}, colour});
geo.push_back({{p.x + ss.x, p.y}, {tex.z, tex.y}, colour});
geo.push_back({{p.x, p.y}, {tex.x, tex.y}, colour});
geo.push_back({{p.x + ss.x, p.y + ss.y}, {tex.z, tex.w}, colour});
}
if (ti.align == TextInfo::Right) {
alignment.x -= maxWidth;
} else if (ti.align == TextInfo::Center) {
alignment.x -= (maxWidth / 2.f);
}
alignment.y -= ti.size * 0.2f;
// If we need to, draw the background.
if (colourBG.a > 0.f) {
renderer->drawColour(
colourBG, glm::vec4(ti.screenPosition - (ss / 3.f),
glm::vec2(maxWidth, maxHeight) + (ss / 2.f)));
}
renderer->getRenderer()->setUniform(
textShader, "proj", renderer->getRenderer()->get2DProjection());
renderer->getRenderer()->setUniformTexture(textShader, "fontTexture", 0);
renderer->getRenderer()->setUniform(textShader, "alignment", alignment);
gb.uploadVertices(geo);
db.addGeometry(&gb);
db.setFaceType(GL_TRIANGLES);
Renderer::DrawParameters dp;
dp.start = 0;
dp.count = gb.getCount();
auto ftexture = renderer->getData()->findTexture(fonts[ti.font]);
dp.textures = {ftexture->getName()};
dp.depthWrite = false;
renderer->getRenderer()->drawArrays(glm::mat4(), &db, dp);
renderer->getRenderer()->popDebugGroup();
}

View File

@ -9,69 +9,60 @@
class GameRenderer;
/**
* @brief Handles rendering of bitmap font textures.
*
*
* In future, strings textures might be cached to improve performance, but
* for now, we just render each glyph on it's own quad
*/
class TextRenderer
{
class TextRenderer {
public:
/**
* @todo Can this be merged with the gamestate text entries?
*/
struct TextInfo
{
enum TextAlignemnt
{
Left = 0,
Right = 1,
Center = 2
};
/// Font index @see TextRenderer::setFontTexture
int font;
/// Message to be displayed (including markup)
GameString text;
/// On screen position
glm::vec2 screenPosition;
/// font size
float size;
/// Base colour
glm::u8vec3 baseColour;
/// Background colour
glm::u8vec4 backgroundColour;
/// Horizontal Alignment
TextAlignemnt align;
/// Wrap width
int wrapX;
/**
* @todo Can this be merged with the gamestate text entries?
*/
struct TextInfo {
enum TextAlignemnt { Left = 0, Right = 1, Center = 2 };
/// Font index @see TextRenderer::setFontTexture
int font;
/// Message to be displayed (including markup)
GameString text;
/// On screen position
glm::vec2 screenPosition;
/// font size
float size;
/// Base colour
glm::u8vec3 baseColour;
/// Background colour
glm::u8vec4 backgroundColour;
/// Horizontal Alignment
TextAlignemnt align;
/// Wrap width
int wrapX;
TextInfo();
};
/**
* Stores the information for kerning a glyph
*/
struct GlyphInfo {
float widthFrac;
};
TextRenderer(GameRenderer* renderer);
~TextRenderer();
void setFontTexture(int index, const std::string& font);
void renderText(const TextInfo& ti, bool forceColour = false);
TextInfo();
};
/**
* Stores the information for kerning a glyph
*/
struct GlyphInfo
{
float widthFrac;
};
TextRenderer(GameRenderer* renderer);
~TextRenderer();
void setFontTexture( int index, const std::string& font );
void renderText( const TextInfo& ti, bool forceColour = false );
private:
std::string fonts[GAME_FONTS];
GlyphInfo glyphData[GAME_GLYPHS];
std::string fonts[GAME_FONTS];
GlyphInfo glyphData[GAME_GLYPHS];
GameRenderer* renderer;
Renderer::ShaderProgram* textShader;
GeometryBuffer gb;
DrawBuffer db;
GameRenderer* renderer;
Renderer::ShaderProgram* textShader;
GeometryBuffer gb;
DrawBuffer db;
};
#endif

View File

@ -1,31 +1,26 @@
#ifndef _VIEWCAMERA_HPP_
#define _VIEWCAMERA_HPP_
#include "ViewFrustum.hpp"
#include <glm/gtc/quaternion.hpp>
#include "ViewFrustum.hpp"
class ViewCamera
{
class ViewCamera {
public:
ViewFrustum frustum;
glm::vec3 position;
glm::quat rotation;
ViewFrustum frustum;
ViewCamera(const glm::vec3& pos = {}, const glm::quat& rot = {})
: frustum({0.1f, 5000.f, glm::radians(45.f), 1.f}),
position(pos), rotation(rot)
{
}
glm::vec3 position;
glm::quat rotation;
glm::mat4 getView()
{
auto up = rotation * glm::vec3(0.f, 0.f, 1.f);
return glm::lookAt(position,
position + rotation * glm::vec3(1.f, 0.f, 0.f),
up);
}
ViewCamera(const glm::vec3& pos = {}, const glm::quat& rot = {})
: frustum({0.1f, 5000.f, glm::radians(45.f), 1.f})
, position(pos)
, rotation(rot) {
}
glm::mat4 getView() {
auto up = rotation * glm::vec3(0.f, 0.f, 1.f);
return glm::lookAt(position,
position + rotation * glm::vec3(1.f, 0.f, 0.f), up);
}
};
#endif

View File

@ -6,65 +6,55 @@
#include <rw_mingw.hpp>
#endif
class ViewFrustum
{
class ViewFrustum {
public:
class ViewPlane
{
public:
glm::vec3 normal;
float distance;
};
float near;
float far;
float fov;
float aspectRatio;
class ViewPlane {
public:
glm::vec3 normal;
float distance;
};
ViewPlane planes[6];
ViewFrustum(float near, float far, float fov, float aspect)
: near(near), far(far), fov(fov), aspectRatio(aspect)
{
}
glm::mat4 projection()
{
return glm::perspective(fov / aspectRatio, aspectRatio, near, far);
}
void update(const glm::mat4& proj)
{
for(size_t i = 0; i < 6; ++i)
{
float sign = (i%2==0) ? 1.f : -1.f;
int r = i / 2;
planes[i].normal.x = proj[0][3] + proj[0][r] * sign;
planes[i].normal.y = proj[1][3] + proj[1][r] * sign;
planes[i].normal.z = proj[2][3] + proj[2][r] * sign;
planes[i].distance = proj[3][3] + proj[3][r] * sign;
auto l = glm::length(planes[i].normal);
planes[i].normal /= l;
planes[i].distance /= l;
}
}
bool intersects(glm::vec3 center, float radius) const
{
float d;
bool result = true;
float near;
float far;
float fov;
float aspectRatio;
for(size_t i = 0; i < 6; ++i)
{
d = glm::dot(planes[i].normal, center) + planes[i].distance;
if( d < -radius ) result = false;
}
ViewPlane planes[6];
return result;
}
ViewFrustum(float near, float far, float fov, float aspect)
: near(near), far(far), fov(fov), aspectRatio(aspect) {
}
glm::mat4 projection() {
return glm::perspective(fov / aspectRatio, aspectRatio, near, far);
}
void update(const glm::mat4& proj) {
for (size_t i = 0; i < 6; ++i) {
float sign = (i % 2 == 0) ? 1.f : -1.f;
int r = i / 2;
planes[i].normal.x = proj[0][3] + proj[0][r] * sign;
planes[i].normal.y = proj[1][3] + proj[1][r] * sign;
planes[i].normal.z = proj[2][3] + proj[2][r] * sign;
planes[i].distance = proj[3][3] + proj[3][r] * sign;
auto l = glm::length(planes[i].normal);
planes[i].normal /= l;
planes[i].distance /= l;
}
}
bool intersects(glm::vec3 center, float radius) const {
float d;
bool result = true;
for (size_t i = 0; i < 6; ++i) {
d = glm::dot(planes[i].normal, center) + planes[i].distance;
if (d < -radius) result = false;
}
return result;
}
};
#endif

View File

@ -2,63 +2,49 @@
#include <memory>
VisualFX::LightData::~LightData()
{
VisualFX::LightData::~LightData() {
}
VisualFX::ParticleData::~ParticleData()
{
VisualFX::ParticleData::~ParticleData() {
}
VisualFX::TrailData::~TrailData()
{
VisualFX::TrailData::~TrailData() {
}
VisualFX::VisualFX(VisualFX::EffectType type)
: type(type)
{
switch( type )
{
case VisualFX::Light:
new (&light) LightData;
break;
case VisualFX::Particle:
new (&particle) ParticleData;
break;
case VisualFX::Trail:
new (&trail) TrailData;
break;
}
VisualFX::VisualFX(VisualFX::EffectType type) : type(type) {
switch (type) {
case VisualFX::Light:
new (&light) LightData;
break;
case VisualFX::Particle:
new (&particle) ParticleData;
break;
case VisualFX::Trail:
new (&trail) TrailData;
break;
}
}
VisualFX::~VisualFX()
{
switch( type )
{
case VisualFX::Light:
light.~LightData();
break;
case VisualFX::Particle:
particle.~ParticleData();
break;
case VisualFX::Trail:
trail.~TrailData();
break;
}
VisualFX::~VisualFX() {
switch (type) {
case VisualFX::Light:
light.~LightData();
break;
case VisualFX::Particle:
particle.~ParticleData();
break;
case VisualFX::Trail:
trail.~TrailData();
break;
}
}
const glm::vec3& VisualFX::getPosition() const
{
static glm::vec3 errorRef;
switch( type )
{
case VisualFX::Particle:
return particle.position;
default:
return errorRef;
}
const glm::vec3& VisualFX::getPosition() const {
static glm::vec3 errorRef;
switch (type) {
case VisualFX::Particle:
return particle.position;
default:
return errorRef;
}
}

View File

@ -1,83 +1,82 @@
#pragma once
#include <glm/glm.hpp>
#include <gl/TextureData.hpp>
#include <glm/glm.hpp>
/**
* Represents a scene effect: lighting, particles etc.
*/
class VisualFX
{
class VisualFX {
public:
enum EffectType
{
Light,
Particle,
Trail
};
struct LightData
{
~LightData();
};
struct ParticleData
{
/** Initial world position */
glm::vec3 position;
enum EffectType { Light, Particle, Trail };
/** Direction of particle */
glm::vec3 direction;
struct LightData {
~LightData();
};
struct ParticleData {
/** Initial world position */
glm::vec3 position;
/** Particle orientation modes */
enum Orientation {
Free, /** faces direction using up */
Camera, /** Faces towards the camera @todo implement */
UpCamera /** Face closes point in camera's look direction */
};
Orientation orientation;
/** Direction of particle */
glm::vec3 direction;
/** Game time at particle instantiation */
float starttime;
/** Number of seconds particle should exist for, negative values = forever */
float lifetime;
/** Particle orientation modes */
enum Orientation {
Free, /** faces direction using up */
Camera, /** Faces towards the camera @todo implement */
UpCamera /** Face closes point in camera's look direction */
};
Orientation orientation;
/** Texture name */
TextureData::Handle texture;
/** Game time at particle instantiation */
float starttime;
/** Number of seconds particle should exist for, negative values =
* forever */
float lifetime;
/** Size of particle */
glm::vec2 size;
/** Texture name */
TextureData::Handle texture;
/** Up direction (only used in Free mode) */
glm::vec3 up;
/** Size of particle */
glm::vec2 size;
/** Render tint colour */
glm::vec4 colour;
/** Up direction (only used in Free mode) */
glm::vec3 up;
/** Render tint colour */
glm::vec4 colour;
/** Constructs a particle */
ParticleData()
: orientation(Free)
, starttime(0.f)
, lifetime(-1.f)
, size(1.f, 1.f)
, up(0.f, 0.f, 1.f)
, colour(1.f, 1.f, 1.f, 1.f) {
}
~ParticleData();
};
struct TrailData {
~TrailData();
};
/// @todo stop abusing unions
union {
LightData light;
ParticleData particle;
TrailData trail;
};
VisualFX(EffectType type);
~VisualFX();
EffectType getType() const {
return type;
}
const glm::vec3& getPosition() const;
/** Constructs a particle */
ParticleData()
: orientation(Free), starttime(0.f), lifetime(-1.f), size(1.f, 1.f),
up(0.f, 0.f, 1.f), colour(1.f, 1.f, 1.f, 1.f) { }
~ParticleData();
};
struct TrailData
{
~TrailData();
};
/// @todo stop abusing unions
union {
LightData light;
ParticleData particle;
TrailData trail;
};
VisualFX(EffectType type);
~VisualFX();
EffectType getType() const { return type; }
const glm::vec3& getPosition() const;
private:
EffectType type;
EffectType type;
};

View File

@ -1,162 +1,151 @@
#include <render/WaterRenderer.hpp>
#include <engine/GameWorld.hpp>
#include <render/GameRenderer.hpp>
#include <render/GameShaders.hpp>
#include <engine/GameWorld.hpp>
#include <render/WaterRenderer.hpp>
#include <glm/glm.hpp>
WaterRenderer::WaterRenderer(GameRenderer* renderer)
: waterProg(nullptr)
{
maskDraw.setFaceType(GL_TRIANGLES);
gridDraw.setFaceType(GL_TRIANGLES);
waterProg = renderer->getRenderer()->createShader(
GameShaders::WaterHQ::VertexShader, GameShaders::WaterHQ::FragmentShader
);
maskProg = renderer->getRenderer()->createShader(
GameShaders::Mask3D::VertexShader, GameShaders::Mask3D::FragmentShader
);
renderer->getRenderer()->setProgramBlockBinding(waterProg, "SceneData", 1);
renderer->getRenderer()->setProgramBlockBinding(maskProg, "SceneData", 1);
renderer->getRenderer()->setUniformTexture(waterProg, "data", 1);
WaterRenderer::WaterRenderer(GameRenderer* renderer) : waterProg(nullptr) {
maskDraw.setFaceType(GL_TRIANGLES);
gridDraw.setFaceType(GL_TRIANGLES);
// Generate grid mesh
int gridres = 60;
std::vector<glm::vec2> grid;
float gridresinv = 1.f / (gridres*0.5f);
glm::vec2 b(-1.f,-1.f);
for( int x = 0; x < gridres; x++ )
{
for( int y = 0; y < gridres; y++ )
{
glm::vec2 tMin( b + glm::vec2(x,y) * gridresinv );
glm::vec2 tMax( b + glm::vec2(x+1,y+1) * gridresinv );
// Build geometry
grid.push_back(glm::vec2(tMax.x, tMax.y));
grid.push_back(glm::vec2(tMax.x, tMin.y));
grid.push_back(glm::vec2(tMin.x, tMin.y));
grid.push_back(glm::vec2(tMin.x, tMin.y));
grid.push_back(glm::vec2(tMin.x, tMax.y));
grid.push_back(glm::vec2(tMax.x, tMax.y));
}
}
gridGeom.uploadVertices(grid.size(), sizeof(glm::vec2)*grid.size(), grid.data());
gridGeom.getDataAttributes().push_back(
{ATRS_Position, 2, 0, 0, GL_FLOAT}
);
gridDraw.addGeometry(&gridGeom);
waterProg = renderer->getRenderer()->createShader(
GameShaders::WaterHQ::VertexShader,
GameShaders::WaterHQ::FragmentShader);
maskProg = renderer->getRenderer()->createShader(
GameShaders::Mask3D::VertexShader, GameShaders::Mask3D::FragmentShader);
renderer->getRenderer()->setProgramBlockBinding(waterProg, "SceneData", 1);
renderer->getRenderer()->setProgramBlockBinding(maskProg, "SceneData", 1);
renderer->getRenderer()->setUniformTexture(waterProg, "data", 1);
// Generate grid mesh
int gridres = 60;
std::vector<glm::vec2> grid;
float gridresinv = 1.f / (gridres * 0.5f);
glm::vec2 b(-1.f, -1.f);
for (int x = 0; x < gridres; x++) {
for (int y = 0; y < gridres; y++) {
glm::vec2 tMin(b + glm::vec2(x, y) * gridresinv);
glm::vec2 tMax(b + glm::vec2(x + 1, y + 1) * gridresinv);
// Build geometry
grid.push_back(glm::vec2(tMax.x, tMax.y));
grid.push_back(glm::vec2(tMax.x, tMin.y));
grid.push_back(glm::vec2(tMin.x, tMin.y));
grid.push_back(glm::vec2(tMin.x, tMin.y));
grid.push_back(glm::vec2(tMin.x, tMax.y));
grid.push_back(glm::vec2(tMax.x, tMax.y));
}
}
gridGeom.uploadVertices(grid.size(), sizeof(glm::vec2) * grid.size(),
grid.data());
gridGeom.getDataAttributes().push_back({ATRS_Position, 2, 0, 0, GL_FLOAT});
gridDraw.addGeometry(&gridGeom);
}
WaterRenderer::~WaterRenderer()
{
WaterRenderer::~WaterRenderer() {
}
void WaterRenderer::setWaterTable(float* waterHeights, unsigned int nHeights, uint8_t* tiles, unsigned int nTiles)
{
// Determine the dimensions of the input tiles
int edgeNum = sqrt(nTiles);
float tileSize = WATER_WORLD_SIZE/edgeNum;
glm::vec2 wO { -WATER_WORLD_SIZE/2.f, -WATER_WORLD_SIZE/2.f };
std::vector<glm::vec3> vertexData;
for( int x = 0; x < edgeNum; x++ )
{
int xi = x * WATER_HQ_DATA_SIZE;
for( int y = 0; y < edgeNum; y++ )
{
RW_CHECK (tiles[xi + y] < nHeights, "Tile index out of bounds");
if (tiles[xi+y] >= nHeights) continue;
void WaterRenderer::setWaterTable(float* waterHeights, unsigned int nHeights,
uint8_t* tiles, unsigned int nTiles) {
// Determine the dimensions of the input tiles
int edgeNum = sqrt(nTiles);
float tileSize = WATER_WORLD_SIZE / edgeNum;
glm::vec2 wO{-WATER_WORLD_SIZE / 2.f, -WATER_WORLD_SIZE / 2.f};
// Tiles with the magic value contain no water.
if( tiles[xi + y] >= NO_WATER_INDEX ) continue;
float h = waterHeights[tiles[xi + y]];
float hMax = h + WATER_HEIGHT;
glm::vec2 tMin( wO + glm::vec2(x,y) * tileSize );
glm::vec2 tMax( wO + glm::vec2(x+1,y+1) * tileSize );
// Build geometry
vertexData.push_back(glm::vec3(tMax.x, tMax.y, hMax));
vertexData.push_back(glm::vec3(tMax.x, tMin.y, hMax));
vertexData.push_back(glm::vec3(tMin.x, tMin.y, hMax));
vertexData.push_back(glm::vec3(tMin.x, tMin.y, hMax));
vertexData.push_back(glm::vec3(tMin.x, tMax.y, hMax));
vertexData.push_back(glm::vec3(tMax.x, tMax.y, hMax));
}
}
maskGeom.uploadVertices(vertexData.size(), sizeof(glm::vec3)*vertexData.size(), vertexData.data());
maskGeom.getDataAttributes().push_back(
{ATRS_Position, 3, 0, 0, GL_FLOAT}
);
maskDraw.addGeometry(&maskGeom);
std::vector<glm::vec3> vertexData;
for (int x = 0; x < edgeNum; x++) {
int xi = x * WATER_HQ_DATA_SIZE;
for (int y = 0; y < edgeNum; y++) {
RW_CHECK(tiles[xi + y] < nHeights, "Tile index out of bounds");
if (tiles[xi + y] >= nHeights) continue;
// Tiles with the magic value contain no water.
if (tiles[xi + y] >= NO_WATER_INDEX) continue;
float h = waterHeights[tiles[xi + y]];
float hMax = h + WATER_HEIGHT;
glm::vec2 tMin(wO + glm::vec2(x, y) * tileSize);
glm::vec2 tMax(wO + glm::vec2(x + 1, y + 1) * tileSize);
// Build geometry
vertexData.push_back(glm::vec3(tMax.x, tMax.y, hMax));
vertexData.push_back(glm::vec3(tMax.x, tMin.y, hMax));
vertexData.push_back(glm::vec3(tMin.x, tMin.y, hMax));
vertexData.push_back(glm::vec3(tMin.x, tMin.y, hMax));
vertexData.push_back(glm::vec3(tMin.x, tMax.y, hMax));
vertexData.push_back(glm::vec3(tMax.x, tMax.y, hMax));
}
}
maskGeom.uploadVertices(vertexData.size(),
sizeof(glm::vec3) * vertexData.size(),
vertexData.data());
maskGeom.getDataAttributes().push_back({ATRS_Position, 3, 0, 0, GL_FLOAT});
maskDraw.addGeometry(&maskGeom);
}
void WaterRenderer::setDataTexture(GLuint fbBinding, GLuint dataTex)
{
fbOutput = fbBinding;
dataTexture = dataTex;
void WaterRenderer::setDataTexture(GLuint fbBinding, GLuint dataTex) {
fbOutput = fbBinding;
dataTexture = dataTex;
}
void WaterRenderer::render(GameRenderer* renderer, GameWorld* world)
{
auto r = renderer->getRenderer();
void WaterRenderer::render(GameRenderer* renderer, GameWorld* world) {
auto r = renderer->getRenderer();
auto waterTex = world->data->findTexture("water_old");
RW_CHECK(waterTex != nullptr, "Water texture is null");
if (waterTex == nullptr) {
// Can't render water if we don't have a texture.
return;
}
auto waterTex = world->data->findTexture("water_old");
RW_CHECK(waterTex != nullptr, "Water texture is null");
if (waterTex == nullptr) {
// Can't render water if we don't have a texture.
return;
}
Renderer::DrawParameters wdp;
wdp.start = 0;
wdp.count = maskGeom.getCount();
wdp.textures = {0};
glm::mat4 m(1.0);
glEnable(GL_STENCIL_TEST);
glDisable(GL_DEPTH_TEST);
Renderer::DrawParameters wdp;
wdp.start = 0;
wdp.count = maskGeom.getCount();
wdp.textures = {0};
glm::mat4 m(1.0);
glStencilFunc(GL_ALWAYS, 1, 0xFF);
glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
glStencilMask(0xFF);
GLenum buffers[] = {GL_COLOR_ATTACHMENT1};
glDrawBuffers(1, buffers);
glClear(GL_STENCIL_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
glEnable(GL_STENCIL_TEST);
glDisable(GL_DEPTH_TEST);
r->useProgram( maskProg );
glStencilFunc(GL_ALWAYS, 1, 0xFF);
glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
glStencilMask(0xFF);
GLenum buffers[] = {GL_COLOR_ATTACHMENT1};
glDrawBuffers(1, buffers);
glClear(GL_STENCIL_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
r->drawArrays(m, &maskDraw, wdp);
glStencilFunc(GL_EQUAL, 1, 0xFF);
glStencilMask(0x00);
glEnable(GL_DEPTH_TEST);
r->useProgram( waterProg );
buffers[0] = GL_COLOR_ATTACHMENT0;
glDrawBuffers(1, buffers);
r->useProgram(maskProg);
r->setUniform(waterProg, "time", world->getGameTime());
r->setUniform(waterProg, "waveParams", glm::vec2(WATER_SCALE, WATER_HEIGHT));
auto ivp = glm::inverse(r->getSceneData().projection * r->getSceneData().view);
r->setUniform(waterProg, "inverseVP", ivp);
r->drawArrays(m, &maskDraw, wdp);
wdp.count = gridGeom.getCount();
wdp.textures = {waterTex->getName(), dataTexture};
r->drawArrays(m, &gridDraw, wdp);
glStencilFunc(GL_EQUAL, 1, 0xFF);
glStencilMask(0x00);
glEnable(GL_DEPTH_TEST);
glDisable(GL_STENCIL_TEST);
r->useProgram(waterProg);
buffers[0] = GL_COLOR_ATTACHMENT0;
glDrawBuffers(1, buffers);
r->setUniform(waterProg, "time", world->getGameTime());
r->setUniform(waterProg, "waveParams",
glm::vec2(WATER_SCALE, WATER_HEIGHT));
auto ivp =
glm::inverse(r->getSceneData().projection * r->getSceneData().view);
r->setUniform(waterProg, "inverseVP", ivp);
wdp.count = gridGeom.getCount();
wdp.textures = {waterTex->getName(), dataTexture};
r->drawArrays(m, &gridDraw, wdp);
glDisable(GL_STENCIL_TEST);
}

View File

@ -1,7 +1,7 @@
#pragma once
#include <rw/types.hpp>
#include <render/OpenGLRenderer.hpp>
#include <rw/types.hpp>
class GameRenderer;
class GameWorld;
@ -9,40 +9,41 @@ class GameWorld;
/**
* Implements the rendering routines for drawing the sea water.
*/
class WaterRenderer
{
class WaterRenderer {
public:
WaterRenderer(GameRenderer* renderer);
~WaterRenderer();
/**
* Creates the required data for rendering the water. Accepts
* two arrays. waterHeights stores the real world heights which
* are indexed into by the array tiles for each water tile.
*
* This data is used to create the internal stencil mask for clipping
* the water rendering.
*/
void setWaterTable(float* waterHeights, unsigned int nHeights, uint8_t* tiles, unsigned int nTiles);
void setDataTexture(GLuint fbBinding, GLuint dataTexture);
/**
* Render the water using the currently active render state
*/
void render(GameRenderer* renderer, GameWorld* world);
WaterRenderer(GameRenderer* renderer);
~WaterRenderer();
/**
* Creates the required data for rendering the water. Accepts
* two arrays. waterHeights stores the real world heights which
* are indexed into by the array tiles for each water tile.
*
* This data is used to create the internal stencil mask for clipping
* the water rendering.
*/
void setWaterTable(float* waterHeights, unsigned int nHeights,
uint8_t* tiles, unsigned int nTiles);
void setDataTexture(GLuint fbBinding, GLuint dataTexture);
/**
* Render the water using the currently active render state
*/
void render(GameRenderer* renderer, GameWorld* world);
private:
Renderer::ShaderProgram* waterProg;
Renderer::ShaderProgram* maskProg;
DrawBuffer maskDraw;
GeometryBuffer maskGeom;
std::vector<int> maskSizes;
DrawBuffer gridDraw;
GeometryBuffer gridGeom;
GLuint fbOutput;
GLuint dataTexture;
Renderer::ShaderProgram* waterProg;
Renderer::ShaderProgram* maskProg;
DrawBuffer maskDraw;
GeometryBuffer maskGeom;
std::vector<int> maskSizes;
DrawBuffer gridDraw;
GeometryBuffer gridGeom;
GLuint fbOutput;
GLuint dataTexture;
};