Browse Source

Add ShaderLoader

master
Geert Custers 2 years ago
parent
commit
f9f11e0fe2

+ 17
- 5
src/graphics/components/DocumentComponent.cpp View File

@@ -5,6 +5,11 @@
#include "InputComponent.h"
#include <ctime>

#include "../opengl/Shader.h"
#include "../opengl/ShaderLoader.h"
#include "../opengl/shaders/gen/TextureShader.h"
#include "../opengl/shaders/gen/FontShader.h"

void deleteComponent(std::shared_ptr<Component> &component);
void deleteNode(std::shared_ptr<Node> node);

@@ -273,21 +278,28 @@ void DocumentComponent::render() {
// because window resets it
//if (transformMatrixDirty) {
//const std::clock_t begin = clock();
GLint transformLocation = glGetUniformLocation(win->fontProgram, "transform");
Shader *fontShader = ShaderLoader::getShader(VertexShader(fontVertexShaderSource),
FragmentShader(fontFragmentShaderSource));
GLint transformLocation = fontShader->uniform("transform");
glUniformMatrix4fv(transformLocation, 1, GL_FALSE, transformMatrix);
//const std::clock_t end = clock();
//std::cout << "Updated font matrix in: " << std::fixed << ((static_cast<double>(end - begin)) / CLOCKS_PER_SEC) << std::scientific << " seconds" << std::endl;

GLint transformLocation2 = glGetUniformLocation(win->textureProgram, "transform");
Shader *textureShader = ShaderLoader::getShader(VertexShader(textureVertexShaderSource),
FragmentShader(textureFragmentShaderSource));
GLint transformLocation2 = textureShader->uniform("transform");
glUniformMatrix4fv(transformLocation2, 1, GL_FALSE, transformMatrix);

transformMatrixDirty = false;
//}
//std::cout << "DocumentComponent::render - renderDirty" << std::endl;
glUseProgram(win->textureProgram);
textureShader->bind();
renderBoxComponents(rootComponent);
glUseProgram(win->fontProgram);
textureShader->release();

fontShader->bind();
renderComponents(rootComponent);
fontShader->release();
}

// create this component and all it's children

+ 12
- 3
src/graphics/components/InputComponent.cpp View File

@@ -3,6 +3,11 @@
#include "../text/TextRasterizerCache.h"
#include "../../scheduler.h"

#include "../opengl/Shader.h"
#include "../opengl/ShaderLoader.h"
#include "../opengl/shaders/gen/TextureShader.h"
#include "../opengl/shaders/gen/FontShader.h"

extern TextRasterizerCache *rasterizerCache;
extern std::unique_ptr<Scheduler> scheduler;

