aboutsummaryrefslogtreecommitdiff
path: root/src/libjin/graphics/opengl.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/libjin/graphics/opengl.cpp')
-rw-r--r--src/libjin/graphics/opengl.cpp418
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