"Blank" window

This commit is contained in:
Emmanuel BENOîT 2017-09-30 10:37:45 +02:00
parent 0665b12d6c
commit 28088760b9
9 changed files with 1073 additions and 28 deletions

2
.gitignore vendored
View file

@ -1,4 +1,4 @@
editor demo
*.o *.o
fd-*.h fd-*.h
imgui.ini imgui.ini

View file

@ -46,9 +46,7 @@ flags = [
'c++', 'c++',
'-I','.', '-I','.',
'-I','imgui', '-I','imgui',
'-I','imguifs',
'-I','glm/glm', '-I','glm/glm',
'-I','picojson',
'-I','/usr/include/SDL2' '-I','/usr/include/SDL2'
] ]

View file

@ -1,36 +1,29 @@
CXXFLAGS += $(shell sdl2-config --cflags) -std=c++14 -Wall CXXFLAGS += $(shell sdl2-config --cflags) -std=c++14 -Wall
CFLAGS += $(shell sdl2-config --cflags) CFLAGS += $(shell sdl2-config --cflags)
CPPFLAGS += -I. -Iimgui -Iimguifs -Iglm -Ipicojson \ CPPFLAGS += -I. -Iimgui -Iglm \
-DREAL_BUILD -DGLM_ENABLE_EXPERIMENTAL -DREAL_BUILD -DGLM_ENABLE_EXPERIMENTAL
LIBS += $(shell sdl2-config --libs) -lGL -lGLEW -ldl LIBS += $(shell sdl2-config --libs) -lGL -lGLEW -ldl
FILEDUMPS = \ FILEDUMPS =
fd-raymarcher.glsl.h
IMGUI = imgui.o imgui_demo.o imgui_draw.o imguifs.o IMGUI = imgui.o imgui_demo.o imgui_draw.o
EDITOR = \ DEMO = \
editor.o \ main.o \
imgui_impl_sdl.o \ imgui_impl_sdl.o \
utilities.o \ utilities.o
project.o \
\
mg-none.o \
mg-fragment.o \
\
gfx-raymarcher.o
EDITOR_DEPS = $(EDITOR:%.o=.%.d) DEMO_DEPS = $(DEMO:%.o=.%.d)
editor: $(EDITOR) $(IMGUI) demo: $(DEMO) $(IMGUI)
$(CXX) $(CXXFLAGS) $(CPPFLAGS) -o editor \ $(CXX) $(CXXFLAGS) $(CPPFLAGS) -o demo \
$(EDITOR) $(IMGUI) $(LIBS) $(DEMO) $(IMGUI) $(LIBS)
clean: clean:
rm -f $(IMGUI) $(EDITOR) $(FILEDUMPS) editor externals.hh.gch rm -f $(IMGUI) $(DEMO) $(FILEDUMPS) demo externals.hh.gch
fullclean: clean fullclean: clean
rm -f $(EDITOR_DEPS) rm -f $(DEMO_DEPS)
.PHONY: clean fullclean .PHONY: clean fullclean
@ -48,13 +41,9 @@ imgui_demo.o: imgui/imgui_demo.cpp
imgui_draw.o: imgui/imgui_draw.cpp imgui_draw.o: imgui/imgui_draw.cpp
$(CXX) $(CXXFLAGS) $(CPPFLAGS) -c -o $@ $< $(CXX) $(CXXFLAGS) $(CPPFLAGS) -c -o $@ $<
imguifs.o: imguifs/imguifilesystem.cpp imguifs/dirent_portable.h imguifs/imguifilesystem.h -include $(DEMO_DEPS)
$(CXX) $(CXXFLAGS) $(CPPFLAGS) -include /usr/include/stdlib.h -c -o $@ $<
$(DEMO): %.o: %.cc externals.hh.gch | $(FILEDUMPS)
-include $(EDITOR_DEPS)
$(EDITOR): %.o: %.cc externals.hh.gch | $(FILEDUMPS)
$(CXX) $(CXXFLAGS) $(CPPFLAGS) -c -o $@ $< $(CXX) $(CXXFLAGS) $(CPPFLAGS) -c -o $@ $<
$(CXX) $(CXXFLAGS) $(CPPFLAGS) -M -MF $(@:%.o=.%.d) -MT $@ $< $(CXX) $(CXXFLAGS) $(CPPFLAGS) -M -MF $(@:%.o=.%.d) -MT $@ $<

32
externals.hh Normal file
View file

@ -0,0 +1,32 @@
// C
#include <stdio.h>
// System (C)
#include <sys/inotify.h>
#include <fcntl.h>
#include <libgen.h>
#include <unistd.h>
// Misc (C)
#include <SDL.h>
#include <GL/glew.h>
// C++ std
#include <vector>
#include <string>
#include <algorithm>
#include <functional>
#include <memory>
#include <fstream>
// ImGui
#include <imgui.h>
// GLM
#include <glm/mat3x3.hpp>
#include <glm/gtx/euler_angles.hpp>
// Silly decoration macros I use everywhere
#define __rd__
#define __wr__
#define __rw__