@@ -159,9 +164,11 @@ void InputComponent::render() {
// can actuall delete vertices here
if (userInputText) {
// make sure we're using win's transformMatrix
glUseProgram(window->fontProgram);
Shader *fontShader = ShaderLoader::getShader(VertexShader(fontVertexShaderSource),
FragmentShader(fontFragmentShaderSource));
fontShader->bind();
if (!boundToPage) {
GLint transformLocation = glGetUniformLocation(window->fontProgram, "transform");
GLint transformLocation = fontShader->uniform("transform");
glErr=glGetError();
if(glErr != GL_NO_ERROR) {
std::cout << "InputComponent::render - glGetUniformLocation not ok: " << glErr << std::endl;
@@ -175,7 +182,9 @@ void InputComponent::render() {
}
//std::cout << "rendering some text" << std::endl;
userInputText->render();
glUseProgram(window->textureProgram);
Shader *textureShader = ShaderLoader::getShader(VertexShader(textureVertexShaderSource),
FragmentShader(textureFragmentShaderSource));
textureShader->bind();
}
if (focused) {
//std::cout << "Rendering cursor" << std::endl;

+ 16
- 4
src/graphics/components/MultiComponent.cpp View File

@@ -6,6 +6,11 @@
#include "AnimeComponent.h"
#include "InputComponent.h"

#include "../opengl/Shader.h"
#include "../opengl/ShaderLoader.h"
#include "../opengl/shaders/gen/TextureShader.h"
#include "../opengl/shaders/gen/FontShader.h"

MultiComponent::MultiComponent(const float rawX, const float rawY, const float rawWidth, const float rawHeight, const int passedWindowWidth, const int passedWindowHeight) {
// take our space (for parent picking)
@@ -215,14 +220,21 @@ void MultiComponent::resize(const int passedWindowWidth, const int passedWindowH

void MultiComponent::render() {
//std::cout << "MultiComponent::render" << std::endl;
glUseProgram(win->fontProgram);
Shader *fontShader = ShaderLoader::getShader(VertexShader(fontVertexShaderSource),
FragmentShader(fontFragmentShaderSource));
fontShader->bind();
renderDocumentComponents(rootComponent);
glUseProgram(win->textureProgram);
fontShader->release();

Shader *textureShader = ShaderLoader::getShader(VertexShader(textureVertexShaderSource),
FragmentShader(textureFragmentShaderSource));
textureShader->bind();
renderBoxComponents(rootComponent);
textureShader->release();
// if we flip, we can't put tab labels on top of the tab
glUseProgram(win->fontProgram);
fontShader->bind();
if (!boundToPage) {
GLint transformLocation = glGetUniformLocation(win->fontProgram, "transform");
GLint transformLocation = fontShader->uniform("transform");
GLenum glErr=glGetError();
if(glErr != GL_NO_ERROR) {
std::cout << "MultiComponent::render - glGetUniformLocation not ok: " << glErr << std::endl;

+ 37
- 0
src/graphics/opengl/Shader.cpp View File

@@ -0,0 +1,37 @@
#include "Shader.h"

void Shader::bind() const {
glUseProgram(handle);
}

void Shader::release() const {
glUseProgram(0);
}

int Shader::uniform(const std::string &name) {
// Is it already in the map?
auto it = locationMap.find(name);
if (it != locationMap.end()) {
return it->second;
}

// It isn't, get the uniform location and store it
GLint location = glGetUniformLocation(handle, name.c_str());
locationMap.insert(std::make_pair(name, location));

return location;
}

int Shader::attribute(const std::string &name) {
// Is it already in the map?
auto it = locationMap.find(name);
if (it != locationMap.end()) {
return it->second;
}

// It isn't, get the attribute location and store it
GLint location = glGetAttribLocation(handle, name.c_str());
locationMap.insert(std::make_pair(name, location));

return location;
}

+ 37
- 0
src/graphics/opengl/Shader.h View File

@@ -0,0 +1,37 @@
#ifndef SHADER_H
#define SHADER_H

#include <GL/glew.h>
#include <string>
#include <map>

struct VertexShader {
VertexShader(std::string s) : source(s) { }
std::string source;
};

struct FragmentShader {
FragmentShader(std::string s) : source(s) { }
std::string source;
};

class Shader {
public:
enum Type {
Vertex,
Fragment
};

Shader(unsigned int h) : handle(h) { }
void bind() const;
void release() const;

unsigned int handle;
int uniform(const std::string &name);
int attribute(const std::string &name);
private:
std::map<std::string, int> locationMap;
};

#endif

+ 138
- 0
src/graphics/opengl/ShaderLoader.cpp View File

@@ -0,0 +1,138 @@
#include "ShaderLoader.h"

#include <fstream>
#include <iostream>
#include <memory>

#include "Shader.h"
#include "../../Log.h"

static constexpr GLint maxLogSize = 1024 * 1024 * 2; //2 MiB

ShaderLoader::ShaderCache ShaderLoader::shaderCache;

GLuint ShaderLoader::loadShader(const std::string &shaderSource, Shader::Type type) {
GLenum glType = getGlShaderType(type);
if (!glType) {
logError() << "Unknown shader type: " << type << std::endl;
return 0;
}
GLuint shader = glCreateShader(glType);
const char *source = shaderSource.c_str();
glShaderSource(shader, 1, &source, NULL);
glCompileShader(shader);

if(checkShader(shader, shaderSource, type))
return 0;

return shader;
}

GLuint ShaderLoader::createProgram(const std::string &shader1Source, Shader::Type shader1Type,
const std::string &shader2Source, Shader::Type shader2Type) {
GLuint shader1 = loadShader(shader1Source, shader1Type);
GLuint shader2 = loadShader(shader2Source, shader2Type);

if (!shader1 || !shader2)
return 0;

GLuint program = glCreateProgram();
glAttachShader(program, shader1);
glAttachShader(program, shader2);

glLinkProgram(program);
if (checkProgram(program, GL_LINK_STATUS, shader1Source))
return 0;
glValidateProgram(program);
if (checkProgram(program, GL_VALIDATE_STATUS, shader1Source))
return 0;

return program;
}

Shader *ShaderLoader::getShader(VertexShader vertexShader, FragmentShader fragmentShader) {
// concatenate strings to create unique key for the shader
std::string key = vertexShader.source + fragmentShader.source;

// has the shader been cached?
auto it = shaderCache.find(key);
if (it != shaderCache.end())
return it->second;

// Ok. It isn't. Let's create the shader Q.Q
GLuint program = createProgram(vertexShader.source, Shader::Type::Vertex,
fragmentShader.source, Shader::Type::Fragment);
if (!program) //reee it failed
return NULL;

Shader *shader = new Shader(program);
shaderCache.insert(std::make_pair(key, shader));
return shader;
}

int ShaderLoader::checkShader(GLuint shader, const std::string &source, Shader::Type type) {
GLint success = 0;
glGetShaderiv(shader, GL_COMPILE_STATUS, &success);

if (success == GL_TRUE) {
logDebug() << "Shader " << source << " compiled successfully!" << std::endl;
} else {
GLint logSize = 0;
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &logSize);
if (logSize > maxLogSize) {
logError() << "Shader " << source << " failed to compile but \
the log is too long to show." << std::endl;
return 1;
}
char log[logSize];
glGetShaderInfoLog(shader, logSize, &logSize, &log[0]);
logError() << "Shader " << source << " failed to compile. GL log output: "
<< log << std::endl;
glDeleteShader(shader);
return 1;
}
return 0;
}

int ShaderLoader::checkProgram(GLuint program, GLenum pname, const std::string &source) {
GLint success = 0;
glGetProgramiv(program, pname, &success);
if (success == GL_TRUE) {
logDebug() << "Program with shader1 " << source << " " << getProgramStatusString(pname)
<< std::endl;
} else {
GLint logSize = 0;
glGetProgramiv(program, GL_INFO_LOG_LENGTH, &logSize);
if (logSize > maxLogSize) {
logError() << "Program with shader1 " << source << " failed to be "
<< getProgramStatusString(pname) << " but the log is too long to show" << std::endl;
return 1;
}
char log[logSize];
glGetProgramInfoLog(program, logSize, &logSize, &log[0]);
logError() << "Program with shader1 " << source << " failed to be "
<< getProgramStatusString(pname) << ". GL log output: " << log << std::endl;
glDeleteProgram(program);
return 1;
}
return 0;
}

constexpr const char *ShaderLoader::getProgramStatusString(GLenum pname) {
switch (pname) {
case GL_LINK_STATUS:
return "linked";
case GL_VALIDATE_STATUS:
return "validated";
}
return "";
}
constexpr GLenum ShaderLoader::getGlShaderType(const Shader::Type type) {
switch (type) {
case Shader::Vertex:
return GL_VERTEX_SHADER;
case Shader::Fragment:
return GL_FRAGMENT_SHADER;
}
return 0;
}

+ 34
- 0
src/graphics/opengl/ShaderLoader.h View File

@@ -0,0 +1,34 @@
#ifndef SHADERLOADER_H
#define SHADERLOADER_H

#include <GL/glew.h>
#include <string>
#include <map>

#include "Shader.h"

class ShaderLoader {
public:
using ShaderCache = std::map<std::string, Shader*>;

// Get a shader from the shader cache and load it from disk it isn't there
static Shader *getShader(VertexShader vertexShader, FragmentShader fragmentShader);

// Load a shader from disk and return the its handle
static GLuint loadShader(const std::string &source, Shader::Type shaderType);

static GLuint createProgram(const std::string &shader1Source, Shader::Type shader1Type,
const std::string &shader2Source, Shader::Type shader2Type);
private:
static ShaderCache shaderCache;

static int checkProgram(GLuint program, GLenum programName,
const std::string &source);

static int checkShader(GLuint shader, const std::string &source, Shader::Type shaderType);

static constexpr GLenum getGlShaderType(const Shader::Type type);

static constexpr const char *getProgramStatusString(GLenum pname);
};
#endif

+ 15
- 80
src/graphics/opengl/Window.cpp View File

@@ -1,7 +1,5 @@
#include "../../URL.h"
#include "Window.h"
#include "shaders/gen/FontShader.h"
#include "shaders/gen/TextureShader.h"
#include "../../html/TagNode.h"
#include "../../html/TextNode.h"

@@ -17,19 +15,16 @@
#include "../components/TextComponent.h"
#include "../components/TabbedComponent.h"
#include "../components/InputComponent.h"
#include "../opengl/Shader.h"
#include "../opengl/ShaderLoader.h"
#include "../opengl/shaders/gen/TextureShader.h"
#include "../opengl/shaders/gen/FontShader.h"

#include <cmath>
#include <ctime>
#include <iostream>

Window::~Window() {
if (fontProgram) {
glDeleteProgram(fontProgram);
}
if (textureProgram) {
glDeleteProgram(textureProgram);
}

glfwTerminate();
}

@@ -638,26 +633,6 @@ bool Window::initGL() {
std::cout << "window::initGL - blend, clear, texParam - not ok: " << glErr << std::endl;
}

const GLuint fontVertexShader = compileShader(GL_VERTEX_SHADER, fontVertexShaderSource);
const GLuint fontFragmentShader = compileShader(GL_FRAGMENT_SHADER, fontFragmentShaderSource);
fontProgram = compileProgram(fontVertexShader, fontFragmentShader);
glDeleteShader(fontVertexShader);
glDeleteShader(fontFragmentShader);
glErr=glGetError();
if(glErr != GL_NO_ERROR) {
std::cout << "window::initGL - font program - not ok: " << glErr << std::endl;
}

const GLuint textureVertexShader = compileShader(GL_VERTEX_SHADER, textureVertexShaderSource);
const GLuint textureFragmentShader = compileShader(GL_FRAGMENT_SHADER, textureFragmentShaderSource);
textureProgram = compileProgram(textureVertexShader, textureFragmentShader);
glDeleteShader(textureVertexShader);
glDeleteShader(textureFragmentShader);
glErr=glGetError();
if(glErr != GL_NO_ERROR) {
std::cout << "window::initGL - texture program - not ok: " << glErr << std::endl;
}

//std::cout << "OpenGL is set up" << std::endl;
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize);
@@ -665,49 +640,6 @@ bool Window::initGL() {
return true;
}

GLuint Window::compileShader(const GLenum shaderType, const char *shaderSource) const {
const GLuint shader = glCreateShader(shaderType);
glShaderSource(shader, 1, &shaderSource, nullptr);
glCompileShader(shader);

GLenum glErr=glGetError();
if(glErr != GL_NO_ERROR) {
std::cout << "window::compileShader - compileShader - not ok: " << glErr << std::endl;
}

GLint success;
GLchar infoLog[1024];
glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
if (!success) {
glGetShaderInfoLog(shader, 1024, nullptr, infoLog);
std::cout << "Could not compile shader\n" << infoLog << std::endl;
}

return shader;
}

GLuint Window::compileProgram(const GLuint vertexShader, const GLuint fragmentShader) const {
const GLuint program = glCreateProgram();
glAttachShader(program, vertexShader);
glAttachShader(program, fragmentShader);
glLinkProgram(program);

GLenum glErr=glGetError();
if(glErr != GL_NO_ERROR) {
std::cout << "window::compileProgram - glLinkProgram - not ok: " << glErr << std::endl;
}

GLint success;
GLchar infoLog[1024];
glGetProgramiv(program, GL_LINK_STATUS, &success);
if (!success) {
glGetProgramInfoLog(program, 1024, nullptr, infoLog);
std::cout << "Could not compile program\n" << infoLog << std::endl;
}

return program;
}

void Window::onResize(int passedWidth, int passedHeight) {
this->windowWidth = passedWidth;
this->windowHeight = passedHeight;
@@ -770,8 +702,9 @@ void Window::render() {
std::cout << "window::render - box render start - not ok: " << glErr << std::endl;
}


glUseProgram(textureProgram);
Shader *textureShader = ShaderLoader::getShader(VertexShader(textureVertexShaderSource),
FragmentShader(textureFragmentShaderSource));
textureShader->bind();
glErr=glGetError();
if(glErr != GL_NO_ERROR) {
std::cout << "window::render - glUseProgram - not ok: " << glErr << std::endl;
@@ -783,7 +716,7 @@ void Window::render() {
renderComponentType("anime", rootComponent);

renderComponentType("tab", rootComponent);
glUseProgram(textureProgram); // reset after doc
textureShader->bind();

//GLint transformLocation = glGetUniformLocation(textureProgram, "transform");
//glUniformMatrix4fv(transformLocation, 1, GL_FALSE, transformMatrix);
@@ -791,13 +724,15 @@ void Window::render() {
renderComponentType("input", rootComponent);

// it's quick but done on scroll
glUseProgram(fontProgram);
Shader *fontShader = ShaderLoader::getShader(VertexShader(fontVertexShaderSource),
FragmentShader(fontFragmentShaderSource));
fontShader->bind();
// reset both, since components can change this
// god we may have to reset this after each component render...
// maybe we don't need too
if (transformMatrixDirty) {
//const std::clock_t begin = clock();
GLint transformLocation = glGetUniformLocation(fontProgram, "transform");
GLint transformLocation = fontShader->uniform("transform");
glErr=glGetError();
if(glErr != GL_NO_ERROR) {
std::cout << "window::render - glGetUniformLocation - not ok: " << glErr << std::endl;
@@ -822,14 +757,14 @@ void Window::render() {

// update 2nd buffer
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glUseProgram(textureProgram);
textureShader->bind();
renderComponentType("anime", rootComponent);
renderComponentType("tab", rootComponent);
glUseProgram(textureProgram);
textureShader->bind();
renderComponentType("box", rootComponent);
renderComponentType("input", rootComponent);
// it's quick but done on scroll
glUseProgram(fontProgram);
fontShader->bind();
renderComponentType("text", rootComponent);
glfwSwapBuffers(window);


+ 0
- 4
src/graphics/opengl/Window.h View File

@@ -15,15 +15,11 @@
class Window {
private:
public:
GLuint fontProgram = 0;
GLuint textureProgram = 0;
~Window();
bool init();
bool initGLFW();
bool initGLEW() const;
bool initGL();
GLuint compileShader(const GLenum shaderType, const char *shaderSource) const;
GLuint compileProgram(const GLuint vertexShader, const GLuint fragmentShader) const;

void render();
void setDOM(const std::shared_ptr<Node> rootNode);

Loading…
Cancel
Save