mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-02 09:52:27 -04:00
alpha blending for x11
This commit is contained in:
parent
d870955f2c
commit
fd62333192
@ -462,11 +462,7 @@ set_mouse_data(int mouse_x, int mouse_y, bool mouse_down) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_bstate != bstate) {
|
set_bstate(bstate);
|
||||||
_bstate = bstate;
|
|
||||||
// If we've changed button states, we need to refresh the window.
|
|
||||||
refresh();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
@ -484,6 +480,21 @@ button_click_detected() {
|
|||||||
_inst->splash_button_clicked();
|
_inst->splash_button_clicked();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: P3DSplashWindow::set_bstate
|
||||||
|
// Access: Protected, Virtual
|
||||||
|
// Description: Changes the button state as the mouse interacts with
|
||||||
|
// it.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
void P3DSplashWindow::
|
||||||
|
set_bstate(ButtonState bstate) {
|
||||||
|
if (_bstate != bstate) {
|
||||||
|
_bstate = bstate;
|
||||||
|
// If we've changed button states, we need to refresh the window.
|
||||||
|
refresh();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Function: P3DSplashWindow::refresh
|
// Function: P3DSplashWindow::refresh
|
||||||
// Access: Protected, Virtual
|
// Access: Protected, Virtual
|
||||||
|
@ -80,7 +80,16 @@ protected:
|
|||||||
void set_button_range(const ImageData &image);
|
void set_button_range(const ImageData &image);
|
||||||
void set_mouse_data(int mouse_x, int mouse_y, bool mouse_down);
|
void set_mouse_data(int mouse_x, int mouse_y, bool mouse_down);
|
||||||
|
|
||||||
|
// The current visual state of the button.
|
||||||
|
enum ButtonState {
|
||||||
|
BS_hidden,
|
||||||
|
BS_ready,
|
||||||
|
BS_rollover,
|
||||||
|
BS_click,
|
||||||
|
};
|
||||||
|
|
||||||
virtual void button_click_detected();
|
virtual void button_click_detected();
|
||||||
|
virtual void set_bstate(ButtonState bstate);
|
||||||
virtual void refresh();
|
virtual void refresh();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
@ -99,14 +108,6 @@ protected:
|
|||||||
int _mouse_x, _mouse_y;
|
int _mouse_x, _mouse_y;
|
||||||
bool _mouse_down;
|
bool _mouse_down;
|
||||||
bool _button_depressed;
|
bool _button_depressed;
|
||||||
|
|
||||||
// The current visual state of the button.
|
|
||||||
enum ButtonState {
|
|
||||||
BS_hidden,
|
|
||||||
BS_ready,
|
|
||||||
BS_rollover,
|
|
||||||
BS_click,
|
|
||||||
};
|
|
||||||
ButtonState _bstate;
|
ButtonState _bstate;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -21,10 +21,6 @@
|
|||||||
inline P3DX11SplashWindow::X11ImageData::
|
inline P3DX11SplashWindow::X11ImageData::
|
||||||
X11ImageData() {
|
X11ImageData() {
|
||||||
_filename_changed = false;
|
_filename_changed = false;
|
||||||
_image = NULL;
|
|
||||||
_resized_image = NULL;
|
|
||||||
_resized_width = 0;
|
|
||||||
_resized_height = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
@ -34,6 +30,5 @@ X11ImageData() {
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
inline P3DX11SplashWindow::X11ImageData::
|
inline P3DX11SplashWindow::X11ImageData::
|
||||||
~X11ImageData() {
|
~X11ImageData() {
|
||||||
dump_image();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -44,6 +44,8 @@ P3DX11SplashWindow(P3DInstance *inst) :
|
|||||||
INIT_THREAD(_read_thread);
|
INIT_THREAD(_read_thread);
|
||||||
|
|
||||||
// Init for subprocess
|
// Init for subprocess
|
||||||
|
_composite_image = NULL;
|
||||||
|
_needs_new_composite = false;
|
||||||
_display = None;
|
_display = None;
|
||||||
_window = None;
|
_window = None;
|
||||||
_screen = 0;
|
_screen = 0;
|
||||||
@ -182,14 +184,28 @@ void P3DX11SplashWindow::
|
|||||||
button_click_detected() {
|
button_click_detected() {
|
||||||
// This method is called in the child process, and must relay
|
// This method is called in the child process, and must relay
|
||||||
// the information to the parent process.
|
// the information to the parent process.
|
||||||
cerr << "click detected\n";
|
|
||||||
|
|
||||||
TiXmlDocument doc;
|
TiXmlDocument doc;
|
||||||
TiXmlElement *xcommand = new TiXmlElement("click");
|
TiXmlElement *xcommand = new TiXmlElement("click");
|
||||||
doc.LinkEndChild(xcommand);
|
doc.LinkEndChild(xcommand);
|
||||||
write_xml(_pipe_write, &doc, nout);
|
write_xml(_pipe_write, &doc, nout);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: P3DX11SplashWindow::set_bstate
|
||||||
|
// Access: Protected, Virtual
|
||||||
|
// Description: Changes the button state as the mouse interacts with
|
||||||
|
// it.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
void P3DX11SplashWindow::
|
||||||
|
set_bstate(ButtonState bstate) {
|
||||||
|
if (_bstate != bstate) {
|
||||||
|
// When the button state changes, we need to remake the composite
|
||||||
|
// image.
|
||||||
|
_needs_new_composite = true;
|
||||||
|
P3DSplashWindow::set_bstate(bstate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Function: P3DX11SplashWindow::start_subprocess
|
// Function: P3DX11SplashWindow::start_subprocess
|
||||||
// Access: Private
|
// Access: Private
|
||||||
@ -474,12 +490,11 @@ subprocess_run() {
|
|||||||
_win_width = event.xconfigure.width;
|
_win_width = event.xconfigure.width;
|
||||||
_win_height = event.xconfigure.height;
|
_win_height = event.xconfigure.height;
|
||||||
|
|
||||||
// If the window changes size, we need to recompute all of the
|
set_button_range(_button_ready_image);
|
||||||
// resized images.
|
|
||||||
_background_image.dump_resized_image();
|
// If the window changes size, we need to recompute the
|
||||||
_button_ready_image.dump_resized_image();
|
// composed image.
|
||||||
_button_rollover_image.dump_resized_image();
|
_needs_new_composite = true;
|
||||||
_button_click_image.dump_resized_image();
|
|
||||||
}
|
}
|
||||||
needs_redraw = true;
|
needs_redraw = true;
|
||||||
break;
|
break;
|
||||||
@ -498,10 +513,15 @@ subprocess_run() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
update_image(_background_image, needs_redraw);
|
update_image(_background_image);
|
||||||
update_image(_button_ready_image, needs_redraw);
|
update_image(_button_ready_image);
|
||||||
update_image(_button_rollover_image, needs_redraw);
|
update_image(_button_rollover_image);
|
||||||
update_image(_button_click_image, needs_redraw);
|
update_image(_button_click_image);
|
||||||
|
|
||||||
|
if (_needs_new_composite) {
|
||||||
|
needs_redraw = true;
|
||||||
|
compose_image();
|
||||||
|
}
|
||||||
|
|
||||||
if (_bstate != prev_bstate) {
|
if (_bstate != prev_bstate) {
|
||||||
needs_redraw = true;
|
needs_redraw = true;
|
||||||
@ -689,79 +709,15 @@ receive_command() {
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
void P3DX11SplashWindow::
|
void P3DX11SplashWindow::
|
||||||
redraw() {
|
redraw() {
|
||||||
|
if (_composite_image == NULL) {
|
||||||
XClearWindow(_display, _window);
|
XClearWindow(_display, _window);
|
||||||
|
|
||||||
paint_image(_background_image);
|
|
||||||
|
|
||||||
switch (_bstate) {
|
|
||||||
case BS_hidden:
|
|
||||||
break;
|
|
||||||
case BS_ready:
|
|
||||||
paint_image(_button_ready_image);
|
|
||||||
break;
|
|
||||||
case BS_rollover:
|
|
||||||
if (!paint_image(_button_rollover_image)) {
|
|
||||||
paint_image(_button_ready_image);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case BS_click:
|
|
||||||
if (!paint_image(_button_click_image)) {
|
|
||||||
paint_image(_button_ready_image);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
|
||||||
// Function: P3DX11SplashWindow::paint_image
|
|
||||||
// Access: Private
|
|
||||||
// Description: Draws the indicated image, centered within the
|
|
||||||
// window. Returns true on success, false if the image
|
|
||||||
// is not defined.
|
|
||||||
////////////////////////////////////////////////////////////////////
|
|
||||||
bool P3DX11SplashWindow::
|
|
||||||
paint_image(X11ImageData &image) {
|
|
||||||
if (image._image == NULL) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// We have an image. Let's see how we can output it.
|
|
||||||
if (image._width <= _win_width && image._height <= _win_height) {
|
|
||||||
// It fits within the window - just draw it.
|
|
||||||
XPutImage(_display, _window, _graphics_context, image._image, 0, 0,
|
|
||||||
(_win_width - image._width) / 2, (_win_height - image._height) / 2,
|
|
||||||
image._width, image._height);
|
|
||||||
} else if (image._resized_image != NULL) {
|
|
||||||
// We have a resized image already, draw that one.
|
|
||||||
XPutImage(_display, _window, _graphics_context, image._resized_image, 0, 0,
|
|
||||||
(_win_width - image._resized_width) / 2, (_win_height - image._resized_height) / 2,
|
|
||||||
image._resized_width, image._resized_height);
|
|
||||||
} else {
|
} else {
|
||||||
// Yuck, the bad case - we need to scale it down.
|
XPutImage(_display, _window, _graphics_context, _composite_image, 0, 0,
|
||||||
double scale = min((double) _win_width / (double) image._width,
|
(_win_width - _composite_width) / 2, (_win_height - _composite_height) / 2,
|
||||||
(double) _win_height / (double) image._height);
|
_composite_width, _composite_height);
|
||||||
image._resized_width = (int)(image._width * scale);
|
|
||||||
image._resized_height = (int)(image._height * scale);
|
|
||||||
char *new_data = (char*) malloc(4 * _win_width * _win_height);
|
|
||||||
image._resized_image = XCreateImage(_display, CopyFromParent, DefaultDepth(_display, _screen),
|
|
||||||
ZPixmap, 0, (char *) new_data, _win_width, _win_height, 32, 0);
|
|
||||||
double x_ratio = ((double) image._width) / ((double) image._resized_width);
|
|
||||||
double y_ratio = ((double) image._height) / ((double) image._resized_height);
|
|
||||||
for (int x = 0; x < _win_width; ++x) {
|
|
||||||
for (int y = 0; y < _win_height; ++y) {
|
|
||||||
XPutPixel(image._resized_image, x, y,
|
|
||||||
XGetPixel(image._image,
|
|
||||||
(int)clamp(x * x_ratio, 0, image._width),
|
|
||||||
(int)clamp(y * y_ratio, 0, image._height)));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
XPutImage(_display, _window, _graphics_context, image._resized_image, 0, 0,
|
|
||||||
(_win_width - image._resized_width) / 2, (_win_height - image._resized_height) / 2,
|
|
||||||
image._resized_width, image._resized_height);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Function: P3DX11SplashWindow::make_window
|
// Function: P3DX11SplashWindow::make_window
|
||||||
@ -876,10 +832,10 @@ setup_gc() {
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
void P3DX11SplashWindow::
|
void P3DX11SplashWindow::
|
||||||
close_window() {
|
close_window() {
|
||||||
_background_image.dump_image();
|
if (_composite_image != NULL) {
|
||||||
_button_ready_image.dump_image();
|
XDestroyImage(_composite_image);
|
||||||
_button_rollover_image.dump_image();
|
_composite_image = NULL;
|
||||||
_button_click_image.dump_image();
|
}
|
||||||
|
|
||||||
if (_bar_context != None) {
|
if (_bar_context != None) {
|
||||||
if (_bar_context != _graphics_context) {
|
if (_bar_context != _graphics_context) {
|
||||||
@ -918,97 +874,288 @@ close_window() {
|
|||||||
// If the image is changed, sets needs_redraw to true.
|
// If the image is changed, sets needs_redraw to true.
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
void P3DX11SplashWindow::
|
void P3DX11SplashWindow::
|
||||||
update_image(X11ImageData &image, bool &needs_redraw) {
|
update_image(X11ImageData &image) {
|
||||||
if (!image._filename_changed) {
|
if (!image._filename_changed) {
|
||||||
// No changes.
|
// No changes.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
image._filename_changed = false;
|
image._filename_changed = false;
|
||||||
needs_redraw = true;
|
|
||||||
|
|
||||||
// Clear the old image.
|
// We'll need to rebuild the composite image.
|
||||||
image.dump_image();
|
_needs_new_composite = true;
|
||||||
|
|
||||||
// Go read the image.
|
// Go read the image.
|
||||||
string data;
|
string data;
|
||||||
if (!read_image_data(image, data, image._filename)) {
|
if (!read_image_data(image, image._data, image._filename)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: P3DX11SplashWindow::compose_image
|
||||||
|
// Access: Private
|
||||||
|
// Description: Constructs the XImage to display onscreen. It's a
|
||||||
|
// composition of the background image and/or one of the
|
||||||
|
// button images, scaled to fit the window.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
void P3DX11SplashWindow::
|
||||||
|
compose_image() {
|
||||||
|
if (_composite_image != NULL) {
|
||||||
|
XDestroyImage(_composite_image);
|
||||||
|
_composite_image = NULL;
|
||||||
|
}
|
||||||
|
_needs_new_composite = false;
|
||||||
|
|
||||||
|
vector<unsigned char> image1;
|
||||||
|
int image1_width = 0, image1_height = 0;
|
||||||
|
scale_image(image1, image1_width, image1_height, _background_image);
|
||||||
|
|
||||||
|
vector<unsigned char> image2;
|
||||||
|
int image2_width = 0, image2_height = 0;
|
||||||
|
|
||||||
|
switch (_bstate) {
|
||||||
|
case BS_hidden:
|
||||||
|
break;
|
||||||
|
case BS_ready:
|
||||||
|
scale_image(image2, image2_width, image2_height, _button_ready_image);
|
||||||
|
break;
|
||||||
|
case BS_rollover:
|
||||||
|
if (!scale_image(image2, image2_width, image2_height, _button_rollover_image)) {
|
||||||
|
scale_image(image2, image2_width, image2_height, _button_ready_image);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case BS_click:
|
||||||
|
if (!scale_image(image2, image2_width, image2_height, _button_click_image)) {
|
||||||
|
scale_image(image2, image2_width, image2_height, _button_ready_image);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (image1.empty() && image2.empty()) {
|
||||||
|
// We have no image. Never mind.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (image2.empty()) {
|
||||||
|
// We have no button image; image1 will serve as the result.
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// We do have a button image. Compose the button image on top of
|
||||||
|
// the background image (or on top of a white image if we have no
|
||||||
|
// background).
|
||||||
|
|
||||||
|
// We compose them here on the client, because X11 doesn't
|
||||||
|
// natively provide an alpha-blending mechanism (at least, not
|
||||||
|
// without the XRender extension).
|
||||||
|
vector<unsigned char> image0;
|
||||||
|
int image0_width, image0_height;
|
||||||
|
compose_two_images(image0, image0_width, image0_height,
|
||||||
|
image1, image1_width, image1_height,
|
||||||
|
image2, image2_width, image2_height);
|
||||||
|
image1.swap(image0);
|
||||||
|
image1_width = image0_width;
|
||||||
|
image1_height = image0_height;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now construct an XImage from the result.
|
||||||
Visual *dvisual = DefaultVisual(_display, _screen);
|
Visual *dvisual = DefaultVisual(_display, _screen);
|
||||||
double r_ratio = dvisual->red_mask / 255.0;
|
double r_ratio = dvisual->red_mask / 255.0;
|
||||||
double g_ratio = dvisual->green_mask / 255.0;
|
double g_ratio = dvisual->green_mask / 255.0;
|
||||||
double b_ratio = dvisual->blue_mask / 255.0;
|
double b_ratio = dvisual->blue_mask / 255.0;
|
||||||
uint32_t *new_data = (uint32_t*)malloc(4 * image._width * image._height);
|
int data_length = 4 * image1_width * image1_height;
|
||||||
|
assert(data_length == image1.size());
|
||||||
|
uint32_t *new_data = (uint32_t*)malloc(data_length);
|
||||||
|
|
||||||
if (image._num_channels == 4) {
|
|
||||||
int j = 0;
|
int j = 0;
|
||||||
for (int i = 0; i < 4 * image._width * image._height; i += 4) {
|
for (int i = 0; i < data_length; i += 4) {
|
||||||
unsigned int r, g, b;
|
unsigned int r, g, b;
|
||||||
r = (unsigned int)(data[i+0] * r_ratio);
|
r = (unsigned int)(image1[i+0] * r_ratio);
|
||||||
g = (unsigned int)(data[i+1] * g_ratio);
|
g = (unsigned int)(image1[i+1] * g_ratio);
|
||||||
b = (unsigned int)(data[i+2] * b_ratio);
|
b = (unsigned int)(image1[i+2] * b_ratio);
|
||||||
new_data[j++] = (r & dvisual->red_mask) |
|
new_data[j++] = ((r & dvisual->red_mask) |
|
||||||
(g & dvisual->green_mask) |
|
(g & dvisual->green_mask) |
|
||||||
(b & dvisual->blue_mask);
|
(b & dvisual->blue_mask));
|
||||||
}
|
|
||||||
} else if (image._num_channels == 3) {
|
|
||||||
int j = 0;
|
|
||||||
for (int i = 0; i < 3 * image._width * image._height; i += 3) {
|
|
||||||
unsigned int r, g, b;
|
|
||||||
r = (unsigned int)(data[i+0] * r_ratio);
|
|
||||||
g = (unsigned int)(data[i+1] * g_ratio);
|
|
||||||
b = (unsigned int)(data[i+2] * b_ratio);
|
|
||||||
new_data[j++] = (r & dvisual->red_mask) |
|
|
||||||
(g & dvisual->green_mask) |
|
|
||||||
(b & dvisual->blue_mask);
|
|
||||||
}
|
|
||||||
} else if (image._num_channels == 1) {
|
|
||||||
// A grayscale image. Replicate out the channels.
|
|
||||||
for (int i = 0; i < image._width * image._height; ++i) {
|
|
||||||
unsigned int r, g, b;
|
|
||||||
r = (unsigned int)(data[i] * r_ratio);
|
|
||||||
g = (unsigned int)(data[i] * g_ratio);
|
|
||||||
b = (unsigned int)(data[i] * b_ratio);
|
|
||||||
new_data[i] = (r & dvisual->red_mask) |
|
|
||||||
(g & dvisual->green_mask) |
|
|
||||||
(b & dvisual->blue_mask);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now load the image.
|
// Now load the image.
|
||||||
image._image = XCreateImage(_display, CopyFromParent, DefaultDepth(_display, _screen),
|
_composite_image = XCreateImage(_display, CopyFromParent, DefaultDepth(_display, _screen),
|
||||||
ZPixmap, 0, (char *)new_data, image._width, image._height, 32, 0);
|
ZPixmap, 0, (char *)new_data, image1_width, image1_height, 32, 0);
|
||||||
|
_composite_width = image1_width;
|
||||||
|
_composite_height = image1_height;
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Function: P3DX11SplashWindow::X11ImageData::dump_image
|
// Function: P3DX11SplashWindow::scale_image
|
||||||
// Access: Public
|
// Access: Private
|
||||||
// Description: Frees the previous image data.
|
// Description: Scales the image into the window size, and expands it
|
||||||
|
// to four channels. Returns true if the image is
|
||||||
|
// valid, false if it is empty.
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
void P3DX11SplashWindow::X11ImageData::
|
bool P3DX11SplashWindow::
|
||||||
dump_image() {
|
scale_image(vector<unsigned char> &image0, int &image0_width, int &image0_height,
|
||||||
if (_image != NULL) {
|
X11ImageData &image) {
|
||||||
XDestroyImage(_image);
|
if (image._data.empty()) {
|
||||||
_image = NULL;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const unsigned char *orig_data = (const unsigned char *)image._data.data();
|
||||||
|
int row_stride = image._width * image._num_channels;
|
||||||
|
int data_length = image._height * row_stride;
|
||||||
|
assert(data_length == image._data.size());
|
||||||
|
|
||||||
|
if (image._width <= _win_width && image._height <= _win_height) {
|
||||||
|
// It fits within the window - just keep it.
|
||||||
|
image0_width = image._width;
|
||||||
|
image0_height = image._height;
|
||||||
|
int new_row_stride = image0_width * 4;
|
||||||
|
int new_data_length = image0_height * new_row_stride;
|
||||||
|
|
||||||
|
image0.clear();
|
||||||
|
image0.reserve(new_data_length);
|
||||||
|
image0.insert(image0.begin(), new_data_length, 0);
|
||||||
|
unsigned char *new_data = &image0[0];
|
||||||
|
|
||||||
|
if (image._num_channels == 4) {
|
||||||
|
// Easy case. Already four channels.
|
||||||
|
assert(data_length == new_data_length && row_stride == new_row_stride);
|
||||||
|
memcpy(new_data, orig_data, data_length);
|
||||||
|
|
||||||
|
} else if (image._num_channels == 3) {
|
||||||
|
// Expand three channels to four.
|
||||||
|
for (int yi = 0; yi < image._height; ++yi) {
|
||||||
|
const unsigned char *sp = orig_data + yi * row_stride;
|
||||||
|
unsigned char *dp = new_data + yi * new_row_stride;
|
||||||
|
for (int xi = 0; xi < image._width; ++xi) {
|
||||||
|
dp[0] = sp[0];
|
||||||
|
dp[1] = sp[1];
|
||||||
|
dp[2] = sp[2];
|
||||||
|
dp[3] = 0xff;
|
||||||
|
sp += 3;
|
||||||
|
dp += 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (image._num_channels == 1) {
|
||||||
|
// A grayscale image. Replicate out the channels.
|
||||||
|
for (int yi = 0; yi < image._height; ++yi) {
|
||||||
|
const unsigned char *sp = orig_data + yi * row_stride;
|
||||||
|
unsigned char *dp = new_data + yi * new_row_stride;
|
||||||
|
for (int xi = 0; xi < image._width; ++xi) {
|
||||||
|
dp[0] = sp[0];
|
||||||
|
dp[1] = sp[0];
|
||||||
|
dp[2] = sp[0];
|
||||||
|
dp[3] = 0xff;
|
||||||
|
sp += 1;
|
||||||
|
dp += 4;
|
||||||
}
|
}
|
||||||
if (_resized_image != NULL) {
|
|
||||||
XDestroyImage(_resized_image);
|
|
||||||
_resized_image = NULL;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// Yuck, the bad case - we need to scale it down.
|
||||||
|
double scale = min((double)_win_width / (double)image._width,
|
||||||
|
(double)_win_height / (double)image._height);
|
||||||
|
image0_width = (int)(image._width * scale);
|
||||||
|
image0_height = (int)(image._height * scale);
|
||||||
|
int new_row_stride = image0_width * 4;
|
||||||
|
int new_data_length = image0_height * new_row_stride;
|
||||||
|
|
||||||
|
image0.clear();
|
||||||
|
image0.reserve(new_data_length);
|
||||||
|
image0.insert(image0.begin(), new_data_length, 0);
|
||||||
|
unsigned char *new_data = &image0[0];
|
||||||
|
|
||||||
|
for (int yi = 0; yi < image0_height; ++yi) {
|
||||||
|
int orig_yi = (yi * image._height) / image0_height;
|
||||||
|
const unsigned char *sp = orig_data + orig_yi * row_stride;
|
||||||
|
unsigned char *dp = new_data + yi * new_row_stride;
|
||||||
|
for (int xi = 0; xi < image0_width; ++xi) {
|
||||||
|
int orig_xi = (xi * image._width) / image0_width;
|
||||||
|
const unsigned char *spx = sp + orig_xi * image._num_channels;
|
||||||
|
if (image._num_channels == 4) {
|
||||||
|
dp[0] = spx[0];
|
||||||
|
dp[1] = spx[1];
|
||||||
|
dp[2] = spx[2];
|
||||||
|
dp[3] = spx[3];
|
||||||
|
} else if (image._num_channels == 3) {
|
||||||
|
dp[0] = spx[0];
|
||||||
|
dp[1] = spx[1];
|
||||||
|
dp[2] = spx[2];
|
||||||
|
dp[3] = 0xff;
|
||||||
|
} else if (image._num_channels == 1) {
|
||||||
|
dp[0] = spx[0];
|
||||||
|
dp[1] = spx[0];
|
||||||
|
dp[2] = spx[0];
|
||||||
|
dp[3] = 0xff;
|
||||||
|
}
|
||||||
|
dp += 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Function: P3DX11SplashWindow::X11ImageData::dump_resized_image
|
// Function: P3DX11SplashWindow::compose_two_images
|
||||||
// Access: Public
|
// Access: Private
|
||||||
// Description: Frees the previous resized image data only, retaining
|
// Description: Constructs into image0 the alpha-composite of image1
|
||||||
// the original image data.
|
// beneath image2.
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
void P3DX11SplashWindow::X11ImageData::
|
void P3DX11SplashWindow::
|
||||||
dump_resized_image() {
|
compose_two_images(vector<unsigned char> &image0, int &image0_width, int &image0_height,
|
||||||
if (_resized_image != NULL) {
|
const vector<unsigned char> &image1, int image1_width, int image1_height,
|
||||||
XDestroyImage(_resized_image);
|
const vector<unsigned char> &image2, int image2_width, int image2_height) {
|
||||||
_resized_image = NULL;
|
// First, the resulting image size is the larger of the two.
|
||||||
|
image0_width = max(image1_width, image2_width);
|
||||||
|
image0_height = max(image1_height, image2_height);
|
||||||
|
|
||||||
|
int new_row_stride = image0_width * 4;
|
||||||
|
int new_data_length = image0_height * new_row_stride;
|
||||||
|
|
||||||
|
// Now copy in the first image. If the first image exactly fills
|
||||||
|
// the output image, this is easy.
|
||||||
|
if (image1_width == image0_width && image1_height == image0_height) {
|
||||||
|
image0 = image1;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// If the first image doesn't fill it, it's only a little bit more
|
||||||
|
// work. Start by finding the top-left pixel.
|
||||||
|
int xo = (image0_width - image1_width) / 2;
|
||||||
|
int yo = (image0_height - image1_height) / 2;
|
||||||
|
|
||||||
|
// Initialize the image to all white pixels.
|
||||||
|
image0.clear();
|
||||||
|
image0.reserve(new_data_length);
|
||||||
|
image0.insert(image0.begin(), new_data_length, 0xff);
|
||||||
|
|
||||||
|
int image0_row_stride = image0_width * 4;
|
||||||
|
int image1_row_stride = image1_width * 4;
|
||||||
|
for (int yi = 0; yi < image1_height; ++yi) {
|
||||||
|
const unsigned char *sp = &image1[0] + yi * image1_row_stride;
|
||||||
|
unsigned char *dp = &image0[0] + (yi + yo) * image0_row_stride;
|
||||||
|
memcpy(dp + xo * 4, sp, image1_row_stride);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now blend in the second image. Find the top-left pixel.
|
||||||
|
int xo = (image0_width - image2_width) / 2;
|
||||||
|
int yo = (image0_height - image2_height) / 2;
|
||||||
|
|
||||||
|
int image0_row_stride = image0_width * 4;
|
||||||
|
int image2_row_stride = image2_width * 4;
|
||||||
|
|
||||||
|
for (int yi = 0; yi < image2_height; ++yi) {
|
||||||
|
const unsigned char *sp = &image2[0] + yi * image2_row_stride;
|
||||||
|
unsigned char *dp = &image0[0] + (yi + yo) * image0_row_stride;
|
||||||
|
dp += xo * 4;
|
||||||
|
for (int xi = 0; xi < image2_width; ++xi) {
|
||||||
|
double alpha = (double)sp[3] / 255.0;
|
||||||
|
dp[0] = (unsigned char)(dp[0] + alpha * (sp[0] - dp[0]));
|
||||||
|
dp[1] = (unsigned char)(dp[1] + alpha * (sp[1] - dp[1]));
|
||||||
|
dp[2] = (unsigned char)(dp[2] + alpha * (sp[2] - dp[2]));
|
||||||
|
dp += 4;
|
||||||
|
sp += 4;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,6 +25,8 @@
|
|||||||
#include <X11/Xlib.h>
|
#include <X11/Xlib.h>
|
||||||
#include <X11/Xutil.h>
|
#include <X11/Xutil.h>
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Class : P3DX11SplashWindow
|
// Class : P3DX11SplashWindow
|
||||||
// Description : This is the Windows implementation of the
|
// Description : This is the Windows implementation of the
|
||||||
@ -45,6 +47,7 @@ public:
|
|||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void button_click_detected();
|
virtual void button_click_detected();
|
||||||
|
virtual void set_bstate(ButtonState bstate);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void start_subprocess();
|
void start_subprocess();
|
||||||
@ -79,27 +82,29 @@ private:
|
|||||||
void receive_command();
|
void receive_command();
|
||||||
|
|
||||||
void redraw();
|
void redraw();
|
||||||
bool paint_image(X11ImageData &image);
|
|
||||||
void make_window();
|
void make_window();
|
||||||
void setup_gc();
|
void setup_gc();
|
||||||
void update_image(X11ImageData &image, bool &needs_redraw);
|
|
||||||
void close_window();
|
void close_window();
|
||||||
|
|
||||||
|
void update_image(X11ImageData &image);
|
||||||
|
void compose_image();
|
||||||
|
bool scale_image(vector<unsigned char> &image0, int &image0_width, int &image0_height,
|
||||||
|
X11ImageData &image);
|
||||||
|
|
||||||
|
void compose_two_images(vector<unsigned char> &image0, int &image0_width, int &image0_height,
|
||||||
|
const vector<unsigned char> &image1, int image1_width, int image1_height,
|
||||||
|
const vector<unsigned char> &image2, int image2_width, int image2_height);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Data members that are stored in the subprocess.
|
// Data members that are stored in the subprocess.
|
||||||
class X11ImageData : public ImageData {
|
class X11ImageData : public ImageData {
|
||||||
public:
|
public:
|
||||||
inline X11ImageData();
|
inline X11ImageData();
|
||||||
inline ~X11ImageData();
|
inline ~X11ImageData();
|
||||||
void dump_image();
|
|
||||||
void dump_resized_image();
|
|
||||||
|
|
||||||
string _filename;
|
string _filename;
|
||||||
bool _filename_changed;
|
bool _filename_changed;
|
||||||
XImage *_image;
|
string _data;
|
||||||
|
|
||||||
XImage *_resized_image;
|
|
||||||
int _resized_width, _resized_height;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
X11ImageData _background_image;
|
X11ImageData _background_image;
|
||||||
@ -107,6 +112,10 @@ private:
|
|||||||
X11ImageData _button_rollover_image;
|
X11ImageData _button_rollover_image;
|
||||||
X11ImageData _button_click_image;
|
X11ImageData _button_click_image;
|
||||||
|
|
||||||
|
XImage *_composite_image;
|
||||||
|
int _composite_width, _composite_height;
|
||||||
|
bool _needs_new_composite;
|
||||||
|
|
||||||
bool _subprocess_continue;
|
bool _subprocess_continue;
|
||||||
|
|
||||||
bool _own_display;
|
bool _own_display;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user