282
imgui_impl_sdl.cc Normal file
View file

@ -0,0 +1,282 @@
// ImGui SDL2 binding with OpenGL
// In this binding, ImTextureID is used to store an OpenGL 'GLuint' texture identifier. Read the FAQ about ImTextureID in imgui.cpp.
// You can copy and use unmodified imgui_impl_* files in your project. See main.cpp for an example of using this.
// If you use this binding you'll need to call 4 functions: ImGui_ImplXXXX_Init(), ImGui_ImplXXXX_NewFrame(), ImGui::Render() and ImGui_ImplXXXX_Shutdown().
// If you are new to ImGui, see examples/README.txt and documentation at the top of imgui.cpp.
// https://github.com/ocornut/imgui
#include "externals.hh"
#include "imgui_impl_sdl.h"
// Data
static double g_Time = 0.0f;
static bool g_MousePressed[3] = { false, false, false };
static float g_MouseWheel = 0.0f;
static GLuint g_FontTexture = 0;
// This is the main rendering function that you have to implement and provide to ImGui (via setting up 'RenderDrawListsFn' in the ImGuiIO structure)
// If text or lines are blurry when integrating ImGui in your engine:
// - in your Render function, try translating your projection matrix by (0.5f,0.5f) or (0.375f,0.375f)
void ImGui_ImplSdl_RenderDrawLists(ImDrawData* draw_data)
{
// Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates)
ImGuiIO& io = ImGui::GetIO();
int fb_width = (int)(io.DisplaySize.x * io.DisplayFramebufferScale.x);
int fb_height = (int)(io.DisplaySize.y * io.DisplayFramebufferScale.y);
if (fb_width == 0 || fb_height == 0)
return;
draw_data->ScaleClipRects(io.DisplayFramebufferScale);
// We are using the OpenGL fixed pipeline to make the example code simpler to read!
// Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled, vertex/texcoord/color pointers.
GLint last_texture; glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture);
GLint last_viewport[4]; glGetIntegerv(GL_VIEWPORT, last_viewport);
GLint last_scissor_box[4]; glGetIntegerv(GL_SCISSOR_BOX, last_scissor_box);
glPushAttrib(GL_ENABLE_BIT | GL_COLOR_BUFFER_BIT | GL_TRANSFORM_BIT);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glDisable(GL_CULL_FACE);
glDisable(GL_DEPTH_TEST);
glEnable(GL_SCISSOR_TEST);
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);
glEnable(GL_TEXTURE_2D);
//glUseProgram(0); // You may want this if using this code in an OpenGL 3+ context
// Setup viewport, orthographic projection matrix
glViewport(0, 0, (GLsizei)fb_width, (GLsizei)fb_height);
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
glOrtho(0.0f, io.DisplaySize.x, io.DisplaySize.y, 0.0f, -1.0f, +1.0f);
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();
// Render command lists
#define OFFSETOF(TYPE, ELEMENT) ((size_t)&(((TYPE *)0)->ELEMENT))
for (int n = 0; n < draw_data->CmdListsCount; n++)
{
const ImDrawList* cmd_list = draw_data->CmdLists[n];
const ImDrawVert* vtx_buffer = cmd_list->VtxBuffer.Data;
const ImDrawIdx* idx_buffer = cmd_list->IdxBuffer.Data;
glVertexPointer(2, GL_FLOAT, sizeof(ImDrawVert), (const GLvoid*)((const char*)vtx_buffer + OFFSETOF(ImDrawVert, pos)));
glTexCoordPointer(2, GL_FLOAT, sizeof(ImDrawVert), (const GLvoid*)((const char*)vtx_buffer + OFFSETOF(ImDrawVert, uv)));
glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(ImDrawVert), (const GLvoid*)((const char*)vtx_buffer + OFFSETOF(ImDrawVert, col)));
for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++)
{
const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i];
if (pcmd->UserCallback)
{
pcmd->UserCallback(cmd_list, pcmd);
}
else
{
glBindTexture(GL_TEXTURE_2D, (GLuint)(intptr_t)pcmd->TextureId);
glScissor((int)pcmd->ClipRect.x, (int)(fb_height - pcmd->ClipRect.w), (int)(pcmd->ClipRect.z - pcmd->ClipRect.x), (int)(pcmd->ClipRect.w - pcmd->ClipRect.y));
glDrawElements(GL_TRIANGLES, (GLsizei)pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, idx_buffer);
}
idx_buffer += pcmd->ElemCount;
}
}
#undef OFFSETOF
// Restore modified state
glDisableClientState(GL_COLOR_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);
glBindTexture(GL_TEXTURE_2D, (GLuint)last_texture);
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glPopAttrib();
glViewport(last_viewport[0], last_viewport[1], (GLsizei)last_viewport[2], (GLsizei)last_viewport[3]);
glScissor(last_scissor_box[0], last_scissor_box[1], (GLsizei)last_scissor_box[2], (GLsizei)last_scissor_box[3]);
}
static const char* ImGui_ImplSdl_GetClipboardText(void*)
{
return SDL_GetClipboardText();
}
static void ImGui_ImplSdl_SetClipboardText(void*, const char* text)
{
SDL_SetClipboardText(text);
}
bool ImGui_ImplSdl_ProcessEvent(SDL_Event* event)
{
ImGuiIO& io = ImGui::GetIO();
switch (event->type)
{
case SDL_MOUSEWHEEL:
{
if (event->wheel.y > 0)
g_MouseWheel = 1;
if (event->wheel.y < 0)
g_MouseWheel = -1;
return true;
}
case SDL_MOUSEBUTTONDOWN:
{
if (event->button.button == SDL_BUTTON_LEFT) g_MousePressed[0] = true;
if (event->button.button == SDL_BUTTON_RIGHT) g_MousePressed[1] = true;
if (event->button.button == SDL_BUTTON_MIDDLE) g_MousePressed[2] = true;
return true;
}
case SDL_TEXTINPUT:
{
io.AddInputCharactersUTF8(event->text.text);
return true;
}
case SDL_KEYDOWN:
case SDL_KEYUP:
{
int key = event->key.keysym.sym & ~SDLK_SCANCODE_MASK;
io.KeysDown[key] = (event->type == SDL_KEYDOWN);
io.KeyShift = ((SDL_GetModState() & KMOD_SHIFT) != 0);
io.KeyCtrl = ((SDL_GetModState() & KMOD_CTRL) != 0);
io.KeyAlt = ((SDL_GetModState() & KMOD_ALT) != 0);
io.KeySuper = ((SDL_GetModState() & KMOD_GUI) != 0);
return true;
}
}
return false;
}
bool ImGui_ImplSdl_CreateDeviceObjects()
{
// Build texture atlas
ImGuiIO& io = ImGui::GetIO();
unsigned char* pixels;
int width, height;
io.Fonts->GetTexDataAsAlpha8(&pixels, &width, &height);
// Upload texture to graphics system
GLint last_texture;
glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture);
glGenTextures(1, &g_FontTexture);
glBindTexture(GL_TEXTURE_2D, g_FontTexture);
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);
glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, width, height, 0, GL_ALPHA, GL_UNSIGNED_BYTE, pixels);
// Store our identifier
io.Fonts->TexID = (void *)(intptr_t)g_FontTexture;
// Restore state
glBindTexture(GL_TEXTURE_2D, last_texture);
return true;
}
void ImGui_ImplSdl_InvalidateDeviceObjects()
{
if (g_FontTexture)
{
glDeleteTextures(1, &g_FontTexture);
ImGui::GetIO().Fonts->TexID = 0;
g_FontTexture = 0;
}
}
bool ImGui_ImplSdl_Init(SDL_Window* window)
{
ImGuiIO& io = ImGui::GetIO();
io.KeyMap[ImGuiKey_Tab] = SDLK_TAB; // Keyboard mapping. ImGui will use those indices to peek into the io.KeyDown[] array.
io.KeyMap[ImGuiKey_LeftArrow] = SDL_SCANCODE_LEFT;
io.KeyMap[ImGuiKey_RightArrow] = SDL_SCANCODE_RIGHT;
io.KeyMap[ImGuiKey_UpArrow] = SDL_SCANCODE_UP;
io.KeyMap[ImGuiKey_DownArrow] = SDL_SCANCODE_DOWN;
io.KeyMap[ImGuiKey_PageUp] = SDL_SCANCODE_PAGEUP;
io.KeyMap[ImGuiKey_PageDown] = SDL_SCANCODE_PAGEDOWN;
io.KeyMap[ImGuiKey_Home] = SDL_SCANCODE_HOME;
io.KeyMap[ImGuiKey_End] = SDL_SCANCODE_END;
io.KeyMap[ImGuiKey_Delete] = SDLK_DELETE;
io.KeyMap[ImGuiKey_Backspace] = SDLK_BACKSPACE;
io.KeyMap[ImGuiKey_Enter] = SDLK_RETURN;
io.KeyMap[ImGuiKey_Escape] = SDLK_ESCAPE;
io.KeyMap[ImGuiKey_A] = SDLK_a;
io.KeyMap[ImGuiKey_C] = SDLK_c;
io.KeyMap[ImGuiKey_V] = SDLK_v;
io.KeyMap[ImGuiKey_X] = SDLK_x;
io.KeyMap[ImGuiKey_Y] = SDLK_y;
io.KeyMap[ImGuiKey_Z] = SDLK_z;
io.RenderDrawListsFn = ImGui_ImplSdl_RenderDrawLists; // Alternatively you can set this to NULL and call ImGui::GetDrawData() after ImGui::Render() to get the same ImDrawData pointer.
io.SetClipboardTextFn = ImGui_ImplSdl_SetClipboardText;
io.GetClipboardTextFn = ImGui_ImplSdl_GetClipboardText;
io.ClipboardUserData = NULL;
#ifdef _WIN32
SDL_SysWMinfo wmInfo;
SDL_VERSION(&wmInfo.version);
SDL_GetWindowWMInfo(window, &wmInfo);
io.ImeWindowHandle = wmInfo.info.win.window;
#else
(void)window;
#endif
return true;
}
void ImGui_ImplSdl_Shutdown()
{
ImGui_ImplSdl_InvalidateDeviceObjects();
ImGui::Shutdown();
}
void ImGui_ImplSdl_NewFrame(SDL_Window *window ,
bool mouseLock,ImVec2 const& mousePos)
{
if (!g_FontTexture)
ImGui_ImplSdl_CreateDeviceObjects();
ImGuiIO& io = ImGui::GetIO();
// Setup display size (every frame to accommodate for window resizing)
int w, h;
int display_w, display_h;
SDL_GetWindowSize(window, &w, &h);
SDL_GL_GetDrawableSize(window, &display_w, &display_h);
io.DisplaySize = ImVec2((float)w, (float)h);
io.DisplayFramebufferScale = ImVec2(w > 0 ? ((float)display_w / w) : 0, h > 0 ? ((float)display_h / h) : 0);
// Setup time step
Uint32 time = SDL_GetTicks();
double current_time = time / 1000.0;
io.DeltaTime = g_Time > 0.0 ? (float)(current_time - g_Time) : (float)(1.0f/60.0f);
g_Time = current_time;
// Setup inputs
// (we already got mouse wheel, keyboard keys & characters from SDL_PollEvent())
int mx, my;
Uint32 mouseMask = SDL_GetMouseState(&mx, &my);
if ( mouseLock ) {
io.MousePos = mousePos;
} else {
if (SDL_GetWindowFlags(window) & SDL_WINDOW_MOUSE_FOCUS)
io.MousePos = ImVec2((float)mx, (float)my); // Mouse position, in pixels (set to -1,-1 if no mouse / on another screen, etc.)
else
io.MousePos = ImVec2(-1,-1);
}
io.MouseDown[0] = g_MousePressed[0] || (mouseMask & SDL_BUTTON(SDL_BUTTON_LEFT)) != 0; // If a mouse press event came, always pass it as "mouse held this frame", so we don't miss click-release events that are shorter than 1 frame.
io.MouseDown[1] = g_MousePressed[1] || (mouseMask & SDL_BUTTON(SDL_BUTTON_RIGHT)) != 0;
io.MouseDown[2] = g_MousePressed[2] || (mouseMask & SDL_BUTTON(SDL_BUTTON_MIDDLE)) != 0;
g_MousePressed[0] = g_MousePressed[1] = g_MousePressed[2] = false;
io.MouseWheel = g_MouseWheel;
g_MouseWheel = 0.0f;
// Hide OS mouse cursor if ImGui is drawing it
SDL_ShowCursor(io.MouseDrawCursor ? 0 : 1);
// Start the frame
ImGui::NewFrame();
}

