From 98a818419870a3f8b9fe6ce57cc8ee8e113ecf30 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Sun, 28 Jun 2009 16:16:57 +0100 Subject: [PATCH] Integrate FLTK into the editor --- include/OpenGLHelper.hpp | 5 ++++ src/Editor.cpp | 2 ++ src/FLTKWindow.cpp | 53 ++++++++++++++++++++++++++++++--- src/Main.cpp | 4 +-- src/OpenGLHelper.cpp | 64 ++++++++++++++++++++++++++++++++++++++-- src/SDLWindow.cpp | 60 ++++--------------------------------- 6 files changed, 125 insertions(+), 63 deletions(-) diff --git a/include/OpenGLHelper.hpp b/include/OpenGLHelper.hpp index d2510e1..89d957a 100644 --- a/include/OpenGLHelper.hpp +++ b/include/OpenGLHelper.hpp @@ -21,12 +21,17 @@ #include "Platform.hpp" #include "IWindow.hpp" #include "IGraphics.hpp" +#include "IPickBuffer.hpp" // Helper functions used by the different IWindow implementations void initGL(); void drawGLScene(IWindowPtr aWindow, IGraphicsPtr aContext, IScreenPtr aScreen); void resizeGLScene(IWindowPtr aWindow); +// Wrappers for OpenGL picking features +void beginPick(IWindowPtr aWindow, unsigned* aBuffer, int x, int y); +unsigned endPick(unsigned* aBuffer); + const float NEAR_CLIP = 0.1f; const float FAR_CLIP = 70.0f; diff --git a/src/Editor.cpp b/src/Editor.cpp index b9fa8e5..83b25eb 100644 --- a/src/Editor.cpp +++ b/src/Editor.cpp @@ -520,6 +520,8 @@ void Editor::onBuildingSelect() void Editor::onMouseClick(IPickBufferPtr aPickBuffer, int x, int y, MouseButton aButton) { + log() << "Click!"; + // See if the GUI can handle it if (myToolbar->handleClick(x, y)) return; diff --git a/src/FLTKWindow.cpp b/src/FLTKWindow.cpp index 6c674fc..7f66b80 100644 --- a/src/FLTKWindow.cpp +++ b/src/FLTKWindow.cpp @@ -27,7 +27,7 @@ // An OpenGL window that supports FLTK widgets for the editor class FLTKWindow : public IWindow, public OpenGLGraphics, - public Fl_Gl_Window, + public Fl_Gl_Window, public IPickBuffer, public enable_shared_from_this { public: FLTKWindow(); @@ -44,14 +44,25 @@ public: // Fl_Gl_Window interface void draw(); int handle(int anEvent); + + // IPickBuffer inteface + IGraphicsPtr beginPick(int x, int y); + unsigned endPick(); private: + void checkValid(); IScreenPtr myScreen; + + // Picking data + static const int SELECT_BUFFER_SZ = 128; + GLuint mySelectBuffer[SELECT_BUFFER_SZ]; }; FLTKWindow::FLTKWindow() - : Fl_Gl_Window(300, 180) + : Fl_Gl_Window(640, 480) { + size_range(300, 240); + resizable(this); //myWindow = new Fl_Window(300, 180); /* myBox = new Fl_Box(20, 40, 260, 100, "Hello, World!"); @@ -61,6 +72,12 @@ FLTKWindow::FLTKWindow() myBox->labeltype(FL_SHADOW_LABEL); */ //myWindow->end(); + + // Bit of a hack to get into a state where we can use OpenGL + show(); + Fl::wait(); + + make_current(); } FLTKWindow::~FLTKWindow() @@ -68,14 +85,21 @@ FLTKWindow::~FLTKWindow() } -void FLTKWindow::draw() +void FLTKWindow::checkValid() { if (!valid()) { initGL(); resizeGLScene(shared_from_this()); + + valid(1); } +} - //drawGLScene(shared_from_this(), shared_from_this(), myScreen); +void FLTKWindow::draw() +{ + checkValid(); + + drawGLScene(shared_from_this(), shared_from_this(), myScreen); } int FLTKWindow::handle(int anEvent) @@ -86,12 +110,18 @@ int FLTKWindow::handle(int anEvent) case FL_PUSH: // Mouse down event // Position in Fl::event_x() and Fl::event_y() + myScreen->onMouseClick(shared_from_this(), Fl::event_x(), + Fl::event_y(), MOUSE_LEFT); return 1; case FL_DRAG: // Mouse moved while pressed down + myScreen->onMouseMove(shared_from_this(), Fl::event_x(), + Fl::event_y(), 1, 1); return 1; case FL_RELEASE: // Mouse up event + myScreen->onMouseRelease(shared_from_this(), Fl::event_x(), + Fl::event_y(), MOUSE_LEFT); return 1; case FL_FOCUS: case FL_UNFOCUS: @@ -144,6 +174,21 @@ int FLTKWindow::height() const return Fl_Gl_Window::h(); } +// Set up OpenGL to pick out objects +IGraphicsPtr FLTKWindow::beginPick(int x, int y) +{ + ::beginPick(shared_from_this(), mySelectBuffer, x, y); + return shared_from_this(); +} + +// Finish picking and return the name of the clicked object or zero +// It's *very* important that this is called exactly once for every +// beginPick or things will get very messed up +unsigned FLTKWindow::endPick() +{ + return ::endPick(mySelectBuffer); +} + IWindowPtr makeFLTKWindow() { return IWindowPtr(new FLTKWindow); diff --git a/src/Main.cpp b/src/Main.cpp index 1d74406..7aac368 100644 --- a/src/Main.cpp +++ b/src/Main.cpp @@ -54,10 +54,10 @@ int main(int argc, char** argv) IScreenPtr screen; if (cmd == "edit") { theWindow = makeFLTKWindow(); - /*if (exists(mapFile)) + if (exists(mapFile)) screen = makeEditorScreen(loadMap(mapFile), mapFile); else - screen = makeEditorScreen(makeEmptyMap(64, 64), mapFile);*/ + screen = makeEditorScreen(makeEmptyMap(64, 64), mapFile); } else if (cmd == "play") { theWindow = makeSDLWindow(); diff --git a/src/OpenGLHelper.cpp b/src/OpenGLHelper.cpp index df1a6b8..c3fdbfc 100644 --- a/src/OpenGLHelper.cpp +++ b/src/OpenGLHelper.cpp @@ -81,8 +81,6 @@ void drawGLScene(IWindowPtr aWindow, IGraphicsPtr aContext, IScreenPtr aScreen) throw runtime_error ("OpenGL error: " + lexical_cast(gluErrorString(error))); } - - SDL_GL_SwapBuffers(); } // Set initial OpenGL options @@ -113,6 +111,68 @@ void resizeGLScene(IWindowPtr aWindow) glViewport(0, 0, aWindow->width(), aWindow->height()); } +void beginPick(IWindowPtr aWindow, unsigned* aBuffer, int x, int y) +{ + // Set up selection buffer + glSelectBuffer(128, aBuffer); + + // Get viewport coordinates + GLint viewportCoords[4]; + glGetIntegerv(GL_VIEWPORT, viewportCoords); + + // Switch to projection matrix + glMatrixMode(GL_PROJECTION); + glPushMatrix(); + + // Render the objects, but don't change the frame buffer + glRenderMode(GL_SELECT); + glLoadIdentity(); + + // Set picking matrix + gluPickMatrix(x, viewportCoords[3] - y, 2, 2, viewportCoords); + + // Just set the perspective + gluPerspective(45.0f, (GLfloat)(aWindow->width())/(GLfloat)(aWindow->height()), + NEAR_CLIP, FAR_CLIP); + + glMatrixMode(GL_MODELVIEW); + glInitNames(); + + // Let the user render their stuff + glLoadIdentity(); +} + +unsigned endPick(unsigned* aBuffer) +{ + int objectsFound = glRenderMode(GL_RENDER); + + // Go back to normal + glMatrixMode(GL_PROJECTION); + glPopMatrix(); + glMatrixMode(GL_MODELVIEW); + + // See if we found any objects + if (objectsFound > 0) { + // Find the object with the lowest depth + unsigned int lowestDepth = aBuffer[1]; + int selectedObject = aBuffer[3]; + + // Go through all the objects found + for (int i = 1; i < objectsFound; i++) { + // See if it's closer than the current nearest + if (aBuffer[(i*4) + 1] < lowestDepth) { // 4 values for each object + lowestDepth = aBuffer[(i * 4) + 1]; + selectedObject = aBuffer[(i * 4) + 3]; + } + } + + // Return closest object + return selectedObject; + } + else + return 0; +} + // Called to set the camera position void OpenGLGraphics::setCamera(const Vector& aPos, const Vector& aRotation) diff --git a/src/SDLWindow.cpp b/src/SDLWindow.cpp index ec6d2a1..7eefc21 100644 --- a/src/SDLWindow.cpp +++ b/src/SDLWindow.cpp @@ -200,8 +200,10 @@ void SDLWindow::run(IScreenPtr aScreen) processInput(); myScreen->update(shared_from_this(), delta); - if (!willSkipNextFrame) + if (!willSkipNextFrame) { drawGLScene(shared_from_this(), shared_from_this(), myScreen); + SDL_GL_SwapBuffers(); + } else willSkipNextFrame = false; } @@ -304,33 +306,7 @@ void SDLWindow::processInput() // Set up OpenGL to pick out objects IGraphicsPtr SDLWindow::beginPick(int x, int y) { - // Set up selection buffer - glSelectBuffer(128, mySelectBuffer); - - // Get viewport coordinates - GLint viewportCoords[4]; - glGetIntegerv(GL_VIEWPORT, viewportCoords); - - // Switch to projection matrix - glMatrixMode(GL_PROJECTION); - glPushMatrix(); - - // Render the objects, but don't change the frame buffer - glRenderMode(GL_SELECT); - glLoadIdentity(); - - // Set picking matrix - gluPickMatrix(x, viewportCoords[3] - y, 2, 2, viewportCoords); - - // Just set the perspective - gluPerspective(45.0f, (GLfloat)myWidth/(GLfloat)myHeight, - NEAR_CLIP, FAR_CLIP); - - glMatrixMode(GL_MODELVIEW); - glInitNames(); - - // Let the user render their stuff - glLoadIdentity(); + ::beginPick(shared_from_this(), mySelectBuffer, x, y); return shared_from_this(); } @@ -339,33 +315,7 @@ IGraphicsPtr SDLWindow::beginPick(int x, int y) // beginPick or things will get very messed up unsigned SDLWindow::endPick() { - int objectsFound = glRenderMode(GL_RENDER); - - // Go back to normal - glMatrixMode(GL_PROJECTION); - glPopMatrix(); - glMatrixMode(GL_MODELVIEW); - - // See if we found any objects - if (objectsFound > 0) { - // Find the object with the lowest depth - unsigned int lowestDepth = mySelectBuffer[1]; - int selectedObject = mySelectBuffer[3]; - - // Go through all the objects found - for (int i = 1; i < objectsFound; i++) { - // See if it's closer than the current nearest - if (mySelectBuffer[(i*4) + 1] < lowestDepth) { // 4 values for each object - lowestDepth = mySelectBuffer[(i * 4) + 1]; - selectedObject = mySelectBuffer[(i * 4) + 3]; - } - } - - // Return closest object - return selectedObject; - } - else - return 0; + return ::endPick(mySelectBuffer); } // Capture the OpenGL pixels and save them to a file -- 2.39.2