AsciiRenderer.cpp
Go to the documentation of this file.
2 #include <iostream>
3 #include <locale>
4 #include <chrono>
5 
6 namespace lvr2 {
7 
8 void AsciiRendererErrorFunc(void* userPtr, enum RTCError error, const char* str)
9 {
10  printf("error %d: %s\n", error, str);
11 }
12 
15  const unsigned int& num_grays)
16 :m_ascii_width(0)
17 ,m_ascii_height(0)
18 ,m_num_grays(num_grays)
19 ,m_chars(nullptr)
20 ,m_colors(nullptr)
21 {
22  std::locale::global(std::locale("en_US.utf8"));
23  std::wcout.imbue(std::locale());
24  init_curses(num_grays);
25 
26  m_camera.setIdentity();
27 
28  initBuffers();
29  initEmbree(mesh);
30  clear();
31 
32 }
33 
35 {
37  destroyEmbree();
39 }
40 
42 {
43  unsigned int W = curses_width();
44  unsigned int H = curses_height();
45 
46  if(W != m_ascii_width || H != m_ascii_height)
47  {
49 
50  m_ascii_width = W;
51  m_ascii_height = H;
52 
53  m_chars = static_cast<BrailleChar**>( malloc( m_ascii_width * sizeof(BrailleChar*) ) );
54 
55  for(int i=0; i<m_ascii_width; i++)
56  {
57  m_chars[i] = static_cast<BrailleChar*>(malloc( m_ascii_height * sizeof(BrailleChar) ) );
58  }
59 
60  m_colors = static_cast<float**>( malloc( m_ascii_width * sizeof(float*) ) );
61 
62  for(int i=0; i<m_ascii_width; i++)
63  {
64  m_colors[i] = static_cast<float*>(malloc( m_ascii_height * sizeof(float) ) );
65  }
66  }
67 }
68 
70 {
71  if(m_chars)
72  {
73  for(int i=0; i<m_ascii_width; i++)
74  {
75  free(m_chars[i]);
76  }
77  free(m_chars);
78  }
79 
80  if(m_colors)
81  {
82  for(int i=0; i<m_ascii_width; i++)
83  {
84  free(m_colors[i]);
85  }
86  free(m_colors);
87  }
88 }
89 
91 {
94  rtcInitIntersectContext(&m_context);
95 }
96 
98 {
99  RTCDevice device = rtcNewDevice(NULL);
100 
101  if (!device)
102  {
103  std::cerr << "error " << rtcGetDeviceError(NULL) << ": cannot create device" << std::endl;
104  }
105 
106  rtcSetDeviceErrorFunction(device, AsciiRendererErrorFunc, NULL);
107  return device;
108 }
109 
111  RTCDevice device,
112  const MeshBufferPtr mesh)
113 {
114  RTCScene scene = rtcNewScene(device);
115  RTCGeometry geom = rtcNewGeometry(device, RTC_GEOMETRY_TYPE_TRIANGLE);
116 
117  auto lvr_vertices = mesh->getVertices();
118  int num_vertices = mesh->numVertices();
119 
120  auto lvr_indices = mesh->getFaceIndices();
121  int num_faces = mesh->numFaces();
122 
123  float* embree_vertices = (float*) rtcSetNewGeometryBuffer(geom,
124  RTC_BUFFER_TYPE_VERTEX,
125  0,
126  RTC_FORMAT_FLOAT3,
127  3*sizeof(float),
128  num_vertices);
129 
130  unsigned* embree_indices = (unsigned*) rtcSetNewGeometryBuffer(geom,
131  RTC_BUFFER_TYPE_INDEX,
132  0,
133  RTC_FORMAT_UINT3,
134  3*sizeof(unsigned),
135  num_faces);
136 
137  if (embree_vertices && embree_indices)
138  {
139  // copy mesh to embree buffers
140  const float* lvr_vertices_begin = lvr_vertices.get();
141  const float* lvr_vertices_end = lvr_vertices_begin + num_vertices * 3;
142  std::copy(lvr_vertices_begin, lvr_vertices_end, embree_vertices);
143 
144  const unsigned int* lvr_indices_begin = lvr_indices.get();
145  const unsigned int* lvr_indices_end = lvr_indices_begin + num_faces * 3;
146  std::copy(lvr_indices_begin, lvr_indices_end, embree_indices);
147  }
148 
149  rtcCommitGeometry(geom);
150  rtcAttachGeometry(scene, geom);
151  rtcReleaseGeometry(geom);
152  rtcCommitScene(scene);
153 
154  return scene;
155 }
156 
158 {
159  rtcReleaseScene(m_scene);
160  rtcReleaseDevice(m_device);
161 }
162 
163 void AsciiRenderer::set(const unsigned int& x, const unsigned int& y)
164 {
165  unsigned int x_outer = x / 2;
166  unsigned int x_inner = x % 2;
167 
168  unsigned int y_outer = y / 4;
169  unsigned int y_inner = y % 4;
170 
171  m_chars[x_outer][y_outer].set(x_inner, y_inner);
172 }
173 
174 void AsciiRenderer::clear(const unsigned int& x, const unsigned int& y)
175 {
176  unsigned int x_outer = x / 2;
177  unsigned int x_inner = x % 2;
178 
179  unsigned int y_outer = y / 4;
180  unsigned int y_inner = y % 4;
181 
182  m_chars[x_outer][y_outer].clear(x_inner, y_inner);
183 }
184 
186 {
187  for(int i=0; i<m_ascii_width; i++)
188  {
189  for(int j=0; j<m_ascii_height; j++)
190  {
191  m_chars[i][j].data = 0;
192  m_colors[i][j] = 0.0;
193  }
194  }
195 }
196 
198 {
199  unsigned int image_width = m_ascii_width * 2;
200  unsigned int image_height = m_ascii_height * 4;
201 
202  double c_u = image_width / 2;
203  double c_v = image_height / 2;
204 
205  float focal_length = 700.0;
206 
207  double fx = focal_length;
208  double fy = focal_length;
209 
210 
211  Vector3d origin;
212  origin = m_camera.translation();
213 
214  #pragma omp parallel for
215  for(int u = 0; u < image_width; u++)
216  {
217  for(int v = 0; v < image_height; v++)
218  {
219  RTCRayHit rayhit;
220  rayhit.ray.org_x = origin.coeff(0);
221  rayhit.ray.org_y = origin.coeff(1);
222  rayhit.ray.org_z = origin.coeff(2);
223  rayhit.ray.tnear = 0;
224  rayhit.ray.tfar = INFINITY;
225  rayhit.ray.mask = 0;
226  rayhit.ray.flags = 0;
227  rayhit.hit.geomID = RTC_INVALID_GEOMETRY_ID;
228  rayhit.hit.instID[0] = RTC_INVALID_GEOMETRY_ID;
229 
230  Vector3d dir(1.0, -(static_cast<double>(u) - c_u ) / fx, -(static_cast<double>(v) - c_v) / fy);
231 
232  dir.normalize();
233 
234  dir = m_camera.linear() * dir;
235 
236  rayhit.ray.dir_x = dir.coeff(0);
237  rayhit.ray.dir_y = dir.coeff(1);
238  rayhit.ray.dir_z = dir.coeff(2);
239 
240 
241  rtcIntersect1(m_scene, &m_context, &rayhit);
242 
243  if(rayhit.hit.geomID != RTC_INVALID_GEOMETRY_ID)
244  {
245  float norm_normal = sqrt( pow(rayhit.hit.Ng_x, 2.0)
246  + pow(rayhit.hit.Ng_y,2.0)
247  + pow(rayhit.hit.Ng_z,2.0));
248 
249  rayhit.hit.Ng_x /= norm_normal;
250  rayhit.hit.Ng_y /= norm_normal;
251  rayhit.hit.Ng_z /= norm_normal;
252 
253  float scalar = rayhit.ray.dir_x * rayhit.hit.Ng_x
254  + rayhit.ray.dir_y * rayhit.hit.Ng_y
255  + rayhit.ray.dir_z * rayhit.hit.Ng_z;
256 
257  unsigned int ascii_x = u / 2;
258  unsigned int ascii_y = v / 4;
259  m_colors[ascii_x][ascii_y] += std::max(0.1f, fabs(scalar)) / 8.0;
260  set(u, v);
261  } else {
262  clear(u, v);
263  }
264  }
265  }
266 }
267 
269 {
270 
271  if(key == 'a') {
272  // trans left
273  m_camera.translate(Eigen::Vector3d(0.0, m_vrot * m_sidereduce, 0.0));
274  } else if( key == 'A') {
275  m_camera.translate(Eigen::Vector3d(0.0, m_vtrans * m_boost * m_sidereduce, 0.0));
276  } else if( key == 'w') {
277  // trans front
278  m_camera.translate(Eigen::Vector3d(m_vtrans, 0.0, 0.0));
279  } else if( key == 'W') {
280  // trans front
281  m_camera.translate(Eigen::Vector3d(m_vtrans * m_boost, 0.0, 0.0));
282  } else if( key == 's') {
283  // trans back
284  m_camera.translate(Eigen::Vector3d(-m_vtrans, 0.0, 0.0));
285  } else if( key == 'S') {
286  // trans back
287  m_camera.translate(Eigen::Vector3d(-m_vtrans * m_boost, 0.0, 0.0));
288  } else if( key == 'd') {
289  // trans right
290  m_camera.translate(Eigen::Vector3d(0.0, -m_vtrans * m_sidereduce, 0.0));
291  } else if( key == 'D') {
292  m_camera.translate(Eigen::Vector3d(0.0, -m_vtrans * m_boost * m_sidereduce, 0.0));
293  } else if( key == 'q' ) {
294  float roll = -m_vrot;
295  m_camera.rotate(Eigen::AngleAxisd(roll, Eigen::Vector3d::UnitX()));
296  } else if( key == 'Q' ) {
297  float roll = -m_vrot;
298  m_camera.rotate(Eigen::AngleAxisd(roll * m_boost, Eigen::Vector3d::UnitX()));
299  } else if( key == 'e' ) {
300  float roll = m_vrot;
301  m_camera.rotate(Eigen::AngleAxisd(roll, Eigen::Vector3d::UnitX()));
302  } else if( key == 'E' ) {
303  float roll = m_vrot;
304  m_camera.rotate(Eigen::AngleAxisd(roll * m_boost, Eigen::Vector3d::UnitX()));
305  } else if( key == KEY_LEFT ) {
306  // yaw +
307  float yaw = m_vrot;
308  m_camera.rotate(Eigen::AngleAxisd(yaw, Eigen::Vector3d::UnitZ()));
309  } else if( key == KEY_RIGHT ) {
310  // yaw -
311  float yaw = -m_vrot;
312  m_camera.rotate(Eigen::AngleAxisd(yaw, Eigen::Vector3d::UnitZ()));
313  } else if( key == KEY_UP ) {
314  float pitch = -m_vrot;
315  m_camera.rotate(Eigen::AngleAxisd(pitch, Eigen::Vector3d::UnitY()));
316  } else if( key == KEY_DOWN ) {
317  float pitch = m_vrot;
318  m_camera.rotate(Eigen::AngleAxisd(pitch, Eigen::Vector3d::UnitY()));
319  } else if( key == ' ') {
321  } else if( key == KEY_MOUSE ) {
322  // rotate
323  MEVENT event;
324 
325  if(getmouse(&event) == OK)
326  {
327 
328  if(event.bstate & BUTTON1_PRESSED) // LEFT KLICK
329  {
330  // record start point
331  // from now on we need to track the rotation
332  m_track_mouse = true;
333  } else if(event.bstate & MOUSE_SCROLL_UP) {
334  // SCROLL
335  m_camera.translate(Eigen::Vector3d(m_vtrans, 0.0, 0.0));
336  } else if( (event.bstate & MOUSE_MOVE) && m_track_mouse) {
337  double mouse_x = static_cast<double>(event.x);
338  double mouse_y = static_cast<double>(event.y);
339 
340  double delta_x = m_mouse_x - mouse_x;
341  double delta_y = m_mouse_y - mouse_y;
342 
343  // sometimes SIGINTS here i guess. maybe use quaternions instead?
344  m_camera.rotate(
345  Eigen::AngleAxisd(-delta_y * m_vrot, Eigen::Vector3d::UnitY())
346  * Eigen::AngleAxisd(delta_x * m_vrot, Eigen::Vector3d::UnitZ())
347  );
348 
349  } else {
350  m_track_mouse = false;
351  }
352 
353  m_mouse_x = static_cast<double>(event.x);
354  m_mouse_y = static_cast<double>(event.y);
355  }
356  } else if(key == KEY_RESIZE) {
357  initBuffers();
358  } else if(key == 'i') {
359  m_vtrans *= 5.0;
360  } else if(key == 'k') {
361  m_vtrans /= 5.0;
362  } else if(key == 'h') {
364  }
365 
366  move(0, 0);
367 }
368 
370 {
371  auto start = std::chrono::steady_clock::now();
372  initBuffers();
373  clear();
374  raycast();
375 
376  unsigned int W = m_ascii_width;
377  unsigned int H = m_ascii_height;
378 
379  for(unsigned int y=0; y< H; y++)
380  {
381  for(unsigned int x=0; x< W; x++)
382  {
383  console_print_grayscale(y,x, m_chars[x][y].getChar(), m_colors[x][y]);
384  }
385  }
386 
387  auto end = std::chrono::steady_clock::now();
388  double ms = std::chrono::duration_cast<std::chrono::microseconds>(end - start).count() / 1000.0;
389 
390  // max fps 1000
391  double fps = 1000.0 / 0.001;
392  if(ms > 0.001)
393  {
394  fps = 1000.0 / ms;
395  }
396 
397  // update avg fps
398  m_avg_fps = m_fps_alpha * m_avg_fps + (1.0 - m_fps_alpha) * fps;
399 
400  mvprintw(0, 0, "%4d fps", int(m_avg_fps) );
401 
402  printControls();
403 
404  refresh();
405 }
406 
407 void AsciiRenderer::consolePrintMessage(std::string message)
408 {
409  m_messages.push_back(message);
410 }
411 
413 {
414  unsigned int H = curses_height();
415  move(H-1, 0);
416 
417  for(auto message : m_messages)
418  {
419  addstr(message.c_str());
420  addch(' ');
421  }
422 
423  m_messages.clear();
424 }
425 
427 {
428  unsigned int H = curses_height();
429 
430  if(m_show_controls)
431  {
432  mvprintw(H-8, 0, "CONTROLLS (H)");
433  mvprintw(H-7, 0, "Translate: W A S D Scroll");
434  mvprintw(H-6, 0, "Rotate: ← ↑ → ↓ q e");
435  mvprintw(H-5, 0, "Mouse control:");
436  mvprintw(H-4, 0, " - ON: Space, Left Click");
437  mvprintw(H-3, 0, " - OFF: Space, Other Click");
438  mvprintw(H-2, 0, "Speed inc/dec: i k");
439  mvprintw(H-1, 0, "Exit: Esc");
440  } else {
441  mvprintw(H-1, 0, "CONTROLLS (H)");
442  }
443 }
444 
445 unsigned int AsciiRenderer::width()
446 {
447  return m_ascii_width * 2;
448 }
449 
450 unsigned int AsciiRenderer::height()
451 {
452  return m_ascii_height * 4;
453 }
454 
455 } // namespace lvr2
void set(const unsigned int &i, const unsigned int &j)
static void console_print_grayscale(int y, int x, wchar_t sign, short gray)
unsigned char data
Definition: BitField.hpp:11
HalfEdgeMesh< Vec > mesh
std::shared_ptr< MeshBuffer > MeshBufferPtr
Definition: MeshBuffer.hpp:217
RTCDevice initializeDevice()
AsciiRenderer(MeshBufferPtr mesh, const unsigned int &num_grays=200)
static mmask_t MOUSE_SCROLL_UP
unsigned int height()
static mmask_t MOUSE_MOVE
Definition: CursesHelper.hpp:9
unsigned int m_ascii_width
void AsciiRendererErrorFunc(void *userPtr, enum RTCError error, const char *str)
void consolePrintMessage(std::string message)
Eigen::Vector3d Vector3d
Eigen 3D vector, double precision.
static void init_curses(unsigned int num_grayscale)
RTCIntersectContext m_context
static void destroy_curses()
unsigned int m_ascii_height
static int curses_width()
void initEmbree(MeshBufferPtr mesh)
void processKey(int key)
Eigen::Affine3d m_camera
static int curses_height()
KF_EXPORTS void error(const char *error_string, const char *file, const int line, const char *func="")
Error handler. All GPU functions from this subsystem call the function to report an error...
RTCScene initializeScene(RTCDevice device, const MeshBufferPtr mesh)
void set(const unsigned int &i, const unsigned int &j)
Definition: BitField.hpp:15
#define NULL
Definition: mydefs.hpp:141
unsigned int width()
std::vector< std::string > m_messages
BrailleChar ** m_chars
void clear(const unsigned int &i, const unsigned int &j)
Definition: BitField.hpp:30


lvr2
Author(s): Thomas Wiemann , Sebastian Pütz , Alexander Mock , Lars Kiesow , Lukas Kalbertodt , Tristan Igelbrink , Johan M. von Behren , Dominik Feldschnieders , Alexander Löhr
autogenerated on Mon Feb 28 2022 22:46:06