20
imgui_impl_sdl.h Normal file
View file

@ -0,0 +1,20 @@
// ImGui SDL2 binding with OpenGL
// In this binding, ImTextureID is used to store an OpenGL 'GLuint' texture identifier. Read the FAQ about ImTextureID in imgui.cpp.
// You can copy and use unmodified imgui_impl_* files in your project. See main.cpp for an example of using this.
// If you use this binding you'll need to call 4 functions: ImGui_ImplXXXX_Init(), ImGui_ImplXXXX_NewFrame(), ImGui::Render() and ImGui_ImplXXXX_Shutdown().
// If you are new to ImGui, see examples/README.txt and documentation at the top of imgui.cpp.
// https://github.com/ocornut/imgui
struct SDL_Window;
typedef union SDL_Event SDL_Event;
IMGUI_API bool ImGui_ImplSdl_Init(SDL_Window* window);
IMGUI_API void ImGui_ImplSdl_Shutdown();
IMGUI_API void ImGui_ImplSdl_NewFrame(SDL_Window* window,
bool mouseLock,ImVec2 const& mousePos);
IMGUI_API bool ImGui_ImplSdl_ProcessEvent(SDL_Event* event);
// Use if you want to reset your rendering device without losing ImGui state.
IMGUI_API void ImGui_ImplSdl_InvalidateDeviceObjects();
IMGUI_API bool ImGui_ImplSdl_CreateDeviceObjects();

