diff options
Diffstat (limited to 'src/libjin/graphics/opengl.cpp')
-rw-r--r-- | src/libjin/graphics/opengl.cpp | 418 |
1 files changed, 418 insertions, 0 deletions
diff --git a/src/libjin/graphics/opengl.cpp b/src/libjin/graphics/opengl.cpp new file mode 100644 index 0000000..da3659d --- /dev/null +++ b/src/libjin/graphics/opengl.cpp @@ -0,0 +1,418 @@ +#define OGL2D_IMPLEMENT +#include "../utils/log.h" + +#include "opengl.h" +#include "color.h" +#include "canvas.h" +#include "texture.h" +#include "window.h" +#include "shaders/shader.h" +#include "fonts/font.h" + +using namespace JinEngine::Math; +using namespace JinEngine::Graphics; +using namespace JinEngine::Graphics::Shaders; + +namespace JinEngine +{ + namespace Graphics + { + + OpenGL gl; + + Canvas* const OpenGL::SCREEN = NULL; + + OpenGL::OpenGL() + { + memset(&mStats, 0, sizeof(mStats)); + memset(&mColor, 0xff, sizeof(mColor)); + // Set default modelview matrix. + mModelViewMatrices.push_back(Matrix()); + mModelViewMatrix.setIdentity(); + for (Matrix& m : mModelViewMatrices) + mModelViewMatrix *= m; + } + + OpenGL::~OpenGL() + { + } + + bool OpenGL::loadGL() + { + // Init glad library. + if (!gladLoadGLLoader(SDL_GL_GetProcAddress)) + { + jin_log_error("init opengl context failed"); + return false; + } + + return true; + } + + void OpenGL::init() + { + enable(GL_BLEND); + setClearColor(0, 0, 0, 0xff); + setColor(0xff, 0xff, 0xff, 0xff); + setBlendMode(OpenGL::BlendMode::ALPHA); + unbindCanvas(); + unuseShader(); + } + + void OpenGL::enable(GLenum cap) + { + glEnable(cap); + } + + void OpenGL::disable(GLenum cap) + { + glDisable(cap); + } + + void OpenGL::setClearColor(GLubyte r, GLubyte g, GLubyte b, GLubyte a) + { + glClearColor(r / 255.f, g / 255.f, b / 255.f, a / 255.f); + } + + void OpenGL::popColor() + { + glColor4ub(mColor.r, mColor.g, mColor.b, mColor.a); + } + + void OpenGL::flushError() + { + while (glGetError() != GL_NO_ERROR); + } + + GLuint OpenGL::genTexture() + { + GLuint t; + glGenTextures(1, &t); + return t; + } + + void OpenGL::bindTexture2D(GLuint texture) + { + glBindTexture(GL_TEXTURE_2D, texture); + } + + void OpenGL::deleteTexture(GLuint texture) + { + glDeleteTextures(1, &texture); + } + + void OpenGL::setTexParameter(GLenum pname, GLint param) + { + glTexParameteri(GL_TEXTURE_2D, pname, param); + } + + void OpenGL::texImage(GLint internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels) + { + glTexImage2D(GL_TEXTURE_2D, 0, internalformat, width, height, 0, format, type, pixels); + } + + void OpenGL::texSubImage(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels) + { + glTexSubImage2D(GL_TEXTURE_2D, 0, xoffset, yoffset, width, height, format, type, pixels); + } + + void OpenGL::activeTextureUnit(unsigned int unit) + { + // glActiveTexture selects which texture unit subsequent texture state calls will affect. + glActiveTexture(GL_TEXTURE0 + unit); + } + + void OpenGL::drawArrays(GLenum mode, GLint first, GLsizei count) + { + glDrawArrays(mode, first, count); + ++mStats.drawCalls; + } + + void OpenGL::drawBuffer(GLenum mode) + { + + } + + void OpenGL::drawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices) + { + + } + + void OpenGL::enableClientState(GLenum arr) + { + glEnableClientState(arr); + } + + void OpenGL::disableClientState(GLenum arr) + { + glDisableClientState(arr); + } + + GLuint OpenGL::genFrameBuffer() + { + GLuint fbo; + glGenFramebuffers(1, &fbo); + return fbo; + } + + void OpenGL::bindFrameBuffer(GLuint fbo) + { + glBindFramebuffer(GL_FRAMEBUFFER, fbo); + } + + void OpenGL::ortho(int w, float radio) + { + glOrtho(0, w, w*radio, 0, -1, 1); + } + + void OpenGL::orthox(int w, int h) + { + glOrtho(0, w, h, 0, -1, 1); + } + + void OpenGL::setColor(Channel r, Channel g, Channel b, Channel a) + { + setColor(Color(r, g, b, a)); + } + + void OpenGL::setColor(Color c) + { + mColor = c; + glColor4f(c.r / 255.f, c.g / 255.f, c.b / 255.f, c.a / 255.f); + } + + Color OpenGL::getColor() + { + return mColor; + } + + void OpenGL::clearMatrix() + { + mModelViewMatrices.clear(); + mModelViewMatrices.push_back(Matrix()); + mModelViewMatrix.setIdentity(); + } + + void OpenGL::pushMatrix() + { + mModelViewMatrices.push_back(Matrix()); + } + + void OpenGL::popMatrix() + { + if (mModelViewMatrices.size() == 1) + return; + mModelViewMatrices.pop_back(); + mModelViewMatrix.setIdentity(); + for (Matrix& m : mModelViewMatrices) + mModelViewMatrix *= m; + } + + void OpenGL::translate(float x, float y) + { + if (mModelViewMatrices.size() == 1) + return; + Matrix& m = mModelViewMatrices.back(); + m.translate(x, y); + mModelViewMatrix.translate(x, y); + } + + void OpenGL::scale(float sx, float sy) + { + if (mModelViewMatrices.size() == 1) + return; + Matrix& m = mModelViewMatrices.back(); + m.scale(sx, sy); + mModelViewMatrix.scale(sx, sy); + } + + void OpenGL::rotate(float r) + { + if (mModelViewMatrices.size() == 1) + return; + Matrix& m = mModelViewMatrices.back(); + m.rotate(r); + mModelViewMatrix.rotate(r); + } + + Matrix OpenGL::getModelViewMatrix(float x, float y, float sx, float sy, float r, float ox, float oy) + { + Matrix m; + m.setTransformation(x, y, r, sx, sy, ox, oy); + return mModelViewMatrix*m; + } + + Math::Matrix OpenGL::getModelViewMatrix(const Math::Transform& tansform) + { + return mModelViewMatrix * tansform.getMatrix(); + } + + Matrix OpenGL::getModelViewMatrix() + { + return mModelViewMatrix; + } + + const Matrix& OpenGL::getProjectionMatrix() + { + return mProjectionMatrix; + } + + void OpenGL::setProjectionMatrix(float l, float r, float b, float t, float n, float f) + { + mProjectionMatrix.setOrtho(l, r, b, t, n, f); + } + + OpenGL::BlendMode OpenGL::getBlendMode() + { + return mBlendMode; + } + + void OpenGL::setBlendMode(BlendMode mode) + { + if (mBlendMode == mode) + return; + mBlendMode = mode; + + // result = src * srcFac FUNC dst * dstFac + + GLenum func = GL_FUNC_ADD; + GLenum srcRGB = GL_ONE; + GLenum srcA = GL_ONE; + GLenum dstRGB = GL_ZERO; + GLenum dstA = GL_ZERO; + + switch (mode) + { + case BlendMode::ADDITIVE: + srcRGB = GL_SRC_ALPHA; + srcA = GL_SRC_ALPHA; + dstRGB = GL_ONE; + dstA = GL_ONE; + break; + case BlendMode::PREMULTIPLIEDALPHA: + srcRGB = srcA = GL_ONE; + dstRGB = dstA = GL_ONE_MINUS_SRC_ALPHA; + break; + case BlendMode::ALPHA: + default: + srcRGB = GL_SRC_ALPHA; + srcA = GL_SRC_ALPHA; + dstRGB = GL_ONE_MINUS_SRC_ALPHA; + dstA = GL_ONE_MINUS_SRC_ALPHA; + + break; + } + + glBlendEquation(func); + glBlendFuncSeparate(srcRGB, dstRGB, srcA, dstA); + } + + void OpenGL::useShader(Shaders::Shader* shader) + { + if (mShader != shader && shader) + { + glUseProgram(shader->getGLProgramID()); + mShader = shader; + + ++mStats.shaderSwitches; + } + } + + void OpenGL::unuseShader() + { + if (mShader) + { + glUseProgram(0); + mShader = nullptr; + } + } + + Shaders::Shader* OpenGL::getShader() + { + return mShader; + } + + void OpenGL::bindCanvas(Canvas* canvas) + { + if (mCanvas != canvas && canvas) + { + GLuint fbo = canvas->getGLFrameBuffer(); + gl.bindFrameBuffer(fbo); + int w = canvas->getWidth(); + int h = canvas->getHeight(); + glViewport(0, 0, w, h); + gl.setProjectionMatrix(0, w, 0, h, -1, 1); + + mCanvas = canvas; + + gl.enable(GL_BLEND); + gl.enable(GL_TEXTURE_2D); + + gl.setBlendMode(OpenGL::BlendMode::ALPHA); + + ++mStats.canvasSwitches; + } + } + + /** + * bind to default screen render buffer. + * do some coordinates transform work + * https://blog.csdn.net/liji_digital/article/details/79370841 + * https://blog.csdn.net/lyx2007825/article/details/8792475 + */ + void OpenGL::unbindCanvas() + { + // Default bind to default canvas. + if (getCanvas() == SCREEN) + return; + // Get window size as viewport. + Window* wnd = Window::get(); + int w = wnd->getW(); + int h = wnd->getH(); + glBindFramebuffer(GL_FRAMEBUFFER, 0); + glViewport(0, 0, w, h); + gl.setProjectionMatrix(0, w, h, 0, -1, 1); + + mCanvas = SCREEN; + } + + Canvas* OpenGL::getCanvas() + { + return mCanvas; + } + + void OpenGL::setFont(Fonts::Font* font) + { + if (mFont != font && font) + { + mFont = font; + + ++mStats.fontSwitches; + } + } + + void OpenGL::unsetFont() + { + mFont = nullptr; + } + + Fonts::Font* OpenGL::getFont() + { + return mFont; + } + + void OpenGL::resetStats() + { + mStats.drawCalls = 0; + mStats.canvasSwitches = 0; + mStats.shaderSwitches = 0; + mStats.fontSwitches = 0; + } + + OpenGL::Stats& OpenGL::getStats() + { + return mStats; + } + + } // namespace Graphics +} // namespace JinEngine
\ No newline at end of file |