forked from dfeneyrou/palanteer
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
issue dfeneyrou#18: Isolate the graphical backend. Cleaner architectu…
…re + easier to add another backend if needed
- Loading branch information
Showing
4 changed files
with
339 additions
and
261 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
// Palanteer viewer | ||
// Copyright (C) 2021, Damien Feneyrou <dfeneyrou@gmail.com> | ||
// | ||
// This program is free software: you can redistribute it and/or modify | ||
// it under the terms of the GNU Affero General Public License as | ||
// published by the Free Software Foundation, either version 3 of the | ||
// License, or (at your option) any later version. | ||
// | ||
// This program is distributed in the hope that it will be useful, | ||
// but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
// GNU Affero General Public License for more details. | ||
// | ||
// You should have received a copy of the GNU Affero General Public License | ||
// along with this program. If not, see <https://www.gnu.org/licenses/>. | ||
|
||
|
||
// Interface for graphic backends | ||
|
||
void vwBackendInit(void); | ||
void vwBackendInstallFont(const void* fontData, int fontDataSize, int fontSize); | ||
bool vwBackendDraw(void); // Return true is something has been drawn | ||
void vwBackendUninit(void); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,232 @@ | ||
// Palanteer viewer | ||
// Copyright (C) 2021, Damien Feneyrou <dfeneyrou@gmail.com> | ||
// | ||
// This program is free software: you can redistribute it and/or modify | ||
// it under the terms of the GNU Affero General Public License as | ||
// published by the Free Software Foundation, either version 3 of the | ||
// License, or (at your option) any later version. | ||
// | ||
// This program is distributed in the hope that it will be useful, | ||
// but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
// GNU Affero General Public License for more details. | ||
// | ||
// You should have received a copy of the GNU Affero General Public License | ||
// along with this program. If not, see <https://www.gnu.org/licenses/>. | ||
|
||
// This file implements the Open GL backend | ||
|
||
#if defined(__linux__) || defined(_WIN32) | ||
|
||
// External | ||
#include "imgui.h" | ||
|
||
// Internal | ||
#include "bs.h" | ||
#include "bsGl.h" | ||
#include "vwGfxBackend.h" | ||
|
||
|
||
// Shaders | ||
static const GLchar* guiVertexShaderSrc = | ||
"#version 300 es\n" | ||
"uniform mat4 ProjMtx;\n" | ||
"in vec2 Position;\n" | ||
"in vec2 UV;\n" | ||
"in vec4 Color;\n" | ||
"out vec2 Frag_UV;\n" | ||
"out vec4 Frag_Color;\n" | ||
"void main()\n" | ||
"{\n" | ||
" Frag_UV = UV;\n" | ||
" Frag_Color = Color;\n" | ||
" gl_Position = ProjMtx * vec4(Position.xy,0,1);\n" | ||
"}\n"; | ||
|
||
static const GLchar* guiFragmentShaderSrc = | ||
"#version 300 es\n" | ||
"precision mediump float;\n" | ||
"uniform sampler2D Texture;\n" | ||
"in vec2 Frag_UV;\n" | ||
"in vec4 Frag_Color;\n" | ||
"out vec4 Out_Color;\n" | ||
"void main()\n" | ||
"{\n" | ||
" Out_Color = vec4(Frag_Color.xyz, Frag_Color.w*texture(Texture, Frag_UV.st));\n" | ||
"}\n"; | ||
|
||
|
||
// Rendering context | ||
static struct { | ||
bsGlProgramVAO guiGlProgram; | ||
GLuint fontTextureId = 0; | ||
int unifAttribLocationTex = 0; | ||
int unifAttribLocationProjMtx = 0; | ||
int attribLocationPosition = 0; | ||
int attribLocationUV = 0; | ||
int attribLocationColor = 0; | ||
} vwGlCtx; | ||
|
||
|
||
void | ||
vwBackendInit(void) | ||
{ | ||
|
||
// Allocate the font texture (fully initialized later) | ||
glGenTextures (1, &vwGlCtx.fontTextureId); | ||
glBindTexture (GL_TEXTURE_2D, vwGlCtx.fontTextureId); | ||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); | ||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); | ||
glPixelStorei (GL_UNPACK_ROW_LENGTH, 0); | ||
|
||
// Build and configure the OpenGL Vertex Array Object for GUI | ||
vwGlCtx.guiGlProgram.install(guiVertexShaderSrc, guiFragmentShaderSrc); | ||
vwGlCtx.unifAttribLocationTex = glGetUniformLocation(vwGlCtx.guiGlProgram.getId(), "Texture"); | ||
vwGlCtx.unifAttribLocationProjMtx = glGetUniformLocation(vwGlCtx.guiGlProgram.getId(), "ProjMtx"); | ||
vwGlCtx.attribLocationPosition = glGetAttribLocation(vwGlCtx.guiGlProgram.getId(), "Position"); | ||
vwGlCtx.attribLocationUV = glGetAttribLocation(vwGlCtx.guiGlProgram.getId(), "UV"); | ||
vwGlCtx.attribLocationColor = glGetAttribLocation(vwGlCtx.guiGlProgram.getId(), "Color"); | ||
glEnableVertexAttribArray(vwGlCtx.attribLocationPosition); | ||
glEnableVertexAttribArray(vwGlCtx.attribLocationUV); | ||
glEnableVertexAttribArray(vwGlCtx.attribLocationColor); | ||
glVertexAttribPointer(vwGlCtx.attribLocationPosition, 2, GL_FLOAT, GL_FALSE, sizeof(ImDrawVert), (GLvoid*)IM_OFFSETOF(ImDrawVert, pos)); | ||
glVertexAttribPointer(vwGlCtx.attribLocationUV, 2, GL_FLOAT, GL_FALSE, sizeof(ImDrawVert), (GLvoid*)IM_OFFSETOF(ImDrawVert, uv)); | ||
glVertexAttribPointer(vwGlCtx.attribLocationColor, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(ImDrawVert), (GLvoid*)IM_OFFSETOF(ImDrawVert, col)); | ||
GL_CHECK(); | ||
|
||
// Base GL setup | ||
glClearColor(0.3, 0.3, 0.3, 1.0); | ||
} | ||
|
||
|
||
bool | ||
vwBackendDraw(void) | ||
{ | ||
ImDrawData* drawData = ImGui::GetDrawData(); | ||
plAssert(drawData); | ||
int frameBufferWidth = (int)(drawData->DisplaySize.x * drawData->FramebufferScale.x); | ||
int frameBufferHeight = (int)(drawData->DisplaySize.y * drawData->FramebufferScale.y); | ||
if(frameBufferWidth==0 || frameBufferHeight==0) return false; | ||
plScope("OpenGL engine"); | ||
plVar(frameBufferWidth, frameBufferHeight); | ||
|
||
// Backup GL state | ||
//vwGlBackupState backup; | ||
// Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled, polygon fill | ||
glEnable(GL_BLEND); | ||
glBlendEquation(GL_FUNC_ADD); | ||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); | ||
glDisable(GL_CULL_FACE); | ||
glDisable(GL_DEPTH_TEST); | ||
GL_CHECK(); | ||
|
||
// Clear screen | ||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); | ||
glEnable(GL_SCISSOR_TEST); | ||
GL_CHECK(); | ||
|
||
// Setup viewport, orthographic projection matrix | ||
glViewport(0, 0, (GLsizei)frameBufferWidth, (GLsizei)frameBufferHeight); | ||
ImGuiIO& io = ImGui::GetIO(); | ||
const float ortho_projection[4][4] = { | ||
{ 2.0f/io.DisplaySize.x, 0.0f, 0.0f, 0.0f }, | ||
{ 0.0f, 2.0f/-io.DisplaySize.y, 0.0f, 0.0f }, | ||
{ 0.0f, 0.0f, -1.0f, 0.0f }, | ||
{-1.0f, 1.0f, 0.0f, 1.0f }, | ||
}; | ||
glUseProgram(vwGlCtx.guiGlProgram.getId()); | ||
glUniform1i(vwGlCtx.unifAttribLocationTex, 0); | ||
glUniformMatrix4fv(vwGlCtx.unifAttribLocationProjMtx, 1, GL_FALSE, &ortho_projection[0][0]); | ||
glBindVertexArray(vwGlCtx.guiGlProgram.getVaoId()); | ||
glBindSampler(0, 0); // Rely on combined texture/sampler state. | ||
GL_CHECK(); | ||
|
||
// Will project scissor/clipping rectangles into framebuffer space | ||
ImVec2 clipOff = drawData->DisplayPos; // (0,0) unless using multi-viewports | ||
ImVec2 clipScale = drawData->FramebufferScale; // (1,1) unless using retina display which are often (2,2) | ||
|
||
glBindBuffer(GL_ARRAY_BUFFER, vwGlCtx.guiGlProgram.getVboId()); | ||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vwGlCtx.guiGlProgram.getIboId()); | ||
|
||
for(int n=0; n<drawData->CmdListsCount; ++n) { | ||
plScope("ImGui list"); | ||
const ImDrawList* cmdList = drawData->CmdLists[n]; | ||
const ImDrawIdx* indexBufferOffset = 0; | ||
|
||
glBufferData(GL_ARRAY_BUFFER, (GLsizeiptr)cmdList->VtxBuffer.Size * sizeof(ImDrawVert), | ||
(const GLvoid*)cmdList->VtxBuffer.Data, GL_STREAM_DRAW); | ||
glBufferData(GL_ELEMENT_ARRAY_BUFFER, (GLsizeiptr)cmdList->IdxBuffer.Size * sizeof(ImDrawIdx), | ||
(const GLvoid*)cmdList->IdxBuffer.Data, GL_STREAM_DRAW); | ||
|
||
for(int cmdIdx = 0; cmdIdx<cmdList->CmdBuffer.Size; ++cmdIdx) { | ||
const ImDrawCmd* cmd = &cmdList->CmdBuffer[cmdIdx]; | ||
if(cmd->UserCallback) { | ||
plScope("GL user callback"); | ||
cmd->UserCallback(cmdList, cmd); | ||
} | ||
else { | ||
plScope("GL draw command"); | ||
plData("elements", cmd->ElemCount); | ||
// Project scissor/clipping rectangles into framebuffer space | ||
ImVec4 clipRect; | ||
clipRect.x = (cmd->ClipRect.x-clipOff.x)*clipScale.x; | ||
clipRect.y = (cmd->ClipRect.y-clipOff.y)*clipScale.y; | ||
clipRect.z = (cmd->ClipRect.z-clipOff.x)*clipScale.x; | ||
clipRect.w = (cmd->ClipRect.w-clipOff.y)*clipScale.y; | ||
if(clipRect.x<frameBufferWidth && clipRect.y<frameBufferHeight && clipRect.z>=0.0f && clipRect.w>=0.0f) { | ||
// Apply scissor/clipping rectangle | ||
glScissor((int)cmd->ClipRect.x, (int)(frameBufferHeight-cmd->ClipRect.w), | ||
(int)(cmd->ClipRect.z-cmd->ClipRect.x), (int)(cmd->ClipRect.w-cmd->ClipRect.y)); | ||
// Bind texture, Draw | ||
glBindTexture(GL_TEXTURE_2D, (GLuint)(intptr_t)cmd->TextureId); | ||
glDrawElements(GL_TRIANGLES, (GLsizei)cmd->ElemCount, GL_UNSIGNED_INT, indexBufferOffset); | ||
} | ||
} | ||
indexBufferOffset += cmd->ElemCount; | ||
} | ||
} | ||
|
||
// Restore | ||
glDisable(GL_SCISSOR_TEST); | ||
GL_CHECK(); | ||
//backup.restore(); | ||
|
||
return true; // We drew something | ||
} | ||
|
||
|
||
|
||
void | ||
vwBackendInstallFont(const void* fontData, int fontDataSize, int fontSize) | ||
{ | ||
// Some config | ||
ImGuiIO& io = ImGui::GetIO(); | ||
io.Fonts->Clear(); | ||
io.Fonts->AddFontFromMemoryCompressedTTF(fontData, fontDataSize, fontSize); | ||
|
||
// Build texture atlas | ||
unsigned char* pixels; | ||
int width, height; | ||
io.Fonts->GetTexDataAsAlpha8(&pixels, &width, &height); | ||
|
||
// Upload texture to graphics system | ||
glBindTexture(GL_TEXTURE_2D, vwGlCtx.fontTextureId); | ||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, width, height, 0, GL_RED, GL_UNSIGNED_BYTE, pixels); | ||
io.Fonts->TexID = (void *)(intptr_t)vwGlCtx.fontTextureId; // Store our identifier | ||
GL_CHECK(); | ||
} | ||
|
||
|
||
void | ||
vwBackendUninit(void) | ||
{ | ||
vwGlCtx.guiGlProgram.deinstall(); | ||
if(vwGlCtx.fontTextureId) { | ||
glDeleteTextures(1, &vwGlCtx.fontTextureId); | ||
ImGui::GetIO().Fonts->TexID = 0; | ||
vwGlCtx.fontTextureId = 0; | ||
} | ||
} | ||
|
||
|
||
#endif // if defined(__linux__) || defined(_WIN32) |
Oops, something went wrong.