179
main.cc Normal file
View file

@ -0,0 +1,179 @@
#include "externals.hh"
#include "imgui_impl_sdl.h"
#include "utilities.hh"
/*= T_Main ===================================================================*/
struct T_Main
{
T_Main( );
~T_Main( );
void mainLoop( );
private:
const std::string projectFile;
SDL_Window * window;
SDL_GLContext gl;
T_FilesWatcher watcher;
std::string loadError;
bool done = false;
bool capture = false;
ImVec2 mouseInitial;
ImVec2 mouseMove;
void startIteration( );
void handleCapture( );
void makeUI( );
void render( );
};
/*----------------------------------------------------------------------------*/
T_Main::T_Main( )
{
SDL_Init( SDL_INIT_VIDEO | SDL_INIT_TIMER );
// Setup window
SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER , 1 );
SDL_GL_SetAttribute( SDL_GL_DEPTH_SIZE , 24 );
SDL_GL_SetAttribute( SDL_GL_STENCIL_SIZE , 8 );
SDL_GL_SetAttribute( SDL_GL_CONTEXT_MAJOR_VERSION , 2 );
SDL_GL_SetAttribute( SDL_GL_CONTEXT_MINOR_VERSION , 2 );
SDL_DisplayMode current;
SDL_GetCurrentDisplayMode( 0 , &current );
window = SDL_CreateWindow( "DEMO",
SDL_WINDOWPOS_CENTERED , SDL_WINDOWPOS_CENTERED ,
1280 , 720 ,
SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE );
gl = SDL_GL_CreateContext( window );
glewInit();
ImGui_ImplSdl_Init( window );
}
void T_Main::mainLoop( )
{
while ( !done ) {
startIteration( );
if ( !done ) {
handleCapture( );
makeUI( );
watcher.check( );
render( );
}
}
}
T_Main::~T_Main( )
{
ImGui_ImplSdl_Shutdown( );
SDL_GL_DeleteContext( gl );
SDL_DestroyWindow( window );
SDL_Quit( );
}
/*----------------------------------------------------------------------------*/
void T_Main::startIteration( )
{
SDL_Event event;
mouseMove = ImVec2( );
while ( SDL_PollEvent( &event ) ) {
ImGui_ImplSdl_ProcessEvent( &event );
if ( event.type == SDL_QUIT ) {
done = true;
return;
}
if ( capture && event.type == SDL_MOUSEMOTION ) {
mouseMove.x += event.motion.xrel;
mouseMove.y += event.motion.yrel;
}
}
ImGui_ImplSdl_NewFrame( window , capture , mouseInitial );
ImGui::GetIO( ).MouseDrawCursor = true;
}
void T_Main::handleCapture( )
{
auto const& io( ImGui::GetIO( ) );
const bool lmb( ImGui::IsMouseDown( 0 ) );
const bool mb( lmb || ImGui::IsMouseDown( 1 ) );
const bool appCanGrab( !( ImGui::IsMouseHoveringAnyWindow( )
|| io.WantCaptureMouse
|| io.WantCaptureKeyboard ) );
const bool shift( io.KeyShift );
const bool ctrl( io.KeyCtrl );
if ( capture && !mb ) {
capture = false;
ImGui::CaptureMouseFromApp( false );
SDL_SetRelativeMouseMode( SDL_FALSE );
SDL_WarpMouseInWindow( window ,
int( mouseInitial.x ) ,
int( mouseInitial.y ) );
ImGui::SetMouseCursor( ImGuiMouseCursor_Arrow );
} else if ( capture ) {
ImGui::SetMouseCursor( ImGuiMouseCursor_Move );
//project->handleDND( mouseMove , ctrl , shift , lmb );
// FIXME: D'n'D
} else if ( appCanGrab && mb ) {
capture = true;
mouseInitial = ImGui::GetMousePos( );
ImGui::CaptureMouseFromApp( true );
SDL_SetRelativeMouseMode( SDL_TRUE );
ImGui::SetMouseCursor( ImGuiMouseCursor_Move );
}
if ( ( appCanGrab || capture ) && io.MouseWheel ) {
//project->handleWheel( io.MouseWheel , ctrl , shift );
// FIXME wheel
}
}
void T_Main::makeUI( )
{
}
void T_Main::render( )
{
auto const& dspSize( ImGui::GetIO( ).DisplaySize );
glViewport( 0 , 0 , (int) dspSize.x, (int) dspSize.y );
glClearColor( 1 , 0 , 1 , 1 );
glClear( GL_COLOR_BUFFER_BIT );
// FIXME draw the fuck
//project->render( );
glUseProgram( 0 );
ImGui::Render( );
SDL_GL_SwapWindow( window );
}
/*============================================================================*/
int main( int , char** )
{
T_Main m;
m.mainLoop( );
#if 0
// Frame time history
const int nFrameTimes = 200;
float frameTimes[ nFrameTimes ];
memset( frameTimes , 0 , sizeof( float ) * nFrameTimes );
#endif
#if 0
// Update frame time history
memmove( frameTimes , &frameTimes[ 1 ] ,
( nFrameTimes - 1 ) * sizeof( float ) );
frameTimes[ nFrameTimes - 1 ] = 1000.0f / ImGui::GetIO( ).Framerate;
#endif
return 0;
}

