1
0
mirror of https://github.com/rwengine/openrw.git synced 2024-11-10 04:42:38 +01:00
openrw/rwengine/include/render/OpenGLRenderer.hpp
Christoph Heiss 938a2e4bfc Introduce Renderer::readPixels
This is needed for taking screenshots.
2016-06-22 11:14:47 +02:00

357 lines
8.7 KiB
C++

#pragma once
#ifndef _OPENGLRENDERER_HPP_
#define _OPENGLRENDERER_HPP_
#include <rw/types.hpp>
#include <gl/DrawBuffer.hpp>
#include <gl/GeometryBuffer.hpp>
#include <glm/vec2.hpp>
typedef uint64_t RenderKey;
// Maximum depth of debug group stack
#define MAX_DEBUG_DEPTH 5
typedef std::uint32_t RenderIndex;
struct VertexP3
{
glm::vec3 position;
static const AttributeList vertex_attributes() {
return {
{ATRS_Position, 3, sizeof(VertexP3), 0ul},
};
}
};
/// @todo normalize this to have the same interface as VertexP3
struct VertexP2 {
static const AttributeList vertex_attributes() {
return {
{ATRS_Position, 2, sizeof(VertexP2), 0ul}
};
}
float x, y;
};
class Renderer
{
public:
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;
// 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;
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;
struct ObjectUniformData {
glm::mat4 model;
glm::vec4 colour;
float diffuse;
float ambient;
float visibility;
};
struct SceneUniformData {
glm::mat4 projection;
glm::mat4 view;
glm::vec4 ambient;
glm::vec4 dynamic;
glm::vec4 fogColour;
glm::vec4 campos;
float fogStart;
float fogEnd;
};
class ShaderProgram {
// This just provides an opaque handle for external users.
};
virtual std::string getIDString() const = 0;
virtual ShaderProgram* createShader(const std::string& vert, const std::string& frag) = 0;
virtual void useProgram(ShaderProgram* p) = 0;
/// @todo dont use GLint in the interface.
virtual void setProgramBlockBinding(ShaderProgram* p, const std::string& name, GLint point) = 0;
virtual void setUniformTexture(ShaderProgram*p, const std::string& name, GLint tex) = 0;
virtual void setUniform(ShaderProgram*p, const std::string& name, const glm::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 clear(const glm::vec4& colour, bool clearColour = true, bool clearDepth = true) = 0;
virtual void setSceneParameters(const SceneUniformData& data) = 0;
virtual void draw(const glm::mat4& model, DrawBuffer* draw, const DrawParameters& p) = 0;
virtual void drawArrays(const glm::mat4& model, DrawBuffer* draw, const DrawParameters& p) = 0;
virtual void drawBatched(const RenderList& list) = 0;
void setViewport(const glm::ivec2& vp);
const glm::ivec2& getViewport() const { return viewport; }
const glm::mat4& get2DProjection() const { return projection2D; }
virtual void invalidate() = 0;
virtual unsigned char* readPixels(const glm::ivec2& size) const { return nullptr; };
/**
* 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;
};
/**
* 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;
protected:
int drawCounter;
int textureCounter;
int bufferCounter;
SceneUniformData lastSceneData;
};
class OpenGLRenderer : public Renderer
{
public:
class OpenGLShaderProgram : public ShaderProgram {
GLuint program;
std::map<std::string, GLint> uniforms;
public:
OpenGLShaderProgram(GLuint p)
: program(p)
{ }
GLuint getName() const { return program; }
GLint getUniformLocation(const std::string& name) {
auto c = uniforms.find(name.c_str());
GLint loc = -1;
if( c == uniforms.end() ) {
loc = glGetUniformLocation(program, name.c_str());
uniforms[name] = loc;
}
else {
loc = c->second;
}
return loc;
}
};
OpenGLRenderer();
std::string getIDString() const;
ShaderProgram* createShader(const std::string &vert, const std::string &frag);
void setProgramBlockBinding(ShaderProgram* p, const std::string &name, GLint point);
void setUniformTexture(ShaderProgram* p, const std::string &name, GLint tex);
void setUniform(ShaderProgram* p, const std::string& name, const glm::mat4& m);
void setUniform(ShaderProgram* p, const std::string& name, const glm::vec4& m);
void setUniform(ShaderProgram* p, const std::string& name, const glm::vec3& m);
void setUniform(ShaderProgram* p, const std::string& name, const glm::vec2& m);
void setUniform(ShaderProgram* p, const std::string& name, float f);
void useProgram(ShaderProgram* p);
void clear(const glm::vec4 &colour, bool clearColour, bool clearDepth);
void setSceneParameters(const SceneUniformData &data);
void setDrawState(const glm::mat4& model, DrawBuffer* draw, const DrawParameters& p);
void draw(const glm::mat4& model, DrawBuffer* draw, const DrawParameters& p);
void drawArrays(const glm::mat4& model, DrawBuffer* draw, const DrawParameters& p);
void drawBatched(const RenderList& list) override;
void invalidate();
unsigned char* readPixels(const glm::ivec2& size) const;
virtual void pushDebugGroup(const std::string& title);
virtual const ProfileInfo& popDebugGroup();
private:
DrawBuffer* currentDbuff;
void useDrawBuffer(DrawBuffer* dbuff);
std::map<GLuint,GLuint> currentTextures;
void useTexture(GLuint unit, GLuint tex);
OpenGLShaderProgram* currentProgram;
GLuint currentUBO;
template<class T> void uploadUBO(GLuint buffer, const T& data)
{
if( currentUBO != buffer ) {
glBindBuffer(GL_UNIFORM_BUFFER, buffer);
currentUBO = buffer;
}
glBufferData(GL_UNIFORM_BUFFER, sizeof(T), &data, GL_DYNAMIC_DRAW);
#if RW_PROFILER
if( currentDebugDepth > 0 )
{
profileInfo[currentDebugDepth-1].uploads++;
}
#endif
}
GLuint UBOObject;
GLuint maxObjectEntries;
GLuint currentObjectEntry;
GLuint entryAlignment;
GLuint UBOScene;
// State Cache
bool blendEnabled;
bool depthWriteEnabled;
// Set state
void setBlend(bool enable)
{
/// @todo set blendEnabled, currently not possible because other functions keep trashing the state
#if 0
if (enable && !blendEnabled) {
glEnable(GL_BLEND);
blendEnabled = enable;
} else if(!enable && blendEnabled) {
glDisable(GL_BLEND);
blendEnabled = enable;
}
#else
glEnable(GL_BLEND);
#endif
}
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;
};
/// @todo remove these from here
GLuint compileShader(GLenum type, const char *source);
GLuint compileProgram(const char* vertex, const char* fragment);
typedef Renderer::RenderList RenderList;
#endif