// Filename: tinyWinGraphicsWindow.cxx // Created by: drose (06May08) // //////////////////////////////////////////////////////////////////// // // PANDA 3D SOFTWARE // Copyright (c) Carnegie Mellon University. All rights reserved. // // All use of this software is subject to the terms of the revised BSD // license. You should have received a copy of this license along // with this source code in a file named "LICENSE." // //////////////////////////////////////////////////////////////////// #include "pandabase.h" #ifdef WIN32 #include "tinyWinGraphicsWindow.h" #include "config_tinydisplay.h" #include "config_windisplay.h" #include "tinyWinGraphicsPipe.h" #include "tinyGraphicsStateGuardian.h" #include "pStatTimer.h" #include TypeHandle TinyWinGraphicsWindow::_type_handle; //////////////////////////////////////////////////////////////////// // Function: TinyWinGraphicsWindow::Constructor // Access: Public // Description: //////////////////////////////////////////////////////////////////// TinyWinGraphicsWindow:: TinyWinGraphicsWindow(GraphicsPipe *pipe, const string &name, const FrameBufferProperties &fb_prop, const WindowProperties &win_prop, int flags, GraphicsStateGuardian *gsg, GraphicsOutput *host) : WinGraphicsWindow(pipe, name, fb_prop, win_prop, flags, gsg, host) { _frame_buffer = NULL; _hdc = (HDC)0; update_pixel_factor(); } //////////////////////////////////////////////////////////////////// // Function: TinyWinGraphicsWindow::Destructor // Access: Public, Virtual // Description: //////////////////////////////////////////////////////////////////// TinyWinGraphicsWindow:: ~TinyWinGraphicsWindow() { } //////////////////////////////////////////////////////////////////// // Function: TinyWinGraphicsWindow::begin_frame // Access: Public, Virtual // Description: This function will be called within the draw thread // before beginning rendering for a given frame. It // should do whatever setup is required, and return true // if the frame should be rendered, or false if it // should be skipped. //////////////////////////////////////////////////////////////////// bool TinyWinGraphicsWindow:: begin_frame(FrameMode mode, Thread *current_thread) { begin_frame_spam(mode); if (_gsg == (GraphicsStateGuardian *)NULL) { return false; } TinyGraphicsStateGuardian *tinygsg; DCAST_INTO_R(tinygsg, _gsg, false); tinygsg->_current_frame_buffer = _frame_buffer; tinygsg->reset_if_new(); _gsg->set_current_properties(&get_fb_properties()); return _gsg->begin_frame(current_thread); } //////////////////////////////////////////////////////////////////// // Function: TinyWinGraphicsWindow::end_frame // Access: Public, Virtual // Description: This function will be called within the draw thread // after rendering is completed for a given frame. It // should do whatever finalization is required. //////////////////////////////////////////////////////////////////// void TinyWinGraphicsWindow:: end_frame(FrameMode mode, Thread *current_thread) { end_frame_spam(mode); nassertv(_gsg != (GraphicsStateGuardian *)NULL); if (mode == FM_render) { // end_render_texture(); copy_to_textures(); } _gsg->end_frame(current_thread); if (mode == FM_render) { trigger_flip(); if (_one_shot) { prepare_for_deletion(); } clear_cube_map_selection(); } } //////////////////////////////////////////////////////////////////// // Function: TinyWinGraphicsWindow::begin_flip // Access: Public, Virtual // Description: This function will be called within the draw thread // after end_frame() has been called on all windows, to // initiate the exchange of the front and back buffers. // // This should instruct the window to prepare for the // flip at the next video sync, but it should not wait. // // We have the two separate functions, begin_flip() and // end_flip(), to make it easier to flip all of the // windows at the same time. //////////////////////////////////////////////////////////////////// void TinyWinGraphicsWindow:: begin_flip() { HBITMAP bm = CreateCompatibleBitmap(_hdc, _frame_buffer->xsize, _frame_buffer->ysize); HDC bmdc = CreateCompatibleDC(_hdc); SelectObject(bmdc, bm); int fb_xsize = get_fb_x_size(); int fb_ysize = get_fb_y_size(); int fb_ytop = _frame_buffer->ysize - fb_ysize; SetDIBits(_hdc, bm, fb_ytop, fb_ysize, _frame_buffer->pbuf, &_bitmap_info, DIB_RGB_COLORS); if (fb_xsize == _frame_buffer->xsize) { BitBlt(_hdc, 0, 0, fb_xsize, fb_ysize, bmdc, 0, 0, SRCCOPY); } else { // SetStretchBltMode(_hdc, HALFTONE); StretchBlt(_hdc, 0, 0, _frame_buffer->xsize, _frame_buffer->ysize, bmdc, 0, 0,fb_xsize, fb_ysize, SRCCOPY); } DeleteDC(bmdc); DeleteObject(bm); GdiFlush(); } //////////////////////////////////////////////////////////////////// // Function: TinyWinGraphicsWindow::supports_pixel_zoom // Access: Published, Virtual // Description: Returns true if a call to set_pixel_zoom() will be // respected, false if it will be ignored. If this // returns false, then get_pixel_factor() will always // return 1.0, regardless of what value you specify for // set_pixel_zoom(). // // This may return false if the underlying renderer // doesn't support pixel zooming, or if you have called // this on a DisplayRegion that doesn't have both // set_clear_color() and set_clear_depth() enabled. //////////////////////////////////////////////////////////////////// bool TinyWinGraphicsWindow:: supports_pixel_zoom() const { return true; } //////////////////////////////////////////////////////////////////// // Function: TinyWinGraphicsWindow::close_window // Access: Protected, Virtual // Description: Closes the window right now. Called from the window // thread. //////////////////////////////////////////////////////////////////// void TinyWinGraphicsWindow:: close_window() { if (_gsg != (GraphicsStateGuardian *)NULL) { TinyGraphicsStateGuardian *tinygsg; DCAST_INTO_V(tinygsg, _gsg); tinygsg->_current_frame_buffer = NULL; _gsg.clear(); _active = false; } ReleaseDC(_hWnd, _hdc); _hdc = (HDC)0; WinGraphicsWindow::close_window(); } //////////////////////////////////////////////////////////////////// // Function: TinyWinGraphicsWindow::open_window // Access: Protected, Virtual // Description: Opens the window right now. Called from the window // thread. Returns true if the window is successfully // opened, or false if there was a problem. //////////////////////////////////////////////////////////////////// bool TinyWinGraphicsWindow:: open_window() { if (!WinGraphicsWindow::open_window()) { return false; } // GSG Creation/Initialization TinyGraphicsStateGuardian *tinygsg; if (_gsg == 0) { // There is no old gsg. Create a new one. tinygsg = new TinyGraphicsStateGuardian(_pipe, NULL); _gsg = tinygsg; } else { DCAST_INTO_R(tinygsg, _gsg, false); } _hdc = GetDC(_hWnd); create_frame_buffer(); if (_frame_buffer == NULL) { tinydisplay_cat.error() << "Could not create frame buffer.\n"; return false; } tinygsg->_current_frame_buffer = _frame_buffer; tinygsg->reset_if_new(); if (!tinygsg->is_valid()) { close_window(); return false; } return true; } //////////////////////////////////////////////////////////////////// // Function: WinGraphicsWindow::handle_reshape // Access: Protected, Virtual // Description: Called in the window thread when the window size or // location is changed, this updates the properties // structure accordingly. //////////////////////////////////////////////////////////////////// void TinyWinGraphicsWindow:: handle_reshape() { WinGraphicsWindow::handle_reshape(); ZB_resize(_frame_buffer, NULL, _properties.get_x_size(), _properties.get_y_size()); setup_bitmap_info(); } //////////////////////////////////////////////////////////////////// // Function: WinGraphicsWindow::do_fullscreen_resize // Access: Protected, Virtual // Description: Called in the window thread when the window size or // location is changed, this updates the properties // structure accordingly. //////////////////////////////////////////////////////////////////// bool TinyWinGraphicsWindow:: do_fullscreen_resize(int x_size, int y_size) { bool result = WinGraphicsWindow::do_fullscreen_resize(x_size, y_size); ZB_resize(_frame_buffer, NULL, _properties.get_x_size(), _properties.get_y_size()); setup_bitmap_info(); return result; } //////////////////////////////////////////////////////////////////// // Function: TinyWinGraphicsWindow::create_frame_buffer // Access: Private // Description: Creates a suitable frame buffer for the current // window size. //////////////////////////////////////////////////////////////////// void TinyWinGraphicsWindow:: create_frame_buffer() { if (_frame_buffer != NULL) { ZB_close(_frame_buffer); _frame_buffer = NULL; } _frame_buffer = ZB_open(_properties.get_x_size(), _properties.get_y_size(), ZB_MODE_RGBA, 0, 0, 0, 0); setup_bitmap_info(); } //////////////////////////////////////////////////////////////////// // Function: TinyWinGraphicsWindow::setup_bitmap_info // Access: Private // Description: Determines the BITMAPINFO stuff for blitting the // frame buffer to the window. //////////////////////////////////////////////////////////////////// void TinyWinGraphicsWindow:: setup_bitmap_info() { _bitmap_info.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); _bitmap_info.bmiHeader.biWidth = _frame_buffer->xsize; _bitmap_info.bmiHeader.biHeight = -_frame_buffer->ysize; _bitmap_info.bmiHeader.biPlanes = 1; _bitmap_info.bmiHeader.biBitCount = 32; _bitmap_info.bmiHeader.biCompression = BI_RGB; _bitmap_info.bmiHeader.biSizeImage = _frame_buffer->linesize * _frame_buffer->ysize; _bitmap_info.bmiHeader.biXPelsPerMeter = 0; _bitmap_info.bmiHeader.biYPelsPerMeter = 0; _bitmap_info.bmiHeader.biClrUsed = 0; _bitmap_info.bmiHeader.biClrImportant = 0; } #endif // WIN32