379
utilities.cc Normal file
View file

@ -0,0 +1,379 @@
#include "externals.hh"
#include "utilities.hh"
void disableButton( )
{
ImGui::PushStyleColor( ImGuiCol_Button , ImColor( .3f , .3f , .3f ) );
ImGui::PushStyleColor( ImGuiCol_ButtonHovered , ImColor( .3f , .3f , .3f ) );
ImGui::PushStyleColor( ImGuiCol_ButtonActive , ImColor( .3f , .3f , .3f ) );
}
/*----------------------------------------------------------------------------*/
void updateAngle(
__rw__ float& initial ,
__rd__ const float delta
)
{
initial = fmod( initial + delta + 540 , 360 ) - 180;
}
void anglesToMatrix(
__rd__ float const* angles ,
__wr__ float* matrix )
{
float c[3] , s[3];
for ( int i = 0 ; i < 3 ; i ++ ) {
const float a = M_PI * angles[ i ] / 180;
c[i] = cos( a );
s[i] = sin( a );
}
matrix[0] = c[1]*c[2];
matrix[1] = s[0]*s[1]*c[2] - c[0]*s[2];
matrix[2] = s[0]*s[2] + c[0]*s[1]*c[2];
matrix[3] = c[1]*s[2];
matrix[4] = c[0]*c[2] + s[0]*s[1]*s[2];
matrix[5] = c[0]*s[1]*s[2] - s[0]*c[2];
matrix[6] = -s[1];
matrix[7] = s[0]*c[1];
matrix[8] = c[0]*c[1];
}
/*= T_FilesWatcher ===========================================================*/
T_FilesWatcher::T_FilesWatcher( )
: fd( inotify_init1( O_NONBLOCK ) )
{ }
T_FilesWatcher::T_FilesWatcher( T_FilesWatcher&& other ) noexcept
: fd( 0 ) , watched( std::move( other.watched ) )
{
std::swap( fd , other.fd );
other.watched.clear( );
for ( T_WatchedFiles* wf : watched ) {
if ( wf ) {
wf->watcher = this;
}
}
}
T_FilesWatcher::~T_FilesWatcher( )
{
if ( fd ) {
close( fd );
}
for ( T_WatchedFiles* wf : watched ) {
if ( wf ) {
wf->watcher = nullptr;
}
}
}
void T_FilesWatcher::check( )
{
for ( T_WatchedFiles* wf : watched ) {
if ( wf ) {
wf->triggered = false;
}
}
inotify_event ie;
while ( read( fd , &ie , sizeof( ie ) ) == sizeof( ie ) ) {
if ( ( ie.mask & ( IN_CLOSE_WRITE | IN_DELETE_SELF ) ) == 0 ) {
continue;
}
for ( T_WatchedFiles* wf : watched ) {
if ( !wf || wf->triggered ) {
continue;
}
auto const& idl( wf->identifiers );
if ( find( idl , ie.wd ) != idl.end( ) ) {
wf->triggered = true;
wf->callback( );
}
}
}
}
/*= T_WatchedFiles ===========================================================*/
T_WatchedFiles::T_WatchedFiles( T_WatchedFiles&& other ) noexcept
: watcher( other.watcher ) , callback( other.callback ) ,
triggered( other.triggered ) ,
identifiers( std::move( other.identifiers ) )
{
if ( watcher ) {
other.watcher = nullptr;
*( find( watcher->watched , &other ) ) = this;
}
}
T_WatchedFiles::T_WatchedFiles(
__rw__ T_FilesWatcher& watcher ,
__rd__ const F_OnFileChanges callback )
: watcher( &watcher ) , callback( callback ) , triggered( false )
{
watcher.watched.push_back( this );
}
T_WatchedFiles::~T_WatchedFiles( )
{
clear( );
if ( watcher ) {
watcher->watched.erase( find( watcher->watched , this ) );
}
}
void T_WatchedFiles::clear( )
{
if ( watcher ) {
const auto fd( watcher->fd );
for ( int wd : identifiers ) {
inotify_rm_watch( fd , wd );
}
}
identifiers.clear( );
}
bool T_WatchedFiles::watch(
__rd__ std::string const& file )
{
static constexpr auto inFlags( IN_CLOSE_WRITE | IN_DELETE_SELF );
if ( watcher ) {
const auto wd( inotify_add_watch( watcher->fd ,
file.c_str( ) , inFlags ) );
if ( wd == -1 ) {
return false;
}
if ( find( identifiers , wd ) == identifiers.end( ) ) {
identifiers.push_back( wd );
}
return true;
}
return false;
}
/*= T_ShaderCode =============================================================*/
T_ShaderCode::T_ShaderCode(
__rd__ const int nparts )
: code( nparts , nullptr )
{ }
T_ShaderCode::~T_ShaderCode( )
{
for ( char* str : code ) {
delete[] str;
}
}
/*----------------------------------------------------------------------------*/
void T_ShaderCode::setPart(
__rd__ const int index ,
__rd__ char const* const string )
{
assert( code[ index ] == nullptr );
const int len( strlen( string ) + 1 );
char buffer[ 32 ];
const int extraLen( index == 0 ? 0
: snprintf( buffer , sizeof( buffer ) ,
"\n#line 0 %d\n" , index ) );
char* const output( new char[ extraLen + len ] );
if ( index != 0 ) {
memcpy( output , buffer , extraLen );
}
strcpy( output + extraLen , string );
code[ index ] = output;
}
void T_ShaderCode::setPart(
__rd__ const int index ,
__rd__ void const* const data ,
__rd__ const int size )
{
assert( code[ index ] == nullptr );
char buffer[ 32 ];
const int extraLen( index == 0 ? 0
: snprintf( buffer , sizeof( buffer ) ,
"\n#line 0 %d\n" , index ) );
char* const output( new char[ extraLen + size + 1 ] );
if ( index != 0 ) {
memcpy( output , buffer , extraLen );
}
memcpy( output + extraLen , data , size );
output[ extraLen + size ] = 0;
code[ index ] = output;
}
bool T_ShaderCode::loadPart(
__rd__ const int index ,
__rd__ std::string const& source ,
__rw__ std::vector< std::string >& errors )
{
assert( code[ index ] == nullptr );
FILE * f = fopen( source.c_str( ) , "r" );
if ( !f ) {
std::string error( "File not found: " );
error += source;
errors.push_back( error );
return false;
}
char buffer[ 32 ];
const int extraLen( index == 0 ? 0
: snprintf( buffer , sizeof( buffer ) ,
"\n#line 0 %d\n" , index ) );
fseek( f , 0 , SEEK_END );
const size_t size( ftell( f ) );
fseek( f , 0 , SEEK_SET );
char* const output( new char[ extraLen + size + 1 ] );
if ( index != 0 ) {
memcpy( output , buffer , extraLen );
}
if ( fread( output + extraLen , 1 , size , f ) != size ) {
fclose( f );
delete[] output;
std::string error( "Could not read file: " );
error += source;
errors.push_back( error );
return false;
}
output[ extraLen + size ] = 0;
fclose( f );
code[ index ] = output;
return true;
}
/*----------------------------------------------------------------------------*/
GLuint T_ShaderCode::createProgram(
__rd__ GLenum type ,
__rw__ std::vector< std::string >& errors ) const
{
GLenum sid = glCreateShaderProgramv( type , code.size( ) , &code[ 0 ] );
if ( sid == 0 ) {
errors.push_back( "Failed to create GL program" );
return sid;
}
int infoLogLength;
glGetProgramiv( sid , GL_INFO_LOG_LENGTH , &infoLogLength );
if ( infoLogLength ) {
char buffer[ infoLogLength + 1 ];
glGetProgramInfoLog( sid , infoLogLength , nullptr , buffer );
char* start( buffer );
char* found( strchr( buffer , '\n' ) );
while ( found ) {
*found = 0;
errors.push_back( start );
start = found + 1;
found = strchr( start , '\n' );
}
if ( start < &buffer[ infoLogLength - 1 ] ) {
errors.push_back( start );
}
}
int lnk;
glGetProgramiv( sid , GL_LINK_STATUS , &lnk );
if ( !lnk ) {
glDeleteProgram( sid );
return 0;
}
return sid;
}
/*= T_Camera =================================================================*/
void T_Camera::handleDND(
__rd__ ImVec2 const& move ,
__rd__ const bool hasCtrl ,
__rd__ const bool hasShift ,
__rd__ const bool lmb // Left mouse button
)
{
if ( move.x == 0 || move.y == 0 ) {
return;
}
const float fdx( move.x * .1f * ( hasCtrl ? 1.f : .1f ) );
const float fdy( move.y * .1f * ( hasCtrl ? 1.f : .1f ) );
if ( lmb && hasShift ) {
// Left mouse button, shift - move camera
const auto side( glm::normalize( glm::cross( up , dir ) ) );
lookAt += .01f * ( side * fdx + up * fdy );
} else if ( lmb ) {
// Left mouse button, no shift - change yaw/pitch
updateAngle( angles.y , fdx );
updateAngle( angles.x , fdy );
} else {
// Right mouse button - change roll
updateAngle( angles.z , fdx );
}
update( );
}
void T_Camera::handleWheel(
__rd__ const float wheel ,
__rd__ const bool hasCtrl ,
__rd__ const bool hasShift
)
{
const float delta( wheel * ( hasCtrl ? 1.f : .1f) );
if ( hasShift ) {
fov = std::max( 1.f , std::min( 179.f , fov + delta ) );
} else {
distance = std::max( .01f , distance - delta );
}
update( );
}
/*----------------------------------------------------------------------------*/
void T_Camera::makeUI( )
{
if ( !ImGui::CollapsingHeader( "Camera" ) ) {
return;
}
const bool changed[] = {
ImGui::DragFloat3( "Look at" , &lookAt.x ) ,
ImGui::DragFloat( "Distance" , &distance , .1f ,
.1f , 1e8 , "%.1f" ) ,
ImGui::DragFloat3( "Angles" , &angles.x , .01f , -180 , 180 ) ,
ImGui::DragFloat( "FoV" , &fov , .01f , .01f , 179.9f )
};
for ( unsigned i = 0 ; i < sizeof( changed ) / sizeof( bool ) ; i ++ ) {
if ( changed[ i ] ) {
update( );
break;
}
}
}
/*----------------------------------------------------------------------------*/
void T_Camera::update( )
{
anglesToMatrix( &angles.x , &rotMat[ 0 ].x );
dir = glm::vec3( 0 , 0 , -distance ) * rotMat;
up = glm::vec3( 0 , 1 , 0 ) * rotMat;
pos = lookAt - dir;
np = 2 * tan( M_PI * ( 180. - fov ) / 360. );
}

