mirror of
https://github.com/rwengine/openrw.git
synced 2024-11-07 03:12:36 +01:00
clang-format files in rwengine/src/render
This commit is contained in:
parent
1e4d7ea133
commit
e888d04303
@ -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;
|
||||
}
|
||||
|
@ -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
@ -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
|
||||
|
@ -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;
|
||||
})";
|
||||
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
@ -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
|
||||
|
@ -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, ¤t_time);
|
||||
glQueryCounter(debugQuery, GL_TIMESTAMP);
|
||||
GLuint64 current_time;
|
||||
glGetQueryObjectui64v(debugQuery, GL_QUERY_RESULT, ¤t_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];
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user