diff --git a/panda/src/tinydisplay/tinyGraphicsStateGuardian.cxx b/panda/src/tinydisplay/tinyGraphicsStateGuardian.cxx index 9a085c9cc9..2334feec68 100644 --- a/panda/src/tinydisplay/tinyGraphicsStateGuardian.cxx +++ b/panda/src/tinydisplay/tinyGraphicsStateGuardian.cxx @@ -446,27 +446,8 @@ end_scene() { int fb_xsize = int(xsize * pixel_factor); int fb_ysize = int(ysize * pixel_factor); - int tyinc = _current_frame_buffer->linesize / PSZB; - int fyinc = _aux_frame_buffer->linesize / PSZB; - - int fyt = 0; - for (int ty = 0; ty < ysize; ++ty) { - int fy = fyt / ysize; - fyt += fb_ysize; - - PIXEL *tp = _current_frame_buffer->pbuf + xmin + (ymin + ty) * tyinc; - PIXEL *fp = _aux_frame_buffer->pbuf + fy * fyinc; - ZPOINT *tz = _current_frame_buffer->zbuf + xmin + (ymin + ty) * _current_frame_buffer->xsize; - ZPOINT *fz = _aux_frame_buffer->zbuf + fy * _aux_frame_buffer->xsize; - int fxt = 0; - for (int tx = 0; tx < xsize; ++tx) { - int fx = fxt / xsize; - fxt += fb_xsize; - - tp[tx] = fp[fx]; - tz[tx] = fz[fx]; - } - } + ZB_zoomFrameBuffer(_current_frame_buffer, xmin, ymin, xsize, ysize, + _aux_frame_buffer, 0, 0, fb_xsize, fb_ysize); _c->zb = _current_frame_buffer; } diff --git a/panda/src/tinydisplay/tinyXGraphicsWindow.cxx b/panda/src/tinydisplay/tinyXGraphicsWindow.cxx index af51cc03e6..d8153fc593 100644 --- a/panda/src/tinydisplay/tinyXGraphicsWindow.cxx +++ b/panda/src/tinydisplay/tinyXGraphicsWindow.cxx @@ -78,7 +78,8 @@ TinyXGraphicsWindow(GraphicsPipe *pipe, _net_wm_state_add = tinyx_pipe->_net_wm_state_add; _net_wm_state_remove = tinyx_pipe->_net_wm_state_remove; - _frame_buffer = NULL; + _reduced_frame_buffer = NULL; + _full_frame_buffer = NULL; _ximage = NULL; update_pixel_factor(); @@ -159,7 +160,11 @@ begin_frame(FrameMode mode, Thread *current_thread) { TinyGraphicsStateGuardian *tinygsg; DCAST_INTO_R(tinygsg, _gsg, false); - tinygsg->_current_frame_buffer = _frame_buffer; + if (_reduced_frame_buffer != (ZBuffer *)NULL) { + tinygsg->_current_frame_buffer = _reduced_frame_buffer; + } else { + tinygsg->_current_frame_buffer = _full_frame_buffer; + } tinygsg->reset_if_new(); _gsg->set_current_properties(&get_fb_properties()); @@ -210,17 +215,25 @@ end_frame(FrameMode mode, Thread *current_thread) { //////////////////////////////////////////////////////////////////// void TinyXGraphicsWindow:: begin_flip() { - if (_bytes_per_pixel == 4 && _pitch == _frame_buffer->linesize) { + if (_reduced_frame_buffer != (ZBuffer *)NULL) { + // Zoom the reduced buffer onto the full buffer. + ZB_zoomFrameBuffer(_full_frame_buffer, 0, 0, + _full_frame_buffer->xsize, _full_frame_buffer->ysize, + _reduced_frame_buffer, 0, 0, + _reduced_frame_buffer->xsize, _reduced_frame_buffer->ysize); + } + + if (_bytes_per_pixel == 4 && _pitch == _full_frame_buffer->linesize) { // If we match the expected bpp, we don't need an intervening copy // operation. Just point the XImage directly at the framebuffer // data. - _ximage->data = (char *)_frame_buffer->pbuf; + _ximage->data = (char *)_full_frame_buffer->pbuf; } else { - ZB_copyFrameBuffer(_frame_buffer, _ximage->data, _pitch); + ZB_copyFrameBuffer(_full_frame_buffer, _ximage->data, _pitch); } XPutImage(_display, _xwindow, _gc, _ximage, 0, 0, 0, 0, - _frame_buffer->xsize, _frame_buffer->ysize); + _full_frame_buffer->xsize, _full_frame_buffer->ysize); XFlush(_display); } @@ -331,8 +344,9 @@ process_events() { // A normal window may be resized by the user at will. properties.set_size(event.xconfigure.width, event.xconfigure.height); system_changed_properties(properties); - ZB_resize(_frame_buffer, NULL, _properties.get_x_size(), _properties.get_y_size()); - _pitch = (_frame_buffer->xsize * _bytes_per_pixel + 3) & ~3; + ZB_resize(_full_frame_buffer, NULL, _properties.get_x_size(), _properties.get_y_size()); + _pitch = (_full_frame_buffer->xsize * _bytes_per_pixel + 3) & ~3; + create_reduced_frame_buffer(); create_ximage(); } break; @@ -774,16 +788,17 @@ open_window() { _gc = XCreateGC(_display, _xwindow, 0, NULL); - create_frame_buffer(); - if (_frame_buffer == NULL) { + create_full_frame_buffer(); + if (_full_frame_buffer == NULL) { tinydisplay_cat.error() << "Could not create frame buffer.\n"; return false; } + create_reduced_frame_buffer(); create_ximage(); nassertr(_ximage != NULL, false); - tinygsg->_current_frame_buffer = _frame_buffer; + tinygsg->_current_frame_buffer = _full_frame_buffer; tinygsg->reset_if_new(); if (!tinygsg->is_valid()) { @@ -805,6 +820,17 @@ open_window() { return true; } +//////////////////////////////////////////////////////////////////// +// Function: TinyXGraphicsWindow::pixel_factor_changed +// Access: Protected, Virtual +// Description: Called internally when the pixel factor changes. +//////////////////////////////////////////////////////////////////// +void TinyXGraphicsWindow:: +pixel_factor_changed() { + GraphicsWindow::pixel_factor_changed(); + create_reduced_frame_buffer(); +} + //////////////////////////////////////////////////////////////////// // Function: TinyXGraphicsWindow::set_wm_properties // Access: Private @@ -1580,16 +1606,16 @@ check_event(Display *display, XEvent *event, char *arg) { } //////////////////////////////////////////////////////////////////// -// Function: TinyXGraphicsWindow::create_frame_buffer +// Function: TinyXGraphicsWindow::create_full_frame_buffer // Access: Private // Description: Creates a suitable frame buffer for the current // window size. //////////////////////////////////////////////////////////////////// void TinyXGraphicsWindow:: -create_frame_buffer() { - if (_frame_buffer != NULL) { - ZB_close(_frame_buffer); - _frame_buffer = NULL; +create_full_frame_buffer() { + if (_full_frame_buffer != NULL) { + ZB_close(_full_frame_buffer); + _full_frame_buffer = NULL; } int mode; @@ -1610,8 +1636,34 @@ create_frame_buffer() { return; } - _frame_buffer = ZB_open(_properties.get_x_size(), _properties.get_y_size(), mode, 0, 0, 0, 0); - _pitch = (_frame_buffer->xsize * _bytes_per_pixel + 3) & ~3; + _full_frame_buffer = ZB_open(_properties.get_x_size(), _properties.get_y_size(), mode, 0, 0, 0, 0); + _pitch = (_full_frame_buffer->xsize * _bytes_per_pixel + 3) & ~3; +} + +//////////////////////////////////////////////////////////////////// +// Function: TinyXGraphicsWindow::create_reduced_frame_buffer +// Access: Private +// Description: Creates a suitable frame buffer for the current +// window size and pixel zoom. +//////////////////////////////////////////////////////////////////// +void TinyXGraphicsWindow:: +create_reduced_frame_buffer() { + if (_reduced_frame_buffer != NULL) { + ZB_close(_reduced_frame_buffer); + _reduced_frame_buffer = NULL; + } + + int x_size = get_fb_x_size(); + int y_size = get_fb_y_size(); + + if (x_size == _full_frame_buffer->xsize) { + // No zooming is necessary. + + } else { + // The reduced size is different, so we need a separate buffer to + // render into. + _reduced_frame_buffer = ZB_open(x_size, y_size, _full_frame_buffer->mode, 0, 0, 0, 0); + } } @@ -1632,14 +1684,14 @@ create_ximage() { _ximage = NULL; } - int image_size = _frame_buffer->ysize * _pitch; + int image_size = _full_frame_buffer->ysize * _pitch; char *data = NULL; if (_bytes_per_pixel != 4) { data = (char *)PANDA_MALLOC_ARRAY(image_size); } _ximage = XCreateImage(_display, _visual, _depth, ZPixmap, 0, data, - _frame_buffer->xsize, _frame_buffer->ysize, + _full_frame_buffer->xsize, _full_frame_buffer->ysize, 32, 0); } diff --git a/panda/src/tinydisplay/tinyXGraphicsWindow.h b/panda/src/tinydisplay/tinyXGraphicsWindow.h index 33ac5c16a4..60a9674719 100644 --- a/panda/src/tinydisplay/tinyXGraphicsWindow.h +++ b/panda/src/tinydisplay/tinyXGraphicsWindow.h @@ -31,12 +31,12 @@ class EXPCL_TINYDISPLAY TinyXGraphicsWindow : public GraphicsWindow { public: TinyXGraphicsWindow(GraphicsPipe *pipe, - const string &name, - const FrameBufferProperties &fb_prop, - const WindowProperties &win_prop, - int flags, - GraphicsStateGuardian *gsg, - GraphicsOutput *host); + const string &name, + const FrameBufferProperties &fb_prop, + const WindowProperties &win_prop, + int flags, + GraphicsStateGuardian *gsg, + GraphicsOutput *host); virtual ~TinyXGraphicsWindow(); virtual bool move_pointer(int device, int x, int y); @@ -51,6 +51,7 @@ public: protected: virtual void close_window(); virtual bool open_window(); + virtual void pixel_factor_changed(); private: void set_wm_properties(const WindowProperties &properties, @@ -69,11 +70,13 @@ private: void open_raw_mice(); void poll_raw_mice(); - void create_frame_buffer(); + void create_full_frame_buffer(); + void create_reduced_frame_buffer(); void create_ximage(); private: - ZBuffer *_frame_buffer; + ZBuffer *_reduced_frame_buffer; + ZBuffer *_full_frame_buffer; int _pitch; XImage *_ximage; diff --git a/panda/src/tinydisplay/zbuffer.cxx b/panda/src/tinydisplay/zbuffer.cxx index 4e27952ba3..49ee2771dd 100644 --- a/panda/src/tinydisplay/zbuffer.cxx +++ b/panda/src/tinydisplay/zbuffer.cxx @@ -130,7 +130,7 @@ void ZB_resize(ZBuffer * zb, void *frame_buffer, int xsize, int ysize) } } -static void ZB_copyBuffer(ZBuffer * zb, +static void ZB_copyBuffer(const ZBuffer * zb, void *buf, int linesize) { @@ -152,7 +152,7 @@ static void ZB_copyBuffer(ZBuffer * zb, (((v >> 8) & 0xf800) | (((v) >> 5) & 0x07e0) | (((v) & 0xff) >> 3)) /* XXX: not optimized */ -static void ZB_copyFrameBuffer5R6G5B(ZBuffer * zb, +static void ZB_copyFrameBuffer5R6G5B(const ZBuffer * zb, void *buf, int linesize) { PIXEL *q; @@ -178,7 +178,7 @@ static void ZB_copyFrameBuffer5R6G5B(ZBuffer * zb, } /* XXX: not optimized */ -static void ZB_copyFrameBufferRGB24(ZBuffer * zb, +static void ZB_copyFrameBufferRGB24(const ZBuffer * zb, void *buf, int linesize) { PIXEL *q; @@ -204,7 +204,7 @@ static void ZB_copyFrameBufferRGB24(ZBuffer * zb, } } -void ZB_copyFrameBuffer(ZBuffer * zb, void *buf, +void ZB_copyFrameBuffer(const ZBuffer * zb, void *buf, int linesize) { switch (zb->mode) { @@ -228,6 +228,33 @@ void ZB_copyFrameBuffer(ZBuffer * zb, void *buf, } } +// Copy from (source_xmin,source_ymin)+(source_xsize,source_ysize) to +// (dest_xmin,dest_ymin)+(dest_xsize,dest_ysize). +void ZB_zoomFrameBuffer(ZBuffer *dest, int dest_xmin, int dest_ymin, int dest_xsize, int dest_ysize, + const ZBuffer *source, int source_xmin, int source_ymin, int source_xsize, int source_ysize) { + int tyinc = dest->linesize / PSZB; + int fyinc = source->linesize / PSZB; + + int fyt = 0; + for (int ty = 0; ty < dest_ysize; ++ty) { + int fy = fyt / dest_ysize; + fyt += source_ysize; + + PIXEL *tp = dest->pbuf + dest_xmin + (dest_ymin + ty) * tyinc; + PIXEL *fp = source->pbuf + source_xmin + (source_ymin + fy) * fyinc; + ZPOINT *tz = dest->zbuf + dest_xmin + (dest_ymin + ty) * dest->xsize; + ZPOINT *fz = source->zbuf + source_xmin + (source_ymin + fy) * source->xsize; + int fxt = 0; + for (int tx = 0; tx < dest_xsize; ++tx) { + int fx = fxt / dest_xsize; + fxt += source_xsize; + + tp[tx] = fp[fx]; + tz[tx] = fz[fx]; + } + } +} + /* * adr must be aligned on an 'int' diff --git a/panda/src/tinydisplay/zbuffer.h b/panda/src/tinydisplay/zbuffer.h index 19a062d68c..2dfc5bd31f 100644 --- a/panda/src/tinydisplay/zbuffer.h +++ b/panda/src/tinydisplay/zbuffer.h @@ -229,7 +229,11 @@ int texcoord_mirror(int coord, int max_coord); int texcoord_mirror_once(int coord, int max_coord); /* linesize is in BYTES */ -void ZB_copyFrameBuffer(ZBuffer *zb,void *buf,int linesize); +void ZB_copyFrameBuffer(const ZBuffer *zb,void *buf,int linesize); +void ZB_zoomFrameBuffer(ZBuffer *dest, int dest_xmin, int dest_ymin, + int dest_xsize, int dest_ysize, + const ZBuffer *source, int source_xmin, int source_ymin, + int source_xsize, int source_ysize); /* zdither.c */