166
utilities.hh Normal file
View file

@ -0,0 +1,166 @@
#pragma once
#ifndef REAL_BUILD
# include "externals.hh"
#endif
/*= Utilities ================================================================*/
// Disable next ImGui button(s)
void disableButton( );
// Re-enable ImGui buttons
inline void reenableButtons( )
{
ImGui::PopStyleColor( 3 );
}
/*----------------------------------------------------------------------------*/
// Add some value to an angle, keeping it in [-180;180]
void updateAngle(
__rw__ float& initial ,
__rd__ const float delta
);
// Make a rotation matrix from three YPR angles (in degrees)
void anglesToMatrix(
__rd__ float const* angles ,
__wr__ float* matrix );
/*----------------------------------------------------------------------------*/
// Helpers for finding entries in collections
template< typename T , typename I >
inline auto find(
__rd__ T const& collection ,
__rd__ I const& item )
{
return std::find( collection.begin( ) , collection.end( ) , item );
}
template< typename T , typename I >
inline auto find(
__rw__ T& collection ,
__rd__ I const& item )
{
return std::find( collection.begin( ) , collection.end( ) , item );
}
/*= T_FilesWatcher / T_WatchedFiles ==========================================*/
struct T_FilesWatcher;
struct T_WatchedFiles;
using F_OnFileChanges = std::function< void( void ) >;
struct T_FilesWatcher
{
friend struct T_WatchedFiles;
T_FilesWatcher( T_FilesWatcher const& ) = delete;
T_FilesWatcher( );
T_FilesWatcher( T_FilesWatcher&& ) noexcept;
~T_FilesWatcher( );
void check( );
private:
int fd;
std::vector< T_WatchedFiles* > watched;
};
/*----------------------------------------------------------------------------*/
struct T_WatchedFiles
{
friend struct T_FilesWatcher;
T_WatchedFiles( ) = delete;
T_WatchedFiles( T_WatchedFiles const& ) = delete;
T_WatchedFiles( T_WatchedFiles&& ) noexcept;
T_WatchedFiles(
__rw__ T_FilesWatcher& watcher ,
__rd__ const F_OnFileChanges callback );
~T_WatchedFiles( );
void clear( );
bool watch( __rd__ std::string const& file );
private:
T_FilesWatcher* watcher;
const F_OnFileChanges callback;
bool triggered;
std::vector< int > identifiers;
};
/*= T_ShaderCode =============================================================*/
struct T_ShaderCode
{
T_ShaderCode( ) = delete;
T_ShaderCode( T_ShaderCode const& ) = delete;
T_ShaderCode( T_ShaderCode&& ) = delete;
explicit T_ShaderCode( __rd__ const int nparts );
~T_ShaderCode( );
void setPart(
__rd__ const int index ,
__rd__ char const* const string );
void setPart(
__rd__ const int index ,
__rd__ void const* const data ,
__rd__ const int size );
bool loadPart(
__rd__ const int index ,
__rd__ std::string const& source ,
__rw__ std::vector< std::string >& errors );
GLuint createProgram(
__rd__ GLenum type ,
__rw__ std::vector< std::string >& errors ) const;
private:
std::vector< char* > code;
};
/*= T_Camera =================================================================*/
struct T_Camera
{
glm::vec3 lookAt;
glm::vec3 angles;
float distance = 10;
float fov = 90;
// Everything below is updated by update()
glm::vec3 dir;
glm::vec3 up;
glm::vec3 pos;
float np;
T_Camera()
{ update( ); }
void handleDND(
__rd__ ImVec2 const& move ,
__rd__ const bool hasCtrl ,
__rd__ const bool hasShift ,
__rd__ const bool lmb // Left mouse button
);
void handleWheel(
__rd__ const float wheel ,
__rd__ const bool hasCtrl ,
__rd__ const bool hasShift
);
void makeUI( );
private:
glm::mat3x3 rotMat;
float rotationMatrix[ 9 ];
void update( );
};