diff --git a/README.md b/README.md index 93e2f5b..ce2a91b 100644 --- a/README.md +++ b/README.md @@ -17,8 +17,8 @@ While `rgl` is a powerful package, it has some limitations when it comes to hand ### Drawbacks: -* Blocks the R session: while the viewer window is open, you cannot use R for other tasks. You must close the viewer window to resume normal R usage. * Limited functionality: only displays point clouds and does not offer additional features. It is not intended to replace `rgl` for other visualization needs and custom rendering. +* Limited to only one windows and thus one rendering. ## Installation diff --git a/src/lidRviewer.cpp b/src/lidRviewer.cpp index 95d9056..39f1b69 100644 --- a/src/lidRviewer.cpp +++ b/src/lidRviewer.cpp @@ -1,11 +1,194 @@ +#include + +#include + +#include +#include + +#include +#include + #include "drawer.h" const float zNear = 1; const float zFar = 100000; const Uint32 time_per_frame = 1000 / 30; +bool running = false; + +std::thread sdl_thread; + +void sdl_loop(DataFrame df) +{ + SDL_Event event; + + unsigned int width = 600; + unsigned int height = 600; + bool run = true; + + Uint32 last_time, current_time, elapsed_time; + + if (SDL_Init(SDL_INIT_VIDEO) != 0) + { + Rcpp::stop("Unable to initialize SDL: %s", SDL_GetError()); + } + + SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); + SDL_Window *window = SDL_CreateWindow("lidRviewer", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, width, height, SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE); + + if (window == nullptr) + { + SDL_Quit(); + Rcpp::stop("Unable to create SDL window: %s", SDL_GetError()); + } + + SDL_GLContext glContext = SDL_GL_CreateContext(window); + SDL_GL_SetSwapInterval(1); // Enable VSync + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + gluPerspective(70, (double)width / height, zNear, zFar); + + glEnable(GL_DEPTH_TEST); + glDepthFunc(GL_LEQUAL); + glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); + + glEnable(GL_POINT_SMOOTH); + glEnable(GL_LINE_SMOOTH); + glHint(GL_LINE_SMOOTH_HINT, GL_NICEST); + + Drawer *drawer = new Drawer(window, df); + drawer->camera.setRotateSensivity(0.1); + drawer->camera.setZoomSensivity(10); + drawer->camera.setPanSensivity(1); + drawer->setPointSize(4); + + last_time = SDL_GetTicks(); + + while (run) + { + while (SDL_PollEvent(&event)) + { + switch (event.type) + { + case SDL_QUIT: + run = false; + break; + + case SDL_KEYDOWN: + switch (event.key.keysym.sym) + { + case SDLK_ESCAPE: + run = false; + break; + case SDLK_z: + drawer->setAttribute(Attribute::Z); + break; + case SDLK_i: + drawer->setAttribute(Attribute::I); + break; + case SDLK_c: + drawer->setAttribute(Attribute::CLASS); + break; + case SDLK_r: + case SDLK_g: + case SDLK_b: + drawer->setAttribute(Attribute::RGB); + break; + case SDLK_q: + drawer->display_hide_spatial_index(); + break; + case SDLK_l: + drawer->display_hide_edl(); + break; + case SDLK_PLUS: + case SDLK_KP_PLUS: + drawer->point_size_plus(); + break; + case SDLK_MINUS: + case SDLK_KP_MINUS: + drawer->point_size_minus(); + break; + default: + drawer->camera.OnKeyboard(event.key); + break; + } + break; + + case SDL_MOUSEMOTION: + drawer->camera.OnMouseMotion(event.motion); + break; + + case SDL_MOUSEBUTTONUP: + case SDL_MOUSEBUTTONDOWN: + drawer->camera.OnMouseEvent(event.button, SDL_MouseWheelEvent{}); // Pass an empty SDL_MouseWheelEvent + break; + + case SDL_MOUSEWHEEL: + drawer->camera.OnMouseEvent(SDL_MouseButtonEvent{}, event.wheel); // Pass an empty SDL_MouseButtonEvent + break; + + case SDL_WINDOWEVENT: + if (event.window.event == SDL_WINDOWEVENT_RESIZED) + { + width = event.window.data1; + height = event.window.data2; + glViewport(0, 0, width, height); + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + gluPerspective(70, (double)width / height, zNear, zFar); + drawer->camera.changed = true; + } + break; + } + } + + current_time = SDL_GetTicks(); + elapsed_time = current_time - last_time; + + if (elapsed_time > time_per_frame) + { + drawer->draw(); + last_time = current_time; + } + else + { + SDL_Delay(time_per_frame - elapsed_time); + } + } + + current_time = SDL_GetTicks(); + elapsed_time = current_time - last_time; + + if (elapsed_time > time_per_frame) + { + drawer->draw(); + last_time = current_time; + } + else + { + SDL_Delay(time_per_frame - elapsed_time); + } + + delete drawer; + SDL_GL_DeleteContext(glContext); + SDL_DestroyWindow(window); + SDL_Quit(); + running = false; +} // [[Rcpp::export]] void viewer(DataFrame df) +{ + if (running) Rcpp::stop("lidRviewer is limited to one rendering point cloud"); + + sdl_thread = std::thread(sdl_loop, df); + sdl_thread.detach(); // Detach the thread to allow it to run independently + + running = true; +} + + +/*void viewer(DataFrame df) { bool run = true; @@ -148,4 +331,4 @@ void viewer(DataFrame df) SDL_DestroyWindow(window); // Correctly destroy window SDL_Quit(); return; -} +}*/