jpeg splash images

This commit is contained in:
David Rose 2009-06-25 01:37:26 +00:00
parent 1de9cc165b
commit 5fea6fffd7
6 changed files with 282 additions and 21 deletions

View File

@ -3,7 +3,7 @@
#define BUILD_DIRECTORY $[and $[HAVE_P3D_PLUGIN],$[HAVE_TINYXML],$[HAVE_OPENSSL],$[HAVE_ZLIB]]
#begin lib_target
#define USE_PACKAGES tinyxml openssl zlib
#define USE_PACKAGES tinyxml openssl zlib jpeg
#define TARGET p3d_plugin
#define LIB_PREFIX

View File

@ -98,13 +98,6 @@ set_fparams(const P3DFileParams &fparams) {
_got_fparams = true;
_fparams = fparams;
// Maybe create the splash window.
if (!_instance_window_opened && _got_wparams) {
if (_splash_window == NULL) {
_splash_window = new SplashWindowType(this);
}
}
// This also sets up some internal data based on the contents of the
// above file and the associated tokens.
@ -115,6 +108,21 @@ set_fparams(const P3DFileParams &fparams) {
_session_key = strm.str();
_python_version = "python24";
// Maybe create the splash window.
if (!_instance_window_opened && _got_wparams) {
if (_splash_window == NULL) {
_splash_window = new SplashWindowType(this);
// _splash_window->set_image_filename("c:/Documents and Settings/drose/Desktop/pandalogo.jpg");
}
}
/*
string splash_image_url = _fparams.lookup_token("splash_img");
if (!splash_image_url.is_empty()) {
}
*/
}
////////////////////////////////////////////////////////////////////
@ -133,6 +141,7 @@ set_wparams(const P3DWindowParams &wparams) {
if (!_instance_window_opened && _got_fparams) {
if (_splash_window == NULL) {
_splash_window = new SplashWindowType(this);
// _splash_window->set_image_filename("c:/Documents and Settings/drose/Desktop/pandalogo.jpg");
} else {
_splash_window->set_wparams(_wparams);
}

View File

@ -50,6 +50,16 @@ set_wparams(const P3DWindowParams &wparams) {
_wparams = wparams;
}
////////////////////////////////////////////////////////////////////
// Function: P3DSplashWindow::set_image_filename
// Access: Public, Virtual
// Description: Specifies the name of a JPEG image file that is
// displayed in the center of the splash window.
////////////////////////////////////////////////////////////////////
void P3DSplashWindow::
set_image_filename(const string &image_filename) {
}
////////////////////////////////////////////////////////////////////
// Function: P3DSplashWindow::set_install_label
// Access: Public, Virtual

View File

@ -42,6 +42,7 @@ public:
virtual void set_wparams(const P3DWindowParams &wparams);
inline const P3DWindowParams &get_wparams() const;
virtual void set_image_filename(const string &image_filename);
virtual void set_install_label(const string &install_label);
virtual void set_install_progress(double install_progress);

View File

@ -16,6 +16,31 @@
#ifdef _WIN32
// Stuff to use libjpeg.
extern "C" {
#include <jpeglib.h>
#include <jerror.h>
}
#include <setjmp.h>
struct my_error_mgr {
struct jpeg_error_mgr pub;
jmp_buf setjmp_buffer;
};
typedef struct my_error_mgr *my_error_ptr;
METHODDEF(void) my_error_exit (j_common_ptr cinfo) {
// cinfo->err really points to a my_error_mgr struct, so coerce pointer
my_error_ptr myerr = (my_error_ptr) cinfo->err;
// Return control to the setjmp point
longjmp(myerr->setjmp_buffer, 1);
}
////////////////////////////////////////////////////////////////////
// Function: P3DWinSplashWindow::Constructor
// Access: Public
@ -28,12 +53,14 @@ P3DWinSplashWindow(P3DInstance *inst) :
_thread = NULL;
_thread_id = 0;
_hwnd = NULL;
_bitmap = NULL;
_progress_bar = NULL;
_text_label = NULL;
_thread_running = false;
_got_install = false;
_install_progress = 0.0;
_image_filename_changed = false;
_install_label_changed = false;
_install_progress = 0.0;
INIT_LOCK(_install_lock);
@ -52,6 +79,31 @@ P3DWinSplashWindow::
DESTROY_LOCK(_install_lock);
}
////////////////////////////////////////////////////////////////////
// Function: P3DWinSplashWindow::set_image_filename
// Access: Public, Virtual
// Description: Specifies the name of a JPEG image file that is
// displayed in the center of the splash window.
////////////////////////////////////////////////////////////////////
void P3DWinSplashWindow::
set_image_filename(const string &image_filename) {
ACQUIRE_LOCK(_install_lock);
if (_image_filename != image_filename) {
_image_filename = image_filename;
_image_filename_changed = true;
}
RELEASE_LOCK(_install_lock);
// Post a silly message to spin the message loop.
PostThreadMessage(_thread_id, WM_USER, 0, 0);
if (!_thread_running && _thread_continue) {
// The user must have closed the window. Let's shut down the
// instance, too.
_inst->request_stop();
}
}
////////////////////////////////////////////////////////////////////
// Function: P3DWinSplashWindow::set_install_label
// Access: Public, Virtual
@ -156,6 +208,10 @@ thread_run() {
if (_got_install) {
ACQUIRE_LOCK(_install_lock);
double install_progress = _install_progress;
if (_image_filename_changed) {
update_image_filename(_image_filename);
}
_image_filename_changed = false;
if (_install_label_changed && _progress_bar != NULL) {
update_install_label(_install_label);
}
@ -213,7 +269,7 @@ make_window() {
static bool registered_class = false;
if (!registered_class) {
ZeroMemory(&wc, sizeof(WNDCLASS));
wc.lpfnWndProc = window_proc;
wc.lpfnWndProc = st_window_proc;
wc.hInstance = application;
wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wc.lpszClassName = "panda3d_splash";
@ -241,7 +297,7 @@ make_window() {
if (_wparams.get_window_type() == P3D_WT_embedded) {
// Create an embedded window.
DWORD window_style =
WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS;
WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS;
HWND parent_hwnd = _wparams.get_parent_window()._hwnd;
@ -270,9 +326,9 @@ make_window() {
nout << "Could not create toplevel window!\n";
return;
}
ShowWindow(_hwnd, SW_SHOWNORMAL);
}
SetWindowLongPtr(_hwnd, GWLP_USERDATA, (LONG_PTR)this);
ShowWindow(_hwnd, SW_SHOWNORMAL);
}
@ -308,18 +364,19 @@ make_progress_bar() {
int bar_width = min((int)(width * 0.6), 400);
int bar_height = min((int)(height * 0.1), 24);
int bar_x = (width - bar_width) / 2;
int bar_y = (height - bar_height) / 2;
int bar_y = (height - bar_height * 2);
_progress_bar =
CreateWindowEx(0, PROGRESS_CLASS, "", window_style,
bar_x, bar_y, bar_width, bar_height,
_hwnd, NULL, application, 0);
CreateWindowEx(0, PROGRESS_CLASS, "", window_style,
bar_x, bar_y, bar_width, bar_height,
_hwnd, NULL, application, 0);
SendMessage(_progress_bar, PBM_SETPOS, (int)(install_progress * 100.0), 0);
ShowWindow(_progress_bar, SW_SHOWNORMAL);
update_install_label(install_label);
}
////////////////////////////////////////////////////////////////////
// Function: P3DWinSplashWindow::update_install_label
// Access: Private
@ -361,7 +418,7 @@ update_install_label(const string &install_label) {
int height = rect.bottom - rect.top;
int bar_height = min((int)(height * 0.1), 24);
int bar_y = (height - bar_height) / 2;
int bar_y = (height - bar_height * 2);
int text_width = text_size.cx;
int text_height = text_size.cy;
@ -374,6 +431,107 @@ update_install_label(const string &install_label) {
ShowWindow(_text_label, SW_SHOWNORMAL);
}
////////////////////////////////////////////////////////////////////
// Function: P3DWinSplashWindow::update_image_filename
// Access: Private
// Description: Loads the splash image, converts to to BITMAP form,
// and stores it in _bitmap. Runs only in the
// sub-thread.
////////////////////////////////////////////////////////////////////
void P3DWinSplashWindow::
update_image_filename(const string &image_filename) {
// Clear the old image.
if (_bitmap != NULL) {
DeleteObject(_bitmap);
_bitmap = NULL;
}
// Since we'll be displaying a new image, we need to refresh the
// window.
InvalidateRect(_hwnd, NULL, TRUE);
FILE *fp = fopen(image_filename.c_str(), "rb");
if (fp == NULL) {
nout << "Couldn't open splash file image: " << image_filename << "\n"
<< flush;
return;
}
// We set up the normal JPEG error routines, then override error_exit.
struct jpeg_decompress_struct cinfo;
struct my_error_mgr jerr;
cinfo.err = jpeg_std_error(&jerr.pub);
jerr.pub.error_exit = my_error_exit;
// Establish the setjmp return context for my_error_exit to use
if (setjmp(jerr.setjmp_buffer)) {
// If we get here, the JPEG code has signaled an error.
nout << "JPEG error decoding " << image_filename << "\n"
<< flush;
// We need to clean up the JPEG object, close the input file, and return.
jpeg_destroy_decompress(&cinfo);
fclose(fp);
return;
}
/* Now we can initialize the JPEG decompression object. */
jpeg_create_decompress(&cinfo);
jpeg_stdio_src(&cinfo, fp);
jpeg_read_header(&cinfo, true);
cinfo.scale_num = 1;
cinfo.scale_denom = 1;
jpeg_start_decompress(&cinfo);
_bitmap_width = cinfo.output_width;
_bitmap_height = cinfo.output_height;
int row_stride = _bitmap_width * cinfo.output_components;
// We have to pad row_stride out to DWORD alignment.
row_stride = 4 * ((row_stride + 3) / 4);
size_t buffer_size = _bitmap_height * row_stride;
JSAMPLE *buffer = new JSAMPLE[buffer_size];
JSAMPLE *buffer_end = buffer + buffer_size;
JSAMPLE *rowptr = buffer;
while (cinfo.output_scanline < cinfo.output_height) {
assert(rowptr + row_stride <= buffer_end);
jpeg_read_scanlines(&cinfo, &rowptr, 1);
rowptr += row_stride;
}
jpeg_finish_decompress(&cinfo);
// Now load the image.
BITMAPINFOHEADER bmih;
bmih.biSize = sizeof(bmih);
bmih.biWidth = _bitmap_width;
bmih.biHeight = -_bitmap_height;
bmih.biPlanes = 1;
bmih.biBitCount = 8 * cinfo.output_components;
bmih.biCompression = BI_RGB;
bmih.biSizeImage = 0;
bmih.biXPelsPerMeter = 0;
bmih.biYPelsPerMeter = 0;
bmih.biClrUsed = 0;
bmih.biClrImportant = 0;
BITMAPINFO bmi;
memcpy(&bmi, &bmih, sizeof(bmih));
HDC dc = GetDC(_hwnd);
_bitmap = CreateDIBitmap(dc, &bmih, CBM_INIT, buffer, &bmi, 0);
ReleaseDC(_hwnd, dc);
nout << "Loaded splash file image: " << image_filename << "\n"
<< flush;
}
////////////////////////////////////////////////////////////////////
// Function: P3DWinSplashWindow::close_window
// Access: Private
@ -381,16 +539,21 @@ update_install_label(const string &install_label) {
////////////////////////////////////////////////////////////////////
void P3DWinSplashWindow::
close_window() {
if (_hwnd) {
if (_hwnd != NULL) {
ShowWindow(_hwnd, SW_HIDE);
CloseWindow(_hwnd);
_hwnd = NULL;
}
if (_bitmap != NULL) {
DeleteObject(_bitmap);
_bitmap = NULL;
}
}
////////////////////////////////////////////////////////////////////
// Function: P3DWinSplashWindow::window_proc
// Access: Private, Static
// Access: Private
// Description: The windows event-processing handler.
////////////////////////////////////////////////////////////////////
LONG P3DWinSplashWindow::
@ -400,6 +563,62 @@ window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
PostQuitMessage(0);
break;
case WM_SIZE:
InvalidateRect(hwnd, NULL, TRUE);
break;
case WM_PAINT:
nout << "WM_PAINT, _bitmap = " << _bitmap << "\n";
{
PAINTSTRUCT ps;
HDC dc = BeginPaint(hwnd, &ps);
if (_bitmap != NULL) {
// Paint the background splash image.
HDC mem_dc = CreateCompatibleDC(dc);
SelectObject(mem_dc, _bitmap);
// Determine the relative size of bitmap and window.
RECT rect;
GetClientRect(hwnd, &rect);
int win_width = rect.right - rect.left;
int win_height = rect.bottom - rect.top;
int bm_width = _bitmap_width;
int bm_height = _bitmap_height;
int win_cx = win_width / 2;
int win_cy = win_height / 2;
if (bm_width <= win_width && bm_height <= win_height) {
// The bitmap fits within the window; center it.
// This is the top-left corner of the bitmap in window coordinates.
int p_x = win_cx - bm_width / 2;
int p_y = win_cy - bm_height / 2;
BitBlt(dc, p_x, p_y, bm_width, bm_height,
mem_dc, 0, 0, SRCCOPY);
} else {
// The bitmap is larger than the window; scale it down.
double x_scale = (double)win_width / (double)bm_width;
double y_scale = (double)win_height / (double)bm_height;
double scale = min(x_scale, y_scale);
int sc_width = (int)(bm_width * scale);
int sc_height = (int)(bm_height * scale);
int p_x = win_cx - sc_width / 2;
int p_y = win_cy - sc_height / 2;
StretchBlt(dc, p_x, p_y, sc_width, sc_height,
mem_dc, 0, 0, bm_width, bm_height, SRCCOPY);
}
SelectObject(mem_dc, NULL);
DeleteDC(mem_dc);
}
EndPaint(hwnd, &ps);
}
break;
case WM_DRAWITEM:
// Draw a text label placed within the window.
{
@ -422,5 +641,20 @@ window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
return DefWindowProc(hwnd, msg, wparam, lparam);
}
////////////////////////////////////////////////////////////////////
// Function: P3DWinSplashWindow::st_window_proc
// Access: Private, Static
// Description: The windows event-processing handler, static version.
////////////////////////////////////////////////////////////////////
LONG P3DWinSplashWindow::
st_window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
LONG_PTR self = GetWindowLongPtr(hwnd, GWLP_USERDATA);
if (self == NULL) {
// We haven't assigned the pointer yet.
return DefWindowProc(hwnd, msg, wparam, lparam);
}
return ((P3DWinSplashWindow *)self)->window_proc(hwnd, msg, wparam, lparam);
}
#endif // _WIN32

View File

@ -34,6 +34,7 @@ public:
P3DWinSplashWindow(P3DInstance *inst);
virtual ~P3DWinSplashWindow();
virtual void set_image_filename(const string &image_filename);
virtual void set_install_label(const string &install_label);
virtual void set_install_progress(double install_progress);
@ -49,12 +50,16 @@ private:
void make_window();
void make_progress_bar();
void update_install_label(const string &install_label);
void update_image_filename(const string &image_filename);
void close_window();
static LONG WINAPI window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam);
LONG window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam);
static LONG WINAPI st_window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam);
private:
bool _got_install;
bool _image_filename_changed;
string _image_filename;
bool _install_label_changed;
string _install_label;
double _install_progress;
@ -67,6 +72,8 @@ private:
HANDLE _thread;
DWORD _thread_id;
HWND _hwnd;
HBITMAP _bitmap;
int _bitmap_width, _bitmap_height;
HWND _progress_bar;
HWND _text_label;
};