diff --git a/CMakeLists.txt b/CMakeLists.txt index 21fe8df80..02b6074ac 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -14,9 +14,7 @@ SET( MIN_PLAYER 2.1.0 ) OPTION (BUILD_PLAYER_PLUGIN "Build Player plugin" ON) OPTION (BUILD_LSPTEST "Build Player plugin tests" OFF) OPTION (CPACK_CFG "[release building] generate CPack configuration files" ON) - -# todo - this doesn't work yet. Run Stage headless with -g. -# OPTION (BUILD_GUI "Build FLTK-based GUI. If OFF, build a gui-less Stage useful e.g. for headless compute clusters." ON ) +OPTION (BUILD_GUI "Build FLTK-based GUI. If OFF, build a gui-less Stage useful e.g. for headless compute clusters." ON ) IF (CMAKE_MAJOR_VERSION EQUAL 2 AND NOT CMAKE_MINOR_VERSION LESS 6) cmake_policy( SET CMP0003 NEW ) @@ -52,8 +50,8 @@ endif( PROJECT_OS_OSX) # Build type cflags SET (OPTIMIZE "-O2") -SET (CMAKE_CXX_FLAGS_RELEASE "${FORCE_ARCH} ${OPTIMIZE} -DNDEBUG ${WALL}" CACHE INTERNAL "CXX Flags for release" FORCE) -SET (CMAKE_CXX_FLAGS_DEBUG "-ggdb ${FORCE_ARCH} ${WALL} -DDEBUG" CACHE INTERNAL "CXX Flags for debug" FORCE) +SET (CMAKE_CXX_FLAGS_RELEASE "${FORCE_ARCH} ${OPTIMIZE} -DNDEBUG ${WALL} -std=c++11" CACHE INTERNAL "CXX Flags for release" FORCE) +SET (CMAKE_CXX_FLAGS_DEBUG "-ggdb ${FORCE_ARCH} ${WALL} -DDEBUG -std=c++11" CACHE INTERNAL "CXX Flags for debug" FORCE) SET (CMAKE_CXX_FLAGS_PROFILE "-ggdb -pg ${FORCE_ARCH} ${WALL}" CACHE INTERNAL "CXX Flags for profile" FORCE) ##################################### @@ -62,6 +60,7 @@ IF (NOT CMAKE_BUILD_TYPE) SET (CMAKE_BUILD_TYPE "release" CACHE STRING "Choose the type of build, options are: release (default) debug profile" FORCE) ENDIF (NOT CMAKE_BUILD_TYPE) + STRING(TOUPPER ${CMAKE_BUILD_TYPE} CMAKE_BUILD_TYPE) MESSAGE( STATUS "Build type ${CMAKE_BUILD_TYPE}" ) @@ -73,13 +72,13 @@ SET(RGBFILE ${CMAKE_INSTALL_PREFIX}/share/stage/rgb.txt ) # Create the config.h file # config.h belongs with the source (and not in CMAKE_CURRENT_BINARY_DIR as in Brian's original version) CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/config.h.in - ${CMAKE_CURRENT_SOURCE_DIR}/config.h @ONLY) + ${CMAKE_CURRENT_SOURCE_DIR}/config.h @ONLY) message( STATUS "Checking for libtool" ) find_path( LTDL_INCLUDE_DIR ltdl.h DOC "Libtool include dir" ) find_library( LTDL_LIB ltdl DOC "Libtool lib" ) -include_directories( +include_directories( ${OPENGL_INCLUDE_DIR} ${LTDL_INCLUDE_DIR} ) @@ -88,7 +87,6 @@ include_directories( MESSAGE( STATUS "Checking for required libraries..." ) find_package( JPEG REQUIRED ) - find_package( PNG REQUIRED ) # deal with new missing X11 on OS X 10.8 Mountain Lion @@ -97,7 +95,7 @@ find_package( PNG REQUIRED ) # SET( PNG_INCLUDE_DIR /opt/X11/include ) set (FLTK_SKIP_FLUID TRUE) -find_package( FLTK REQUIRED ) +find_package( FLTK ) find_package( OpenGL REQUIRED ) IF( NOT OPENGL_GLU_FOUND ) @@ -121,12 +119,22 @@ MESSAGE( STATUS "Checking for optional libraries..." ) SET(PC_LIBRARIES ${FLTK_LIBRARIES} ${OPENGL_LIBRARIES}) SET(PC_INCLUDE_DIRS ${FLTK_INCLUDE_DIR} ${OPENGL_INCLUDE_DIR}) +if(FLTK_FOUND) + LIST(APPEND PC_LIBRARIES ${FLTK_LIBRARIES}) + LIST(APPEND PC_INCLUDE_DIRS ${FLTK_INCLUDE_DIR}) +else(FLTK_FOUND) + if(BUILD_GUI) + message(STATUS "Could not find FLTK. Turning off BUILD_GUI") + set(BUILD_GUI OFF) + endif(BUILD_GUI) +endif(FLTK_FOUND) + SET(PC_LINK_FLAGS "") FOREACH(LIB ${PC_LIBRARIES}) GET_FILENAME_COMPONENT(LIBNAME ${LIB} NAME_WE) STRING(REGEX REPLACE "^lib" "" LINKLIB ${LIBNAME}) SET(PC_LINK_FLAGS "${PC_LINK_FLAGS} -l${LINKLIB}") -ENDFOREACH(LIB ${FLTK_LIBRARIES}) +ENDFOREACH(LIB ${PC_LIBRARIES}) SET(PC_INCLUDE_FLAGS "") FOREACH(INC ${PC_INCLUDE_DIRS}) @@ -141,14 +149,16 @@ MESSAGE( STATUS "Installation path CMAKE_INSTALL_PREFIX=${CMAKE_INSTALL_PREFIX}" # all targets need these include directories include_directories( . - libstage - replace - ${FLTK_INCLUDE_DIR} - ${PNG_INCLUDE_DIR} - ${JPEG_INCLUDE_DIR} - ${CMAKE_INCLUDE_PATH} + libstage + replace + ${PNG_INCLUDE_DIR} + ${JPEG_INCLUDE_DIR} + ${CMAKE_INCLUDE_PATH} ) +if(FLTK_FOUND) + include_directories(${FLTK_INCLUDE_DIR}) +endif(FLTK_FOUND) # work through these subdirs ADD_SUBDIRECTORY(libstage) @@ -177,13 +187,21 @@ ENDIF ( BUILD_PLAYER_PLUGIN ) # Create the CMake module files (needs to be run after the stage target was created) if (${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}.${CMAKE_PATCH_VERSION} GREATER 2.8.11) # Use a generator expression if the version of cmake allows it. - set(STAGE_TARGET_NAME "$") + set(STAGE_CORE_TARGET_NAME "$") + if(BUILD_GUI) + set(STAGE_TARGET_NAME "$") + endif(BUILD_GUI) else() # Otherwise use the LOCATION property of the target (this will produce a warning on newer versions of cmake) - get_property(location_ TARGET stage PROPERTY LOCATION) - get_filename_component(STAGE_TARGET_NAME "${location_}" NAME) + get_property(location_ TARGET stage_core PROPERTY LOCATION) + get_filename_component(STAGE_CORE_TARGET_NAME "${location_}" NAME) + if(BUILD_GUI) + get_property(location_ TARGET stage PROPERTY LOCATION) + get_filename_component(STAGE_TARGET_NAME "${location_}" NAME) + endif(BUILD_GUI) unset(location_) endif() + CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/stage-config.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/stage-config.cmake @ONLY) if (${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}.${CMAKE_PATCH_VERSION} GREATER 2.8.11) # Also run it through file(GENERATE ...) to expand generator expressions (if the version of cmake supports it). @@ -192,6 +210,7 @@ if (${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}.${CMAKE_PATCH_VERSION} GREATER INPUT ${CMAKE_CURRENT_BINARY_DIR}/stage-config.cmake) endif() CONFIGURE_FILE (${CMAKE_CURRENT_SOURCE_DIR}/stage-config-version.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/stage-config-version.cmake @ONLY) + INSTALL (FILES ${CMAKE_CURRENT_BINARY_DIR}/stage-config.cmake ${CMAKE_CURRENT_BINARY_DIR}/stage-config-version.cmake DESTINATION ${PROJECT_LIB_DIR}/cmake/${PROJECT_NAME}) # generate a cpack config file used to create packaged tarballs diff --git a/avonstage/avonstage.cc b/avonstage/avonstage.cc index 7cb78e52f..c14c19f11 100644 --- a/avonstage/avonstage.cc +++ b/avonstage/avonstage.cc @@ -445,12 +445,12 @@ int main(int argc, char *argv[]) // help options case '?': puts(USAGE); - exit(0); + return -1; break; default: printf("unhandled option %c\n", ch); puts(USAGE); - // exit(0); + return -1; } } @@ -458,7 +458,7 @@ int main(int argc, char *argv[]) if (worldfilename == NULL) { puts("[AvonStage] no worldfile specified on command line. Quit.\n"); - exit(-1); + return -1; } puts(""); // end the first start-up line diff --git a/examples/ctrl/CMakeLists.txt b/examples/ctrl/CMakeLists.txt index a9c367980..a2bbf2f02 100644 --- a/examples/ctrl/CMakeLists.txt +++ b/examples/ctrl/CMakeLists.txt @@ -26,7 +26,7 @@ set_source_files_properties( ${PLUGINS} PROPERTIES ) foreach( PLUGIN ${PLUGINS} ) - TARGET_LINK_LIBRARIES( ${PLUGIN} stage ${OPENGL_LIBRARIES} ) + TARGET_LINK_LIBRARIES( ${PLUGIN} stage_core ${OPENGL_LIBRARIES} ) endforeach( PLUGIN ) # delete the "lib" prefix from the plugin libraries diff --git a/examples/ctrl/fasr2.cc b/examples/ctrl/fasr2.cc index dcbf389a8..08eb643c6 100644 --- a/examples/ctrl/fasr2.cc +++ b/examples/ctrl/fasr2.cc @@ -1,6 +1,7 @@ #include #include "stage.hh" +#include "canvas.hh" using namespace Stg; // generic planner implementation @@ -152,7 +153,7 @@ class Robot { explicit GraphVis(Graph **graphpp) : Visualizer("graph", "vis_graph"), graphpp(graphpp) {} virtual ~GraphVis() {} - virtual void Visualize(Model *mod, Camera *) + virtual void Visualize(Model *mod, Camera *, Canvas * canvas) { if (*graphpp == NULL) return; @@ -166,9 +167,9 @@ class Robot { Color c = mod->GetColor(); c.a = 0.4; - mod->PushColor(c); + canvas->PushColor(c); (*graphpp)->Draw(); - mod->PopColor(); + canvas->PopColor(); glPopMatrix(); } diff --git a/examples/libstage/stest.cc b/examples/libstage/stest.cc index b2d1522d7..b4661368a 100644 --- a/examples/libstage/stest.cc +++ b/examples/libstage/stest.cc @@ -146,7 +146,7 @@ int main(int argc, char *argv[]) // check and handle the argumets if (argc < 3) { puts("Usage: stest "); - exit(0); + return -1; } const int popsize = atoi(argv[2]); diff --git a/libstage/CMakeLists.txt b/libstage/CMakeLists.txt index c25f0b77d..a52605696 100644 --- a/libstage/CMakeLists.txt +++ b/libstage/CMakeLists.txt @@ -3,7 +3,7 @@ MESSAGE( STATUS "Configuring libstage" ) # for config.h include_directories(${PROJECT_BINARY_DIR}) -set( stageSrcs +set(stageSrcs block.cc blockgroup.cc camera.cc @@ -31,77 +31,80 @@ set( stageSrcs stage.cc stage.hh texture_manager.cc - typetable.cc - world.cc - worldfile.cc - canvas.cc - options_dlg.cc - options_dlg.hh - vis_strip.cc - worldgui.cc + typetable.cc + world.cc + worldfile.cc + canvas.cc + vis_strip.cc ancestor.cc + image.cc ) -# model_getset.cc -# model_load.cc - -#set_source_files_properties( ${stageSrcs} PROPERTIES COMPILE_FLAGS" ) - -add_library(stage SHARED ${stageSrcs}) - -# if fltk-config didn't bring along the OpenGL dependencies (eg. on -# Debian/Ubuntu), add them explicity -IF (NOT(${FLTK_LDFLAGS} MATCHES "-lGL")) - target_link_libraries( stage ${OPENGL_LIBRARIES}) -ENDIF (NOT(${FLTK_LDFLAGS} MATCHES "-lGL")) - - -# causes the shared library to have a version number -set_target_properties( stage PROPERTIES +# Core library. Contains simulation code and most part of platform-independent rendering code +add_library(stage_core SHARED ${stageSrcs}) +set_target_properties( stage_core PROPERTIES VERSION ${VERSION} # LINK_FLAGS "${FLTK_LDFLAGS}" ) +target_link_libraries( stage_core ${OPENGL_LIBRARIES} ${LTDL_LIB} ${JPEG_LIBRARIES} ${PNG_LIBRARIES}) -target_link_libraries( stage - ${LTDL_LIB} - ${JPEG_LIBRARIES} - ${PNG_LIBRARIES} - ${FLTK_LIBRARIES} -) - -set( stagebinarySrcs main.cc ) -set_source_files_properties( ${stagebinarySrcs} PROPERTIES COMPILE_FLAGS "${FLTK_CFLAGS}" ) - -# TODO: build an app bundle on OS X -#set(MACOSX_BUNDLE_INFO_STRING "${PROJECT_NAME}") -#set(MACOSX_BUNDLE_GUI_IDENTIFIER "org.playerstage.stage") -#set(MACOSX_BUNDLE_LONG_VERSION_STRING "${PROJECT_NAME} Version ${VERSION}") -#set(MACOSX_BUNDLE_BUNDLE_NAME ${PROJECT_NAME}) -#set(MACOSX_BUNDLE_SHORT_VERSION_STRING ${VERSION}) -#set(MACOSX_BUNDLE_BUNDLE_VERSION ${VERSION}) -#set(MACOSX_BUNDLE_COPYRIGHT "Copyright 2010. All Rights Reserved.") -# add_executable( stagebinary MACOSX_BUNDLE ${stagebinarySrcs} ) - -add_executable( stagebinary ${stagebinarySrcs} ) - - -set_target_properties( stagebinary PROPERTIES OUTPUT_NAME stage ) - -# Apple seems to have trouble when libstage and stagebinary are linked against FLTK -# Newer Linux distributions won't allow stagebinary to inherit libstage's links to fltk, so we need -# to explicitly link on Linux - -target_link_libraries( stagebinary stage ) - -IF(PROJECT_OS_LINUX) - target_link_libraries( stagebinary stage pthread ) -ENDIF(PROJECT_OS_LINUX) +# Headless binary version. Does not need FLTK, but stil references a lot of OpenGL +add_executable( stagebinary_headless main_headless.cc ) +set_target_properties( stagebinary_headless PROPERTIES OUTPUT_NAME stage_headless ) +target_link_libraries( stagebinary_headless stage_core ) -INSTALL(TARGETS stagebinary stage - RUNTIME DESTINATION bin - LIBRARY DESTINATION ${PROJECT_LIB_DIR} +install(TARGETS stagebinary_headless stage_core + RUNTIME DESTINATION bin LIBRARY DESTINATION ${PROJECT_LIB_DIR} ) -INSTALL(FILES stage.hh - DESTINATION include/${PROJECT_NAME}-${APIVERSION}) +install(FILES stage.hh DESTINATION include/${PROJECT_NAME}-${APIVERSION}) + +# GUI part of the stage +if(FLTK_FOUND AND BUILD_GUI) + add_library(stage SHARED canvas_fltk.cc options_dlg.cc menu_manager_fltk.cc worldgui.cc) + + # if fltk-config didn't bring along the OpenGL dependencies (eg. on + # Debian/Ubuntu), add them explicity + IF (NOT(${FLTK_LDFLAGS} MATCHES "-lGL")) + target_link_libraries( stage ${OPENGL_LIBRARIES}) + ENDIF (NOT(${FLTK_LDFLAGS} MATCHES "-lGL")) + + # causes the shared library to have a version number + set_target_properties( stage PROPERTIES + VERSION ${VERSION} + # LINK_FLAGS "${FLTK_LDFLAGS}" + ) + + target_link_libraries( stage stage_core ${FLTK_LIBRARIES}) + + set( stagebinarySrcs main.cc ) + set_source_files_properties( ${stagebinarySrcs} PROPERTIES COMPILE_FLAGS "${FLTK_CFLAGS}" ) + + # TODO: build an app bundle on OS X + #set(MACOSX_BUNDLE_INFO_STRING "${PROJECT_NAME}") + #set(MACOSX_BUNDLE_GUI_IDENTIFIER "org.playerstage.stage") + #set(MACOSX_BUNDLE_LONG_VERSION_STRING "${PROJECT_NAME} Version ${VERSION}") + #set(MACOSX_BUNDLE_BUNDLE_NAME ${PROJECT_NAME}) + #set(MACOSX_BUNDLE_SHORT_VERSION_STRING ${VERSION}) + #set(MACOSX_BUNDLE_BUNDLE_VERSION ${VERSION}) + #set(MACOSX_BUNDLE_COPYRIGHT "Copyright 2010. All Rights Reserved.") + # add_executable( stagebinary MACOSX_BUNDLE ${stagebinarySrcs} ) + + add_executable( stagebinary ${stagebinarySrcs} ) + set_target_properties( stagebinary PROPERTIES OUTPUT_NAME stage ) + + # Apple seems to have trouble when libstage and stagebinary are linked against FLTK + # Newer Linux distributions won't allow stagebinary to inherit libstage's links to fltk, so we need + # to explicitly link on Linux + target_link_libraries( stagebinary stage_core stage ) + + if(PROJECT_OS_LINUX) + target_link_libraries( stagebinary stage pthread ) + endif(PROJECT_OS_LINUX) + install(TARGETS stagebinary stage RUNTIME DESTINATION bin LIBRARY DESTINATION ${PROJECT_LIB_DIR}) + + # All GUI-specific code was stripped from stage.hh + # GUI-supported world now is located at world_gui.hh, so it should be installed + install(FILES world_gui.hh DESTINATION include/${PROJECT_NAME}-${APIVERSION}) +endif(FLTK_FOUND AND BUILD_GUI) diff --git a/libstage/block.cc b/libstage/block.cc index 31ff5669a..4eca64d9f 100644 --- a/libstage/block.cc +++ b/libstage/block.cc @@ -1,6 +1,8 @@ #include "region.hh" #include "worldfile.hh" + + using namespace Stg; using std::vector; @@ -39,8 +41,6 @@ void Block::Translate(double x, double y) it->x += x; it->y += y; } - - group->BuildDisplayList(); } /** Return the value half way between the min and max Y position of @@ -108,9 +108,6 @@ void Block::SetZ(double min, double max) { local_z.min = min; local_z.max = max; - - // force redraw - group->BuildDisplayList(); } void Block::AppendTouchingModels(std::set &touchers) diff --git a/libstage/blockgroup.cc b/libstage/blockgroup.cc index 3cf159159..784a4cbcc 100644 --- a/libstage/blockgroup.cc +++ b/libstage/blockgroup.cc @@ -1,5 +1,5 @@ - #include "stage.hh" +#include "canvas.hh" #include "worldfile.hh" #include @@ -7,6 +7,7 @@ #include // for _POSIX_PATH_MAX #include + using namespace Stg; using namespace std; @@ -173,7 +174,7 @@ static void combineCallback(GLdouble coords[3], } // render each block as a polygon extruded into Z -void BlockGroup::BuildDisplayList() +void BlockGroup::BuildDisplayList(Canvas * canvas) { static GLUtesselator *tobj = NULL; @@ -224,7 +225,7 @@ void BlockGroup::BuildDisplayList() glEnable(GL_POLYGON_OFFSET_FILL); glPolygonOffset(0.5, 0.5); - mod.PushColor(mod.color); + canvas->PushColor(mod.color); gluTessBeginPolygon(tobj, NULL); @@ -240,7 +241,7 @@ void BlockGroup::BuildDisplayList() FOR_EACH (blk, blocks) blk->DrawSides(); - mod.PopColor(); + canvas->PopColor(); // now outline the polys glDisable(GL_POLYGON_OFFSET_FILL); @@ -251,7 +252,7 @@ void BlockGroup::BuildDisplayList() c.r /= 2.0; c.g /= 2.0; c.b /= 2.0; - mod.PushColor(c); + canvas->PushColor(c); gluTessBeginPolygon(tobj, NULL); @@ -270,15 +271,15 @@ void BlockGroup::BuildDisplayList() glDepthMask(GL_TRUE); glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - mod.PopColor(); + canvas->PopColor(); glEndList(); } -void BlockGroup::CallDisplayList() +void BlockGroup::CallDisplayList(Canvas * canvas) { if (displaylist == 0 || mod.rebuild_displaylist) { - BuildDisplayList(); + BuildDisplayList(canvas); mod.rebuild_displaylist = 0; } diff --git a/libstage/canvas.cc b/libstage/canvas.cc index e0bf52e63..4313b48cc 100644 --- a/libstage/canvas.cc +++ b/libstage/canvas.cc @@ -18,12 +18,10 @@ #include #include // For greater( ) -#include #include #include #include "file_manager.hh" -#include "options_dlg.hh" #include "region.hh" using namespace Stg; @@ -33,57 +31,36 @@ static const int checkImageHeight = 2; static GLubyte checkImage[checkImageHeight][checkImageWidth][4]; static bool blur = true; -static bool init_done = false; -static bool texture_load_done = false; - // GLuint glowTex; GLuint checkTex; -void Canvas::TimerCallback(Canvas *c) -{ - if (c->world->dirty) { - // puts( "timer redraw" ); - c->redraw(); - c->world->dirty = false; - } - - Fl::repeat_timeout(c->interval / 1000.0, (Fl_Timeout_Handler)Canvas::TimerCallback, c); -} - -Canvas::Canvas(WorldGui *world, int x, int y, int width, int height) - : Fl_Gl_Window(x, y, width, height), colorstack(), models_sorted(), current_camera(NULL), - camera(), perspective_camera(), dirty_buffer(false), wf(NULL), startx(-1), starty(-1), +Canvas::Canvas(World *world, int x, int y, int width, int height) + : colorstack(), models_sorted(), current_camera(NULL), + camera(), perspective_camera(), dirty_buffer(false), wf(NULL), selected_models(), last_selection(NULL), interval(40), // msec between redraws + init_done(false), texture_load_done(false), // initialize Option objects // showBlinken( "Blinkenlights", "show_blinkenlights", "", true, world ), - showBBoxes("Debug/Bounding boxes", "show_boundingboxes", "^b", false, world), - showBlocks("Blocks", "show_blocks", "b", true, world), - showBlur("Trails/Blur", "show_trailblur", "^d", false, world), - showClock("Clock", "show_clock", "c", true, world), - showData("Data", "show_data", "d", false, world), - showFlags("Flags", "show_flags", "l", true, world), - showFollow("Follow", "show_follow", "f", false, world), - showFootprints("Footprints", "show_footprints", "o", false, world), - showGrid("Grid", "show_grid", "g", true, world), - showOccupancy("Debug/Occupancy", "show_occupancy", "^o", false, world), - showScreenshots("Save screenshots", "screenshots", "", false, world), - showStatus("Status", "show_status", "s", true, world), - showTrailArrows("Trails/Rising Arrows", "show_trailarrows", "^a", false, world), - showTrailRise("Trails/Rising blocks", "show_trailrise", "^r", false, world), - showTrails("Trails/Fast", "show_trailfast", "^f", false, world), - showVoxels("Debug/Voxels", "show_voxels", "^v", false, world), - pCamOn("Perspective camera", "pcam_on", "r", false, world), - visualizeAll("Selected only", "vis_all", "v", false, world), + showBBoxes("Debug/Bounding boxes", "show_boundingboxes", "^b", false), + showBlocks("Blocks", "show_blocks", "b", true), + showBlur("Trails/Blur", "show_trailblur", "^d", false), + showClock("Clock", "show_clock", "c", true), + showData("Data", "show_data", "d", false), + showFlags("Flags", "show_flags", "l", true), + showFollow("Follow", "show_follow", "f", false), + showFootprints("Footprints", "show_footprints", "o", false), + showGrid("Grid", "show_grid", "g", true), + showOccupancy("Debug/Occupancy", "show_occupancy", "^o", false), + showStatus("Status", "show_status", "s", true), + showTrailArrows("Trails/Rising Arrows", "show_trailarrows", "^a", false), + showTrailRise("Trails/Rising blocks", "show_trailrise", "^r", false), + showTrails("Trails/Fast", "show_trailfast", "^f", false), + showVoxels("Debug/Voxels", "show_voxels", "^v", false), + pCamOn("Perspective camera", "pcam_on", "r", false), + visualizeAll("Selected only", "vis_all", "v", false), // and the rest - graphics(true), world(world), frames_rendered_count(0), screenshot_frame_skip(1) + graphics(true), world(world), frames_rendered_count(0) { - end(); - // show(); // must do this so that the GL context is created before - // configuring GL - // but that line causes a segfault in Linux/X11! TODO: test in OS X - - mode( FL_RGB |FL_DOUBLE|FL_DEPTH| FL_MULTISAMPLE | FL_ALPHA ); - perspective_camera.setPose(0.0, -4.0, 3.0); current_camera = &camera; setDirtyBuffer(); @@ -95,8 +72,8 @@ Canvas::Canvas(WorldGui *world, int x, int y, int width, int height) void Canvas::InitGl() { - valid(1); - FixViewport(w(), h()); + //valid(1); + FixViewport(getWidth(), getHeight()); // set gl state that won't change every redraw glClearColor(0.7, 0.7, 0.8, 1.0); @@ -116,14 +93,9 @@ void Canvas::InitGl() glEnableClientState(GL_VERTEX_ARRAY); glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - // install a font - gl_font(FL_HELVETICA, 12); - blur = false; glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); - - init_done = true; } void Canvas::InitTextures() @@ -191,8 +163,6 @@ void Canvas::InitTextures() glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, checkImageWidth, checkImageHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, checkImage); - - texture_load_done = true; } Canvas::~Canvas() @@ -203,7 +173,8 @@ Canvas::~Canvas() Model *Canvas::getModel(int x, int y) { // render all models in a unique color - make_current(); // make sure the GL context is current + // Why we are calling make_current here? This should be done on upper level + //make_current(); // make sure the GL context is current glClearColor(1, 1, 1, 1); // white glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glLoadIdentity(); @@ -285,7 +256,7 @@ void Canvas::select(Model *mod) selected_models.push_front(mod); // mod->Disable(); - redraw(); + doRedraw(); } } @@ -293,7 +264,7 @@ void Canvas::unSelect(Model *mod) { if (mod) { EraseAll(mod, selected_models); - redraw(); + doRedraw(); } } @@ -307,12 +278,12 @@ void Canvas::CanvasToWorld(int px, int py, double *wx, double *wy, double *wz) { if (px <= 0) px = 1; - else if (px >= w()) - px = w() - 1; + else if (px >= getWidth()) + px = getWidth() - 1; if (py <= 0) py = 1; - else if (py >= h()) - py = h() - 1; + else if (py >= getHeight()) + py = getHeight() - 1; // redraw the screen only if the camera model isn't active. // TODO new selection technique will simply use drawfloor to result in z = 0 @@ -338,240 +309,8 @@ void Canvas::CanvasToWorld(int px, int py, double *wx, double *wy, double *wz) glGetDoublev(GL_PROJECTION_MATRIX, projection); GLfloat pz; - glReadPixels(px, h() - py, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &pz); - gluUnProject(px, w() - py, pz, modelview, projection, viewport, wx, wy, wz); -} - -int Canvas::handle(int event) -{ - // printf( "cam %.2f %.2f\n", camera.yaw(), camera.pitch() ); - - switch (event) { - case FL_MOUSEWHEEL: - if (pCamOn == true) { - perspective_camera.scroll(Fl::event_dy() / 10.0); - } else { - camera.scale(Fl::event_dy(), Fl::event_x(), w(), Fl::event_y(), h()); - } - invalidate(); - redraw(); - return 1; - - case FL_MOVE: // moused moved while no button was pressed - if (Fl::event_state(FL_META)) { - puts("TODO: HANDLE HISTORY"); - // world->paused = ! world->paused; - return 1; - } - - if (startx >= 0) { - // mouse pointing to valid value - - if (Fl::event_state(FL_CTRL)) // rotate the camera view - { - int dx = Fl::event_x() - startx; - int dy = Fl::event_y() - starty; - - if (pCamOn == true) { - perspective_camera.addYaw(-dx); - perspective_camera.addPitch(-dy); - } else { - camera.addPitch(-0.5 * static_cast(dy)); - camera.addYaw(-0.5 * static_cast(dx)); - } - invalidate(); - redraw(); - } else if (Fl::event_state(FL_ALT)) { - int dx = Fl::event_x() - startx; - int dy = Fl::event_y() - starty; - - if (pCamOn == true) { - perspective_camera.move(-dx, dy, 0.0); - } else { - camera.move(-dx, dy); - } - invalidate(); - } - } - startx = Fl::event_x(); - starty = Fl::event_y(); - return 1; - case FL_PUSH: // button pressed - { - // else - { - Model *mod = getModel(startx, starty); - startx = Fl::event_x(); - starty = Fl::event_y(); - selectedModel = false; - switch (Fl::event_button()) { - case 1: - clicked_empty_space = (mod == NULL); - empty_space_startx = startx; - empty_space_starty = starty; - if (mod) { - // clicked a model - if (Fl::event_state(FL_SHIFT)) { - // holding shift, toggle selection - if (selected(mod)) - unSelect(mod); - else { - select(mod); - selectedModel = true; // selected a model - } - } else { - if (!selected(mod)) { - // clicked on an unselected model while - // not holding shift, this is the new - // selection - unSelectAll(); - select(mod); - } - selectedModel = true; // selected a model - } - } - - redraw(); // probably required - return 1; - case 3: { - // leave selections alone - // rotating handled within FL_DRAG - return 1; - } - default: return 0; - } - } - } - - case FL_DRAG: // mouse moved while button was pressed - { - int dx = Fl::event_x() - startx; - int dy = Fl::event_y() - starty; - - if (Fl::event_state(FL_BUTTON1) && Fl::event_state(FL_CTRL) == false) { - // Left mouse button drag - if (selectedModel) { - // started dragging on a selected model - - double sx, sy, sz; - CanvasToWorld(startx, starty, &sx, &sy, &sz); - double x, y, z; - CanvasToWorld(Fl::event_x(), Fl::event_y(), &x, &y, &z); - // move all selected models to the mouse pointer - FOR_EACH (it, selected_models) { - Model *mod = *it; - mod->AddToPose(x - sx, y - sy, 0, 0); - } - } else { - // started dragging on empty space or an - // unselected model, move the canvas - if (pCamOn == true) { - perspective_camera.move(-dx, dy, 0.0); - } else { - camera.move(-dx, dy); - } - invalidate(); // so the projection gets updated - } - } else if (Fl::event_state(FL_BUTTON3) - || (Fl::event_state(FL_BUTTON1) && Fl::event_state(FL_CTRL))) { - // rotate all selected models - - if (selected_models.size()) { - FOR_EACH (it, selected_models) { - Model *mod = *it; - mod->AddToPose(0, 0, 0, 0.05 * (dx + dy)); - } - } else { - // printf( "button 2\n" ); - - int dx = Fl::event_x() - startx; - int dy = Fl::event_y() - starty; - - if (pCamOn == true) { - perspective_camera.addYaw(-dx); - perspective_camera.addPitch(-dy); - } else { - camera.addPitch(-0.5 * static_cast(dy)); - camera.addYaw(-0.5 * static_cast(dx)); - } - } - invalidate(); - redraw(); - } - - startx = Fl::event_x(); - starty = Fl::event_y(); - - redraw(); - return 1; - } // end case FL_DRAG - - case FL_RELEASE: // mouse button released - if (empty_space_startx == Fl::event_x() && empty_space_starty == Fl::event_y() - && clicked_empty_space == true) { - // clicked on empty space, unselect all - unSelectAll(); - redraw(); - } - return 1; - - case FL_FOCUS: - case FL_UNFOCUS: - //.... Return 1 if you want keyboard events, 0 otherwise - return 1; - - case FL_KEYBOARD: - switch (Fl::event_key()) { - case FL_Left: - if (pCamOn == false) { - camera.move(-10, 0); - } else { - perspective_camera.strafe(-0.5); - } - break; - case FL_Right: - if (pCamOn == false) { - camera.move(10, 0); - } else { - perspective_camera.strafe(0.5); - } - break; - case FL_Down: - if (pCamOn == false) { - camera.move(0, -10); - } else { - perspective_camera.forward(-0.5); - } - break; - case FL_Up: - if (pCamOn == false) { - camera.move(0, 10); - } else { - perspective_camera.forward(0.5); - } - break; - default: - redraw(); // we probably set a display config - so need this - return 0; // keypress unhandled - } - - invalidate(); // update projection - return 1; - - // case FL_SHORTCUT: - // //... shortcut, key is in Fl::event_key(), ascii in - // Fl::event_text() - // //... Return 1 if you understand/use the shortcut event, 0 - // otherwise... - // return 1; - default: - // pass other events to the base class... - // printf( "EVENT %d\n", event ); - return Fl_Gl_Window::handle(event); - - } // end switch( event ) - - return 0; + glReadPixels(px, getHeight() - py, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &pz); + gluUnProject(px, getWidth() - py, pz, modelview, projection, viewport, wx, wy, wz); } void Canvas::FixViewport(int W, int H) @@ -583,7 +322,7 @@ void Canvas::FixViewport(int W, int H) void Canvas::AddModel(Model *mod) { models_sorted.push_back(mod); - redraw(); + doRedraw(); } void Canvas::RemoveModel(Model *mod) @@ -643,22 +382,22 @@ void Canvas::DrawGlobalGrid() for (double i = 0; i < bounds.x.max; i += skip) { snprintf(str, 16, "%d", (int)i); - Gl::draw_string(i, 0, 0, str); + this->draw_string(i, 0, 0, str); } for (double i = 0; i >= bounds.x.min; i -= skip) { snprintf(str, 16, "%d", (int)i); - Gl::draw_string(i, 0, 0, str); + this->draw_string(i, 0, 0, str); } for (double i = 0; i < bounds.y.max; i += skip) { snprintf(str, 16, "%d", (int)i); - Gl::draw_string(0, i, 0, str); + this->draw_string(0, i, 0, str); } for (double i = 0; i >= bounds.y.min; i -= skip) { snprintf(str, 16, "%d", (int)i); - Gl::draw_string(0, i, 0, str); + this->draw_string(0, i, 0, str); } PopColor(); @@ -685,7 +424,7 @@ void Canvas::DrawFloor() void Canvas::DrawBlocks() { FOR_EACH (it, models_sorted) - (*it)->DrawBlocksTree(); + (*it)->DrawBlocksTree(this); } void Canvas::DrawBoundingBoxes() @@ -694,8 +433,9 @@ void Canvas::DrawBoundingBoxes() glLineWidth(2.0); glPointSize(5.0); //glDisable(GL_CULL_FACE); - - world->DrawBoundingBoxTree(); + const std::vector & children = world->GetChildren(); + FOR_EACH (it, children) + (*it)->DrawBoundingBoxTree(this); //glEnable(GL_CULL_FACE); glLineWidth(1.0); @@ -731,8 +471,8 @@ void Canvas::resetCamera() float x = (min_x + max_x) / 2.0; float y = (min_y + max_y) / 2.0; camera.setPose(x, y); - float scale_x = w() / (max_x - min_x) * 0.9; - float scale_y = h() / (max_y - min_y) * 0.9; + float scale_x = getWidth() / (max_x - min_x) * 0.9; + float scale_y = getHeight() / (max_y - min_y) * 0.9; camera.setScale(scale_x < scale_y ? scale_x : scale_y); // TODO reset perspective cam @@ -794,7 +534,7 @@ void Canvas::renderFrame() GLfloat scale = 1.0 / world->Resolution(); glScalef(scale, scale, 1.0); // XX TODO - this seems slightly - world->PushColor(Color(0, 0, 1, 0.5)); + PushColor(Color(0, 0, 1, 0.5)); glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); @@ -805,7 +545,7 @@ void Canvas::renderFrame() char str[128]; snprintf(str, 128, "(%d,%d)", world->rt_cells[i].x, world->rt_cells[i].y); - Gl::draw_string(world->rt_cells[i].x + 1, world->rt_cells[i].y + 1, 0.1, str); + this->draw_string(world->rt_cells[i].x + 1, world->rt_cells[i].y + 1, 0.1, str); // printf( "x: %d y: %d\n", world->rt_regions[i].x, world->rt_regions[i].y // ); @@ -818,17 +558,17 @@ void Canvas::renderFrame() glEnd(); #if 1 - world->PushColor(Color(0, 1, 0, 0.2)); + PushColor(Color(0, 1, 0, 0.2)); glBegin(GL_LINE_STRIP); for (unsigned int i = 0; i < world->rt_cells.size(); i++) { glVertex2f(world->rt_cells[i].x + 0.5, world->rt_cells[i].y + 0.5); } glEnd(); - world->PopColor(); + PopColor(); #endif glPopMatrix(); - world->PopColor(); + PopColor(); } if (!world->rt_candidate_cells.empty()) { @@ -836,7 +576,7 @@ void Canvas::renderFrame() GLfloat scale = 1.0 / world->Resolution(); glScalef(scale, scale, 1.0); // XX TODO - this seems slightly - world->PushColor(Color(1, 0, 0, 0.5)); + PushColor(Color(1, 0, 0, 0.5)); glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); @@ -858,16 +598,16 @@ void Canvas::renderFrame() world->rt_candidate_cells[i].x + 1, world->rt_candidate_cells[i].y + 1); } - world->PushColor(Color(0, 1, 0, 0.2)); + PushColor(Color(0, 1, 0, 0.2)); glBegin(GL_LINE_STRIP); for (unsigned int i = 0; i < world->rt_candidate_cells.size(); i++) { glVertex2f(world->rt_candidate_cells[i].x + 0.5, world->rt_candidate_cells[i].y + 0.5); } glEnd(); - world->PopColor(); + PopColor(); glPopMatrix(); - world->PopColor(); + PopColor(); // world->rt_cells.clear(); } @@ -881,7 +621,7 @@ void Canvas::renderFrame() glDisable(GL_DEPTH_TEST); // using alpha blending FOR_EACH (it, models_sorted) - (*it)->DrawTrailFootprint(); + (*it)->DrawTrailFootprint(current_camera, this); glEnable(GL_DEPTH_TEST); } @@ -898,11 +638,11 @@ void Canvas::renderFrame() if (showTrailArrows) FOR_EACH (it, models_sorted) - (*it)->DrawTrailArrows(); + (*it)->DrawTrailArrows(this); if (showTrailRise) FOR_EACH (it, models_sorted) - (*it)->DrawTrailBlocks(); + (*it)->DrawTrailBlocks(current_camera, this); if (showBlocks) DrawBlocks(); @@ -914,7 +654,7 @@ void Canvas::renderFrame() // LISTMETHOD( models_sorted, Model*, DrawWaypoints ); FOR_EACH (it, selected_models) - (*it)->DrawSelected(); + (*it)->DrawSelected(this); // useful debug - puts a point at the origin of each model // for( GList* it = world->World::children; it; it=it->next ) @@ -925,19 +665,19 @@ void Canvas::renderFrame() if (showData) { if (!visualizeAll) { FOR_EACH (it, world->World::children) - (*it)->DataVisualizeTree(current_camera); + (*it)->DataVisualizeTree(current_camera, this); } else if (selected_models.size() > 0) { FOR_EACH (it, selected_models) - (*it)->DataVisualizeTree(current_camera); + (*it)->DataVisualizeTree(current_camera, this); } else if (last_selection) { - last_selection->DataVisualizeTree(current_camera); + last_selection->DataVisualizeTree(current_camera, this); } } } if (showGrid) FOR_EACH (it, models_sorted) - (*it)->DrawGrid(); + (*it)->DrawGrid(this); if (showStatus) { glPushMatrix(); @@ -946,7 +686,7 @@ void Canvas::renderFrame() glTranslatef(0, 0, 0.1); FOR_EACH (it, models_sorted) - (*it)->DrawStatusTree(&camera); + (*it)->DrawStatusTree(&camera, this); glPopMatrix(); } @@ -974,7 +714,7 @@ void Canvas::renderFrame() glMatrixMode(GL_PROJECTION); glPushMatrix(); // save old projection glLoadIdentity(); - glOrtho(0, w(), 0, h(), -100, 100); + glOrtho(0, getWidth(), 0, getHeight(), -100, 100); glMatrixMode(GL_MODELVIEW); glPushMatrix(); @@ -985,10 +725,10 @@ void Canvas::renderFrame() if (showFollow == true && last_selection) clockstr.append(" [FOLLOW MODE]"); - float txtWidth = gl_width(clockstr.c_str()); + float txtWidth = this->fontWidth(clockstr.c_str()); if (txtWidth < 200) txtWidth = 200; - int txtHeight = gl_height(); + int txtHeight = this->fontHeight(); const int margin = 5; int width, height; @@ -1003,7 +743,7 @@ void Canvas::renderFrame() //char buf[ clockstr.size() ]; //strcpy( buf, clockstr.c_str() ); - Gl::draw_string(margin, margin, 0, clockstr.c_str() ); + this->draw_string(margin, margin, 0, clockstr.c_str() ); colorstack.Pop(); colorstack.Pop(); @@ -1027,9 +767,6 @@ void Canvas::renderFrame() glMatrixMode(GL_MODELVIEW); } - if (showScreenshots && (frames_rendered_count % screenshot_frame_skip == 0)) - Screenshot(); - frames_rendered_count++; } @@ -1039,7 +776,7 @@ void Canvas::EnterScreenCS() glMatrixMode(GL_PROJECTION); glPushMatrix(); // save old projection glLoadIdentity(); - glOrtho(0, w(), 0, h(), -100, 100); + glOrtho(0, getWidth(), 0, getHeight(), -100, 100); glMatrixMode(GL_MODELVIEW); glPushMatrix(); @@ -1056,98 +793,16 @@ void Canvas::LeaveScreenCS() glMatrixMode(GL_MODELVIEW); } -void Canvas::Screenshot() -{ - int width = w(); - int height = h(); - int depth = 4; // RGBA - - // we use RGBA throughout, though we only need RGB, as the 4-byte - // pixels avoid a nasty word-alignment problem when indexing into - // the pixel array. - - // might save a bit of time with a static var as the image size rarely changes - static std::vector pixels; - pixels.resize(width * height * depth); - - glFlush(); // make sure the drawing is done - // read the pixels from the screen - glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, &pixels[0]); - - static uint32_t count = 0; - char filename[64]; - snprintf(filename, 63, "stage-%06d.png", count++); - - FILE *fp = fopen(filename, "wb"); - if (fp == NULL) { - PRINT_ERR1("Unable to open %s", filename); - } - - // create PNG data - png_structp pp = png_create_write_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0); - assert(pp); - png_infop info = png_create_info_struct(pp); - assert(info); - - // setup the output file - png_init_io(pp, fp); - - // need to invert the image as GL and PNG disagree on the row order - png_bytep *rowpointers = new png_bytep[height]; - for (int i = 0; i < height; i++) - rowpointers[i] = &pixels[(height - 1 - i) * width * depth]; - - png_set_rows(pp, info, rowpointers); - - png_set_IHDR(pp, info, width, height, 8, PNG_COLOR_TYPE_RGBA, PNG_INTERLACE_NONE, - PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); - - png_write_png(pp, info, PNG_TRANSFORM_IDENTITY, NULL); - - // free the PNG data - we reuse the pixel array next call. - png_destroy_write_struct(&pp, &info); - - fclose(fp); - - printf("Saved %s\n", filename); - delete[] rowpointers; -} - -void Canvas::perspectiveCb(Fl_Widget *w, void *p) -{ - Canvas *canvas = static_cast(w); - Option *opt = static_cast