diff --git a/pptk/viewer/main.cpp b/pptk/viewer/main.cpp index 2fcc624..767c74f 100644 --- a/pptk/viewer/main.cpp +++ b/pptk/viewer/main.cpp @@ -4,14 +4,20 @@ #include "viewer.h" int main(int argc, char* argv[]) { - if (argc != 2) { - qDebug() << "usage: viewer "; + if ((argc != 2)&&(argc != 4)) { + qDebug() << "usage: viewer "; return 1; } QApplication a(argc, argv); unsigned short clientPort = (unsigned short)atoi(argv[1]); Viewer viewer(clientPort); - viewer.resize(512, 512); + if (argc>3) + { + viewer.resize((unsigned short)atoi(argv[2]), (unsigned short)atoi(argv[3])); + }else + { + viewer.resize(512, 512); + } viewer.create(); viewer.show(); diff --git a/pptk/viewer/viewer.h b/pptk/viewer/viewer.h index ee6c645..e28e52f 100644 --- a/pptk/viewer/viewer.h +++ b/pptk/viewer/viewer.h @@ -66,8 +66,10 @@ class Viewer : public QWindow, protected OpenGLFuncs { // initalize various states _socket_waiting_on_enter_key = NULL; + _socket_waiting_on_screenshot = NULL; _timer_fine_render_delay = NULL; _fine_render_state = INACTIVE; + _render_state = FAST; _render_time = std::numeric_limits::infinity(); _show_text = true; @@ -403,6 +405,10 @@ class Viewer : public QWindow, protected OpenGLFuncs { if (payloadLength != sizeof(float)) break; float r = *(float*)&payload[0]; _camera.setCameraDistance(qMax(0.1f, r)); + } else if (!strcmp(propertyName.c_str(), "vFOV")) { + if (payloadLength != sizeof(float)) break; + float fov = *(float*)&payload[0]; + _camera.setVerticalFOV(fov); } else if (!strcmp(propertyName.c_str(), "selected")) { quint64 num_selected = payloadLength / sizeof(unsigned int); if (payloadLength != num_selected * sizeof(unsigned int)) break; @@ -426,7 +432,12 @@ class Viewer : public QWindow, protected OpenGLFuncs { } else if (!strcmp(propertyName.c_str(), "curr_attribute_id")) { if (payloadLength != sizeof(unsigned int)) break; _points->setCurrentAttributeIndex(*(unsigned int*)&payload[0]); - } else { + } else if (!strcmp(propertyName.c_str(), "window_size")) { + if (payloadLength != sizeof(unsigned int) * 2) break; + unsigned int* v = (unsigned int*)&payload[0]; + resize( v[0], v[1]); + } + else { // unrecognized property name, do nothing // todo: consider doing something } @@ -508,7 +519,10 @@ class Viewer : public QWindow, protected OpenGLFuncs { // receive property name string std::string filename(stringLength, 'x'); comm::receiveBytes((char*)&filename[0], stringLength, clientConnection); - printScreen(filename); + _socket_waiting_on_screenshot = clientConnection; + screenshot(filename); + return; + //captureCameraAnimation(filename); break; } case 7: { // wait for enter @@ -573,7 +587,6 @@ class Viewer : public QWindow, protected OpenGLFuncs { _dolly->setRepeat(repeat); _dolly->start(); playCameraAnimation(); - break; } case 10: { // set per point attributes @@ -679,6 +692,7 @@ class Viewer : public QWindow, protected OpenGLFuncs { _context->doneCurrent(); #endif _fine_render_state = INACTIVE; + _render_state = FINE; break; } case TERMINATE: { @@ -706,6 +720,44 @@ class Viewer : public QWindow, protected OpenGLFuncs { QTimer::singleShot(15, this, SLOT(playCameraAnimation())); } + void capture() { + if (_render_state == FINE){ + _context->makeCurrent(this); + int w = width() * this->devicePixelRatio(); + int h = height() * this->devicePixelRatio(); + GLubyte* pixels = new GLubyte[4 * w * h]; + glBindBuffer(GL_PIXEL_PACK_BUFFER, 0); + glBindFramebuffer(GL_FRAMEBUFFER, 0); + //glReadBuffer(GL_FRONT); // otherwise will read back buffer + glReadBuffer(GL_BACK); // otherwise will read back buffer + glReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, pixels); + QImage image(w, h, QImage::Format_ARGB32); + for (int i = 0; i < h; i++) { + for (int j = 0; j < w; j++) { + int index = j * 4 + (h - i - 1) * w * 4; + QColor color(pixels[index + 0], + pixels[index + 1], + pixels[index + 2], + pixels[index + 3]); + image.setPixel(j, i, color.rgba()); + } + } + // expect absolute filename path + QString qstr_filename = QString::fromStdString(captureFilename); + image.save(qstr_filename); + delete[] pixels; + _context->doneCurrent(); + + const char* msg = "c"; + comm::sendBytes(msg, 1, _socket_waiting_on_screenshot); + _socket_waiting_on_screenshot->disconnectFromHost(); + _socket_waiting_on_screenshot = NULL; + }else + { + QTimer::singleShot(0, this, SLOT(capture())); + } + } + private: void dummyCalculation(int n) { _dummy_accumulator /= (float)n; @@ -713,32 +765,6 @@ class Viewer : public QWindow, protected OpenGLFuncs { _dummy_accumulator += sqrtf(pow(6.9f, log((float)i))); } - void printScreen(std::string filename) { - _context->makeCurrent(this); - int w = width() * this->devicePixelRatio(); - int h = height() * this->devicePixelRatio(); - GLubyte* pixels = new GLubyte[4 * w * h]; - glBindBuffer(GL_PIXEL_PACK_BUFFER, 0); - glBindFramebuffer(GL_FRAMEBUFFER, 0); - glReadBuffer(GL_FRONT); // otherwise will read back buffer - glReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, pixels); - QImage image(w, h, QImage::Format_ARGB32); - for (int i = 0; i < h; i++) { - for (int j = 0; j < w; j++) { - int index = j * 4 + (h - i - 1) * w * 4; - QColor color(pixels[index + 0], - pixels[index + 1], - pixels[index + 2], - pixels[index + 3]); - image.setPixel(j, i, color.rgba()); - } - } - // expect absolute filename path - QString qstr_filename = QString::fromStdString(filename); - image.save(qstr_filename); - delete[] pixels; - _context->doneCurrent(); - } void displayInfo() { if (!_show_text) return; @@ -873,6 +899,12 @@ class Viewer : public QWindow, protected OpenGLFuncs { displayInfo(); if (this->isExposed()) _context->swapBuffers(this); _context->doneCurrent(); + _render_state = FAST; + } + + void screenshot(std::string filename) { + captureFilename = filename; + QTimer::singleShot(0, this, SLOT(capture())); } QPointF win2ndc(QPointF p) { @@ -898,14 +930,18 @@ class Viewer : public QWindow, protected OpenGLFuncs { float _dummy_accumulator; enum FineRenderState { INACTIVE, INITIALIZE, CHUNK, FINALIZE, TERMINATE }; FineRenderState _fine_render_state; + enum RenderState { FAST, FINE }; + RenderState _render_state; QTimer* _timer_fine_render_delay; std::size_t _chunk_offset; std::size_t _max_chunk_size; std::vector _refined_indices; QTcpSocket* _socket_waiting_on_enter_key; + QTcpSocket* _socket_waiting_on_screenshot; double _render_time; bool _show_text; + std::string captureFilename; }; #endif // __VIEWER_H__ diff --git a/pptk/viewer/viewer.py b/pptk/viewer/viewer.py index c1f92bd..4132f83 100644 --- a/pptk/viewer/viewer.py +++ b/pptk/viewer/viewer.py @@ -51,7 +51,7 @@ def __init__(self, *args, **kwargs): s.bind(('localhost', 0)) s.listen(0) self._process = subprocess.Popen( - [os.path.join(_viewer_dir, 'viewer'), str(s.getsockname()[1])], + [os.path.join(_viewer_dir, 'viewer'), str(s.getsockname()[1]),'100','1000'], stdout=subprocess.PIPE, stderr=(None if debug else subprocess.PIPE)) if debug: @@ -121,6 +121,8 @@ def set(self, **kwargs): show_info bool Show information text overlay show_axis bool Show axis / look-at cursor theta float32 Camera elevation angle (radians) + vFOV float32 Camera vertical field of view + window_size 2 x uint set window size ================= =============== ================================= (phi, theta, r) are spherical coordinates specifying camera position @@ -295,7 +297,7 @@ def capture(self, filename): """ msg = struct.pack('b', 6) + _pack_string(os.path.abspath(filename)) - self.__send(msg) + self.__send(msg, True) def play(self, poses, ts=[], tlim=[-numpy.inf, numpy.inf], repeat=False, interp='cubic_natural'): @@ -440,7 +442,7 @@ def __load(self, positions): # send message to viewer self.__send(msg) - def __send(self, msg): + def __send(self, msg, blocking = False): s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect(('localhost', self._portNumber)) totalSent = 0 @@ -449,6 +451,13 @@ def __send(self, msg): if sent == 0: raise RuntimeError("socket connection broken") totalSent = totalSent + sent + if blocking: + s.setblocking(1) + buf = b'' + while len(buf) == 0: + buf += s.recv(1) + if buf != b'c': + raise RuntimeError('expecting return code \'c\'') s.close() def __query(self, msg): @@ -601,10 +610,12 @@ def _init_properties(): _properties['phi'] = _encode_float _properties['theta'] = _encode_float _properties['r'] = _encode_float + _properties['vFOV'] = _encode_float _properties['selected'] = _encode_uints _properties['color_map'] = _encode_rgbas _properties['color_map_scale'] = _encode_floats _properties['curr_attribute_id'] = _encode_uint + _properties['window_size'] = _encode_uints def _construct_get_msg(prop_name):