mirror of
https://github.com/panda3d/panda3d.git
synced 2025-09-30 08:44:19 -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) {
|
||||
_bstate = bstate;
|
||||
// If we've changed button states, we need to refresh the window.
|
||||
refresh();
|
||||
}
|
||||
set_bstate(bstate);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
@ -484,6 +480,21 @@ button_click_detected() {
|
||||
_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
|
||||
// Access: Protected, Virtual
|
||||
|
@ -80,7 +80,16 @@ protected:
|
||||
void set_button_range(const ImageData &image);
|
||||
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 set_bstate(ButtonState bstate);
|
||||
virtual void refresh();
|
||||
|
||||
protected:
|
||||
@ -99,14 +108,6 @@ protected:
|
||||
int _mouse_x, _mouse_y;
|
||||
bool _mouse_down;
|
||||
bool _button_depressed;
|
||||
|
||||
// The current visual state of the button.
|
||||
enum ButtonState {
|
||||
BS_hidden,
|
||||
BS_ready,
|
||||
BS_rollover,
|
||||
BS_click,
|
||||
};
|
||||
ButtonState _bstate;
|
||||
};
|
||||
|
||||
|
@ -21,10 +21,6 @@
|
||||
inline P3DX11SplashWindow::X11ImageData::
|
||||
X11ImageData() {
|
||||
_filename_changed = false;
|
||||
_image = NULL;
|
||||
_resized_image = NULL;
|
||||
_resized_width = 0;
|
||||
_resized_height = 0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
@ -34,6 +30,5 @@ X11ImageData() {
|
||||
////////////////////////////////////////////////////////////////////
|
||||
inline P3DX11SplashWindow::X11ImageData::
|
||||
~X11ImageData() {
|
||||
dump_image();
|
||||
}
|
||||
|
||||
|
@ -44,6 +44,8 @@ P3DX11SplashWindow(P3DInstance *inst) :
|
||||
INIT_THREAD(_read_thread);
|
||||
|
||||
// Init for subprocess
|
||||
_composite_image = NULL;
|
||||
_needs_new_composite = false;
|
||||
_display = None;
|
||||
_window = None;
|
||||
_screen = 0;
|
||||
@ -182,14 +184,28 @@ void P3DX11SplashWindow::
|
||||
button_click_detected() {
|
||||
// This method is called in the child process, and must relay
|
||||
// the information to the parent process.
|
||||
cerr << "click detected\n";
|
||||
|
||||
TiXmlDocument doc;
|
||||
TiXmlElement *xcommand = new TiXmlElement("click");
|
||||
doc.LinkEndChild(xcommand);
|
||||
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
|
||||
// Access: Private
|
||||
@ -473,13 +489,12 @@ subprocess_run() {
|
||||
event.xconfigure.height != _win_height) {
|
||||
_win_width = event.xconfigure.width;
|
||||
_win_height = event.xconfigure.height;
|
||||
|
||||
set_button_range(_button_ready_image);
|
||||
|
||||
// If the window changes size, we need to recompute all of the
|
||||
// resized images.
|
||||
_background_image.dump_resized_image();
|
||||
_button_ready_image.dump_resized_image();
|
||||
_button_rollover_image.dump_resized_image();
|
||||
_button_click_image.dump_resized_image();
|
||||
// If the window changes size, we need to recompute the
|
||||
// composed image.
|
||||
_needs_new_composite = true;
|
||||
}
|
||||
needs_redraw = true;
|
||||
break;
|
||||
@ -498,10 +513,15 @@ subprocess_run() {
|
||||
}
|
||||
}
|
||||
|
||||
update_image(_background_image, needs_redraw);
|
||||
update_image(_button_ready_image, needs_redraw);
|
||||
update_image(_button_rollover_image, needs_redraw);
|
||||
update_image(_button_click_image, needs_redraw);
|
||||
update_image(_background_image);
|
||||
update_image(_button_ready_image);
|
||||
update_image(_button_rollover_image);
|
||||
update_image(_button_click_image);
|
||||
|
||||
if (_needs_new_composite) {
|
||||
needs_redraw = true;
|
||||
compose_image();
|
||||
}
|
||||
|
||||
if (_bstate != prev_bstate) {
|
||||
needs_redraw = true;
|
||||
@ -689,78 +709,14 @@ receive_command() {
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void P3DX11SplashWindow::
|
||||
redraw() {
|
||||
XClearWindow(_display, _window);
|
||||
if (_composite_image == NULL) {
|
||||
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 {
|
||||
// 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);
|
||||
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);
|
||||
XPutImage(_display, _window, _graphics_context, _composite_image, 0, 0,
|
||||
(_win_width - _composite_width) / 2, (_win_height - _composite_height) / 2,
|
||||
_composite_width, _composite_height);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
@ -876,10 +832,10 @@ setup_gc() {
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void P3DX11SplashWindow::
|
||||
close_window() {
|
||||
_background_image.dump_image();
|
||||
_button_ready_image.dump_image();
|
||||
_button_rollover_image.dump_image();
|
||||
_button_click_image.dump_image();
|
||||
if (_composite_image != NULL) {
|
||||
XDestroyImage(_composite_image);
|
||||
_composite_image = NULL;
|
||||
}
|
||||
|
||||
if (_bar_context != None) {
|
||||
if (_bar_context != _graphics_context) {
|
||||
@ -918,97 +874,288 @@ close_window() {
|
||||
// If the image is changed, sets needs_redraw to true.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void P3DX11SplashWindow::
|
||||
update_image(X11ImageData &image, bool &needs_redraw) {
|
||||
update_image(X11ImageData &image) {
|
||||
if (!image._filename_changed) {
|
||||
// No changes.
|
||||
return;
|
||||
}
|
||||
image._filename_changed = false;
|
||||
needs_redraw = true;
|
||||
|
||||
// Clear the old image.
|
||||
image.dump_image();
|
||||
// We'll need to rebuild the composite image.
|
||||
_needs_new_composite = true;
|
||||
|
||||
// Go read the image.
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
double r_ratio = dvisual->red_mask / 255.0;
|
||||
double g_ratio = dvisual->green_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;
|
||||
for (int i = 0; i < 4 * image._width * image._height; i += 4) {
|
||||
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 == 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);
|
||||
}
|
||||
int j = 0;
|
||||
for (int i = 0; i < data_length; i += 4) {
|
||||
unsigned int r, g, b;
|
||||
r = (unsigned int)(image1[i+0] * r_ratio);
|
||||
g = (unsigned int)(image1[i+1] * g_ratio);
|
||||
b = (unsigned int)(image1[i+2] * b_ratio);
|
||||
new_data[j++] = ((r & dvisual->red_mask) |
|
||||
(g & dvisual->green_mask) |
|
||||
(b & dvisual->blue_mask));
|
||||
}
|
||||
|
||||
// Now load the image.
|
||||
image._image = XCreateImage(_display, CopyFromParent, DefaultDepth(_display, _screen),
|
||||
ZPixmap, 0, (char *)new_data, image._width, image._height, 32, 0);
|
||||
_composite_image = XCreateImage(_display, CopyFromParent, DefaultDepth(_display, _screen),
|
||||
ZPixmap, 0, (char *)new_data, image1_width, image1_height, 32, 0);
|
||||
_composite_width = image1_width;
|
||||
_composite_height = image1_height;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DX11SplashWindow::X11ImageData::dump_image
|
||||
// Access: Public
|
||||
// Description: Frees the previous image data.
|
||||
// Function: P3DX11SplashWindow::scale_image
|
||||
// Access: Private
|
||||
// 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::
|
||||
dump_image() {
|
||||
if (_image != NULL) {
|
||||
XDestroyImage(_image);
|
||||
_image = NULL;
|
||||
bool P3DX11SplashWindow::
|
||||
scale_image(vector<unsigned char> &image0, int &image0_width, int &image0_height,
|
||||
X11ImageData &image) {
|
||||
if (image._data.empty()) {
|
||||
return false;
|
||||
}
|
||||
if (_resized_image != NULL) {
|
||||
XDestroyImage(_resized_image);
|
||||
_resized_image = NULL;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} 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
|
||||
// Access: Public
|
||||
// Description: Frees the previous resized image data only, retaining
|
||||
// the original image data.
|
||||
// Function: P3DX11SplashWindow::compose_two_images
|
||||
// Access: Private
|
||||
// Description: Constructs into image0 the alpha-composite of image1
|
||||
// beneath image2.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void P3DX11SplashWindow::X11ImageData::
|
||||
dump_resized_image() {
|
||||
if (_resized_image != NULL) {
|
||||
XDestroyImage(_resized_image);
|
||||
_resized_image = NULL;
|
||||
void P3DX11SplashWindow::
|
||||
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) {
|
||||
// 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/Xutil.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Class : P3DX11SplashWindow
|
||||
// Description : This is the Windows implementation of the
|
||||
@ -45,6 +47,7 @@ public:
|
||||
|
||||
protected:
|
||||
virtual void button_click_detected();
|
||||
virtual void set_bstate(ButtonState bstate);
|
||||
|
||||
private:
|
||||
void start_subprocess();
|
||||
@ -79,27 +82,29 @@ private:
|
||||
void receive_command();
|
||||
|
||||
void redraw();
|
||||
bool paint_image(X11ImageData &image);
|
||||
void make_window();
|
||||
void setup_gc();
|
||||
void update_image(X11ImageData &image, bool &needs_redraw);
|
||||
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:
|
||||
// Data members that are stored in the subprocess.
|
||||
class X11ImageData : public ImageData {
|
||||
public:
|
||||
inline X11ImageData();
|
||||
inline ~X11ImageData();
|
||||
void dump_image();
|
||||
void dump_resized_image();
|
||||
|
||||
string _filename;
|
||||
bool _filename_changed;
|
||||
XImage *_image;
|
||||
|
||||
XImage *_resized_image;
|
||||
int _resized_width, _resized_height;
|
||||
string _data;
|
||||
};
|
||||
|
||||
X11ImageData _background_image;
|
||||
@ -107,6 +112,10 @@ private:
|
||||
X11ImageData _button_rollover_image;
|
||||
X11ImageData _button_click_image;
|
||||
|
||||
XImage *_composite_image;
|
||||
int _composite_width, _composite_height;
|
||||
bool _needs_new_composite;
|
||||
|
||||
bool _subprocess_continue;
|
||||
|
||||
bool _own_display;
|
||||
|
Loading…
x
Reference in New Issue
Block a user