//---------------------------------------------------------------------------- // Anti-Grain Geometry - Version 2.4 // Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) // // Permission to copy, use, modify, sell and distribute this software // is granted provided this copyright notice appears in all copies. // This software is provided "as is" without express or implied // warranty, and with no claim as to its suitability for any purpose. // //---------------------------------------------------------------------------- // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com // http://www.antigrain.com //---------------------------------------------------------------------------- // // class platform_support. X11 version. // //---------------------------------------------------------------------------- #include #include #include #include #include #include #include #include #include #include "agg_basics.h" #include "agg_pixfmt_gray.h" #include "agg_pixfmt_rgb.h" #include "agg_pixfmt_rgba.h" #include "util/agg_color_conv_rgb8.h" #include "platform/agg_platform_support.h" namespace agg { //------------------------------------------------------------------------ class platform_specific { public: platform_specific(pix_format_e format, bool flip_y); ~platform_specific(); void caption(const char* capt); void put_image(const rendering_buffer* src); pix_format_e m_format; pix_format_e m_sys_format; int m_byte_order; bool m_flip_y; unsigned m_bpp; unsigned m_sys_bpp; Display* m_display; int m_screen; int m_depth; Visual* m_visual; Window m_window; GC m_gc; XImage* m_ximg_window; XSetWindowAttributes m_window_attributes; Atom m_close_atom; unsigned char* m_buf_window; unsigned char* m_buf_img[platform_support::max_images]; unsigned m_keymap[256]; bool m_update_flag; bool m_resize_flag; bool m_initialized; //bool m_wait_mode; std::clock_t m_sw_start; }; //------------------------------------------------------------------------ platform_specific::platform_specific(pix_format_e format, bool flip_y) : m_format(format), m_sys_format(pix_format_undefined), m_byte_order(LSBFirst), m_flip_y(flip_y), m_bpp(0), m_sys_bpp(0), m_display(0), m_screen(0), m_depth(0), m_visual(0), m_window(0), m_gc(0), m_ximg_window(0), m_close_atom(0), m_buf_window(0), m_update_flag(true), m_resize_flag(true), m_initialized(false) //m_wait_mode(true) { std::memset(m_buf_img, 0, sizeof(m_buf_img)); unsigned i; for(i = 0; i < 256; i++) { m_keymap[i] = i; } m_keymap[XK_Pause&0xFF] = key_pause; m_keymap[XK_Clear&0xFF] = key_clear; m_keymap[XK_KP_0&0xFF] = key_kp0; m_keymap[XK_KP_1&0xFF] = key_kp1; m_keymap[XK_KP_2&0xFF] = key_kp2; m_keymap[XK_KP_3&0xFF] = key_kp3; m_keymap[XK_KP_4&0xFF] = key_kp4; m_keymap[XK_KP_5&0xFF] = key_kp5; m_keymap[XK_KP_6&0xFF] = key_kp6; m_keymap[XK_KP_7&0xFF] = key_kp7; m_keymap[XK_KP_8&0xFF] = key_kp8; m_keymap[XK_KP_9&0xFF] = key_kp9; m_keymap[XK_KP_Insert&0xFF] = key_kp0; m_keymap[XK_KP_End&0xFF] = key_kp1; m_keymap[XK_KP_Down&0xFF] = key_kp2; m_keymap[XK_KP_Page_Down&0xFF] = key_kp3; m_keymap[XK_KP_Left&0xFF] = key_kp4; m_keymap[XK_KP_Begin&0xFF] = key_kp5; m_keymap[XK_KP_Right&0xFF] = key_kp6; m_keymap[XK_KP_Home&0xFF] = key_kp7; m_keymap[XK_KP_Up&0xFF] = key_kp8; m_keymap[XK_KP_Page_Up&0xFF] = key_kp9; m_keymap[XK_KP_Delete&0xFF] = key_kp_period; m_keymap[XK_KP_Decimal&0xFF] = key_kp_period; m_keymap[XK_KP_Divide&0xFF] = key_kp_divide; m_keymap[XK_KP_Multiply&0xFF] = key_kp_multiply; m_keymap[XK_KP_Subtract&0xFF] = key_kp_minus; m_keymap[XK_KP_Add&0xFF] = key_kp_plus; m_keymap[XK_KP_Enter&0xFF] = key_kp_enter; m_keymap[XK_KP_Equal&0xFF] = key_kp_equals; m_keymap[XK_Up&0xFF] = key_up; m_keymap[XK_Down&0xFF] = key_down; m_keymap[XK_Right&0xFF] = key_right; m_keymap[XK_Left&0xFF] = key_left; m_keymap[XK_Insert&0xFF] = key_insert; m_keymap[XK_Home&0xFF] = key_delete; m_keymap[XK_End&0xFF] = key_end; m_keymap[XK_Page_Up&0xFF] = key_page_up; m_keymap[XK_Page_Down&0xFF] = key_page_down; m_keymap[XK_F1&0xFF] = key_f1; m_keymap[XK_F2&0xFF] = key_f2; m_keymap[XK_F3&0xFF] = key_f3; m_keymap[XK_F4&0xFF] = key_f4; m_keymap[XK_F5&0xFF] = key_f5; m_keymap[XK_F6&0xFF] = key_f6; m_keymap[XK_F7&0xFF] = key_f7; m_keymap[XK_F8&0xFF] = key_f8; m_keymap[XK_F9&0xFF] = key_f9; m_keymap[XK_F10&0xFF] = key_f10; m_keymap[XK_F11&0xFF] = key_f11; m_keymap[XK_F12&0xFF] = key_f12; m_keymap[XK_F13&0xFF] = key_f13; m_keymap[XK_F14&0xFF] = key_f14; m_keymap[XK_F15&0xFF] = key_f15; m_keymap[XK_Num_Lock&0xFF] = key_numlock; m_keymap[XK_Caps_Lock&0xFF] = key_capslock; m_keymap[XK_Scroll_Lock&0xFF] = key_scrollock; switch(m_format) { default: break; case pix_format_gray8: case pix_format_sgray8: m_bpp = 8; break; case pix_format_gray16: m_bpp = 16; break; case pix_format_gray32: m_bpp = 32; break; case pix_format_rgb565: case pix_format_rgb555: m_bpp = 16; break; case pix_format_rgb24: case pix_format_bgr24: case pix_format_srgb24: case pix_format_sbgr24: m_bpp = 24; break; case pix_format_bgra32: case pix_format_abgr32: case pix_format_argb32: case pix_format_rgba32: case pix_format_sbgra32: case pix_format_sabgr32: case pix_format_sargb32: case pix_format_srgba32: m_bpp = 32; break; case pix_format_rgb48: case pix_format_bgr48: m_bpp = 48; break; case pix_format_bgra64: case pix_format_abgr64: case pix_format_argb64: case pix_format_rgba64: m_bpp = 64; break; case pix_format_rgb96: case pix_format_bgr96: m_bpp = 96; break; case pix_format_bgra128: case pix_format_abgr128: case pix_format_argb128: case pix_format_rgba128: m_bpp = 128; break; } m_sw_start = std::clock(); } //------------------------------------------------------------------------ platform_specific::~platform_specific() { } //------------------------------------------------------------------------ void platform_specific::caption(const char* capt) { XTextProperty tp; tp.value = (unsigned char *)capt; tp.encoding = XA_WM_NAME; tp.format = 8; tp.nitems = std::strlen(capt); XSetWMName(m_display, m_window, &tp); XStoreName(m_display, m_window, capt); XSetIconName(m_display, m_window, capt); XSetWMIconName(m_display, m_window, &tp); } //------------------------------------------------------------------------ void platform_specific::put_image(const rendering_buffer* src) { if(m_ximg_window == 0) return; m_ximg_window->data = (char*)m_buf_window; if(m_format == m_sys_format) { XPutImage(m_display, m_window, m_gc, m_ximg_window, 0, 0, 0, 0, src->width(), src->height()); } else { int row_len = src->width() * m_sys_bpp / 8; unsigned char* buf_tmp = new unsigned char[row_len * src->height()]; rendering_buffer rbuf_tmp; rbuf_tmp.attach(buf_tmp, src->width(), src->height(), m_flip_y ? -row_len : row_len); switch(m_sys_format) { default: break; case pix_format_rgb555: switch(m_format) { default: break; case pix_format_rgb555: color_conv(&rbuf_tmp, src, color_conv_rgb555_to_rgb555()); break; case pix_format_rgb565: color_conv(&rbuf_tmp, src, color_conv_rgb565_to_rgb555()); break; case pix_format_rgb24: color_conv(&rbuf_tmp, src, color_conv_rgb24_to_rgb555()); break; case pix_format_bgr24: color_conv(&rbuf_tmp, src, color_conv_bgr24_to_rgb555()); break; case pix_format_rgba32: color_conv(&rbuf_tmp, src, color_conv_rgba32_to_rgb555()); break; case pix_format_argb32: color_conv(&rbuf_tmp, src, color_conv_argb32_to_rgb555()); break; case pix_format_bgra32: color_conv(&rbuf_tmp, src, color_conv_bgra32_to_rgb555()); break; case pix_format_abgr32: color_conv(&rbuf_tmp, src, color_conv_abgr32_to_rgb555()); break; } break; case pix_format_rgb565: switch(m_format) { default: break; case pix_format_rgb555: color_conv(&rbuf_tmp, src, color_conv_rgb555_to_rgb565()); break; case pix_format_rgb565: color_conv(&rbuf_tmp, src, color_conv_rgb565_to_rgb565()); break; case pix_format_rgb24: color_conv(&rbuf_tmp, src, color_conv_rgb24_to_rgb565()); break; case pix_format_bgr24: color_conv(&rbuf_tmp, src, color_conv_bgr24_to_rgb565()); break; case pix_format_rgba32: color_conv(&rbuf_tmp, src, color_conv_rgba32_to_rgb565()); break; case pix_format_argb32: color_conv(&rbuf_tmp, src, color_conv_argb32_to_rgb565()); break; case pix_format_bgra32: color_conv(&rbuf_tmp, src, color_conv_bgra32_to_rgb565()); break; case pix_format_abgr32: color_conv(&rbuf_tmp, src, color_conv_abgr32_to_rgb565()); break; } break; case pix_format_rgba32: switch(m_format) { default: break; case pix_format_sgray8: convert(&rbuf_tmp, src); break; case pix_format_gray8: convert(&rbuf_tmp, src); break; case pix_format_gray16: convert(&rbuf_tmp, src); break; case pix_format_gray32: convert(&rbuf_tmp, src); break; case pix_format_rgb555: color_conv(&rbuf_tmp, src, color_conv_rgb555_to_rgba32()); break; case pix_format_rgb565: color_conv(&rbuf_tmp, src, color_conv_rgb565_to_rgba32()); break; case pix_format_srgb24: convert(&rbuf_tmp, src); break; case pix_format_sbgr24: convert(&rbuf_tmp, src); break; case pix_format_rgb24: convert(&rbuf_tmp, src); break; case pix_format_bgr24: convert(&rbuf_tmp, src); break; case pix_format_srgba32: convert(&rbuf_tmp, src); break; case pix_format_sargb32: convert(&rbuf_tmp, src); break; case pix_format_sabgr32: convert(&rbuf_tmp, src); break; case pix_format_sbgra32: convert(&rbuf_tmp, src); break; case pix_format_rgba32: convert(&rbuf_tmp, src); break; case pix_format_argb32: convert(&rbuf_tmp, src); break; case pix_format_abgr32: convert(&rbuf_tmp, src); break; case pix_format_bgra32: convert(&rbuf_tmp, src); break; case pix_format_rgb48: convert(&rbuf_tmp, src); break; case pix_format_bgr48: convert(&rbuf_tmp, src); break; case pix_format_rgba64: convert(&rbuf_tmp, src); break; case pix_format_argb64: convert(&rbuf_tmp, src); break; case pix_format_abgr64: convert(&rbuf_tmp, src); break; case pix_format_bgra64: convert(&rbuf_tmp, src); break; case pix_format_rgb96: convert(&rbuf_tmp, src); break; case pix_format_bgr96: convert(&rbuf_tmp, src); break; case pix_format_rgba128: convert(&rbuf_tmp, src); break; case pix_format_argb128: convert(&rbuf_tmp, src); break; case pix_format_abgr128: convert(&rbuf_tmp, src); break; case pix_format_bgra128: convert(&rbuf_tmp, src); break; } break; case pix_format_abgr32: switch(m_format) { default: break; case pix_format_sgray8: convert(&rbuf_tmp, src); break; case pix_format_gray8: convert(&rbuf_tmp, src); break; case pix_format_gray16: convert(&rbuf_tmp, src); break; case pix_format_gray32: convert(&rbuf_tmp, src); break; case pix_format_rgb555: color_conv(&rbuf_tmp, src, color_conv_rgb555_to_abgr32()); break; case pix_format_rgb565: color_conv(&rbuf_tmp, src, color_conv_rgb565_to_abgr32()); break; case pix_format_srgb24: convert(&rbuf_tmp, src); break; case pix_format_sbgr24: convert(&rbuf_tmp, src); break; case pix_format_rgb24: convert(&rbuf_tmp, src); break; case pix_format_bgr24: convert(&rbuf_tmp, src); break; case pix_format_srgba32: convert(&rbuf_tmp, src); break; case pix_format_sargb32: convert(&rbuf_tmp, src); break; case pix_format_sabgr32: convert(&rbuf_tmp, src); break; case pix_format_sbgra32: convert(&rbuf_tmp, src); break; case pix_format_rgba32: convert(&rbuf_tmp, src); break; case pix_format_argb32: convert(&rbuf_tmp, src); break; case pix_format_abgr32: convert(&rbuf_tmp, src); break; case pix_format_bgra32: convert(&rbuf_tmp, src); break; case pix_format_rgb48: convert(&rbuf_tmp, src); break; case pix_format_bgr48: convert(&rbuf_tmp, src); break; case pix_format_rgba64: convert(&rbuf_tmp, src); break; case pix_format_argb64: convert(&rbuf_tmp, src); break; case pix_format_abgr64: convert(&rbuf_tmp, src); break; case pix_format_bgra64: convert(&rbuf_tmp, src); break; case pix_format_rgb96: convert(&rbuf_tmp, src); break; case pix_format_bgr96: convert(&rbuf_tmp, src); break; case pix_format_rgba128: convert(&rbuf_tmp, src); break; case pix_format_argb128: convert(&rbuf_tmp, src); break; case pix_format_abgr128: convert(&rbuf_tmp, src); break; case pix_format_bgra128: convert(&rbuf_tmp, src); break; } break; case pix_format_argb32: switch(m_format) { default: break; case pix_format_sgray8: convert(&rbuf_tmp, src); break; case pix_format_gray8: convert(&rbuf_tmp, src); break; case pix_format_gray16: convert(&rbuf_tmp, src); break; case pix_format_gray32: convert(&rbuf_tmp, src); break; case pix_format_rgb555: color_conv(&rbuf_tmp, src, color_conv_rgb555_to_argb32()); break; case pix_format_rgb565: color_conv(&rbuf_tmp, src, color_conv_rgb565_to_argb32()); break; case pix_format_srgb24: convert(&rbuf_tmp, src); break; case pix_format_sbgr24: convert(&rbuf_tmp, src); break; case pix_format_rgb24: convert(&rbuf_tmp, src); break; case pix_format_bgr24: convert(&rbuf_tmp, src); break; case pix_format_srgba32: convert(&rbuf_tmp, src); break; case pix_format_sargb32: convert(&rbuf_tmp, src); break; case pix_format_sabgr32: convert(&rbuf_tmp, src); break; case pix_format_sbgra32: convert(&rbuf_tmp, src); break; case pix_format_rgba32: convert(&rbuf_tmp, src); break; case pix_format_argb32: convert(&rbuf_tmp, src); break; case pix_format_abgr32: convert(&rbuf_tmp, src); break; case pix_format_bgra32: convert(&rbuf_tmp, src); break; case pix_format_rgb48: convert(&rbuf_tmp, src); break; case pix_format_bgr48: convert(&rbuf_tmp, src); break; case pix_format_rgba64: convert(&rbuf_tmp, src); break; case pix_format_argb64: convert(&rbuf_tmp, src); break; case pix_format_abgr64: convert(&rbuf_tmp, src); break; case pix_format_bgra64: convert(&rbuf_tmp, src); break; case pix_format_rgb96: convert(&rbuf_tmp, src); break; case pix_format_bgr96: convert(&rbuf_tmp, src); break; case pix_format_rgba128: convert(&rbuf_tmp, src); break; case pix_format_argb128: convert(&rbuf_tmp, src); break; case pix_format_abgr128: convert(&rbuf_tmp, src); break; case pix_format_bgra128: convert(&rbuf_tmp, src); break; } break; case pix_format_bgra32: switch(m_format) { default: break; case pix_format_sgray8: convert(&rbuf_tmp, src); break; case pix_format_gray8: convert(&rbuf_tmp, src); break; case pix_format_gray16: convert(&rbuf_tmp, src); break; case pix_format_gray32: convert(&rbuf_tmp, src); break; case pix_format_rgb555: color_conv(&rbuf_tmp, src, color_conv_rgb555_to_bgra32()); break; case pix_format_rgb565: color_conv(&rbuf_tmp, src, color_conv_rgb565_to_bgra32()); break; case pix_format_srgb24: convert(&rbuf_tmp, src); break; case pix_format_sbgr24: convert(&rbuf_tmp, src); break; case pix_format_rgb24: convert(&rbuf_tmp, src); break; case pix_format_bgr24: convert(&rbuf_tmp, src); break; case pix_format_srgba32: convert(&rbuf_tmp, src); break; case pix_format_sargb32: convert(&rbuf_tmp, src); break; case pix_format_sabgr32: convert(&rbuf_tmp, src); break; case pix_format_sbgra32: convert(&rbuf_tmp, src); break; case pix_format_rgba32: convert(&rbuf_tmp, src); break; case pix_format_argb32: convert(&rbuf_tmp, src); break; case pix_format_abgr32: convert(&rbuf_tmp, src); break; case pix_format_bgra32: convert(&rbuf_tmp, src); break; case pix_format_rgb48: convert(&rbuf_tmp, src); break; case pix_format_bgr48: convert(&rbuf_tmp, src); break; case pix_format_rgba64: convert(&rbuf_tmp, src); break; case pix_format_argb64: convert(&rbuf_tmp, src); break; case pix_format_abgr64: convert(&rbuf_tmp, src); break; case pix_format_bgra64: convert(&rbuf_tmp, src); break; case pix_format_rgb96: convert(&rbuf_tmp, src); break; case pix_format_bgr96: convert(&rbuf_tmp, src); break; case pix_format_rgba128: convert(&rbuf_tmp, src); break; case pix_format_argb128: convert(&rbuf_tmp, src); break; case pix_format_abgr128: convert(&rbuf_tmp, src); break; case pix_format_bgra128: convert(&rbuf_tmp, src); break; } break; } m_ximg_window->data = (char*)buf_tmp; XPutImage(m_display, m_window, m_gc, m_ximg_window, 0, 0, 0, 0, src->width(), src->height()); delete [] buf_tmp; } } //------------------------------------------------------------------------ platform_support::platform_support(pix_format_e format, bool flip_y) : m_specific(new platform_specific(format, flip_y)), m_format(format), m_bpp(m_specific->m_bpp), m_window_flags(0), m_wait_mode(true), m_flip_y(flip_y), m_initial_width(10), m_initial_height(10) { std::strcpy(m_caption, "AGG Application"); } //------------------------------------------------------------------------ platform_support::~platform_support() { delete m_specific; } //------------------------------------------------------------------------ void platform_support::caption(const char* cap) { std::strcpy(m_caption, cap); if(m_specific->m_initialized) { m_specific->caption(cap); } } //------------------------------------------------------------------------ enum xevent_mask_e { xevent_mask = PointerMotionMask| ButtonPressMask| ButtonReleaseMask| ExposureMask| KeyPressMask| StructureNotifyMask }; //------------------------------------------------------------------------ bool platform_support::init(unsigned width, unsigned height, unsigned flags) { m_window_flags = flags; m_specific->m_display = XOpenDisplay(NULL); if(m_specific->m_display == 0) { std::fprintf(stderr, "Unable to open DISPLAY!\n"); return false; } m_specific->m_screen = XDefaultScreen(m_specific->m_display); m_specific->m_depth = XDefaultDepth(m_specific->m_display, m_specific->m_screen); m_specific->m_visual = XDefaultVisual(m_specific->m_display, m_specific->m_screen); unsigned long r_mask = m_specific->m_visual->red_mask; unsigned long g_mask = m_specific->m_visual->green_mask; unsigned long b_mask = m_specific->m_visual->blue_mask; //std::printf("depth=%d, red=%08x, green=%08x, blue=%08x\n", // m_specific->m_depth, // m_specific->m_visual->red_mask, // m_specific->m_visual->green_mask, // m_specific->m_visual->blue_mask); // // NOT COMPLETED YET! // // Try to find an appropriate Visual if the default doesn't fit. // if(m_specific->m_depth < 15 || // r_mask == 0 || g_mask == 0 || b_mask == 0) // { // // // This is an attempt to find an appropriate Visual if // // the default one doesn't match the minumum requirements // static int depth[] = { 32, 24, 16, 15 }; // int i; // for(int i = 0; i < 4; i++) // { // XVisualInfo vi; // if(XMatchVisualInfo(m_specific->m_display, // m_specific->m_screen, // depth[i], // TrueColor, // &vi)) // { // // std::printf("TrueColor depth=%d, red=%08x, green=%08x, blue=%08x, bits=%d\n", // // vi.depth, // // vi.visual->red_mask, // // vi.visual->green_mask, // // vi.visual->blue_mask, // // vi.bits_per_rgb); // m_specific->m_depth = vi.depth; // m_specific->m_visual = vi.visual; // r_mask = m_specific->m_visual->red_mask; // g_mask = m_specific->m_visual->green_mask; // b_mask = m_specific->m_visual->blue_mask; // break; // } // if(XMatchVisualInfo(m_specific->m_display, // m_specific->m_screen, // depth[i], // DirectColor, // &vi)) // { // // std::printf("DirectColor depth=%d, red=%08x, green=%08x, blue=%08x, bits=%d\n", // // vi.depth, // // vi.visual->red_mask, // // vi.visual->green_mask, // // vi.visual->blue_mask, // // vi.bits_per_rgb); // m_specific->m_depth = vi.depth; // m_specific->m_visual = vi.visual; // r_mask = m_specific->m_visual->red_mask; // g_mask = m_specific->m_visual->green_mask; // b_mask = m_specific->m_visual->blue_mask; // break; // } // } // } if(m_specific->m_depth < 15 || r_mask == 0 || g_mask == 0 || b_mask == 0) { std::fprintf(stderr, "There's no Visual compatible with minimal AGG requirements:\n" "At least 15-bit color depth and True- or DirectColor class.\n\n"); XCloseDisplay(m_specific->m_display); return false; } int t = 1; int hw_byte_order = LSBFirst; if(*(char*)&t == 0) hw_byte_order = MSBFirst; // Perceive SYS-format by mask switch(m_specific->m_depth) { case 15: m_specific->m_sys_bpp = 16; if(r_mask == 0x7C00 && g_mask == 0x3E0 && b_mask == 0x1F) { m_specific->m_sys_format = pix_format_rgb555; m_specific->m_byte_order = hw_byte_order; } break; case 16: m_specific->m_sys_bpp = 16; if(r_mask == 0xF800 && g_mask == 0x7E0 && b_mask == 0x1F) { m_specific->m_sys_format = pix_format_rgb565; m_specific->m_byte_order = hw_byte_order; } break; case 24: case 32: m_specific->m_sys_bpp = 32; if(g_mask == 0xFF00) { if(r_mask == 0xFF && b_mask == 0xFF0000) { switch(m_specific->m_format) { case pix_format_rgba32: m_specific->m_sys_format = pix_format_rgba32; m_specific->m_byte_order = LSBFirst; break; case pix_format_abgr32: m_specific->m_sys_format = pix_format_abgr32; m_specific->m_byte_order = MSBFirst; break; default: m_specific->m_byte_order = hw_byte_order; m_specific->m_sys_format = (hw_byte_order == LSBFirst) ? pix_format_rgba32 : pix_format_abgr32; break; } } if(r_mask == 0xFF0000 && b_mask == 0xFF) { switch(m_specific->m_format) { case pix_format_argb32: m_specific->m_sys_format = pix_format_argb32; m_specific->m_byte_order = MSBFirst; break; case pix_format_bgra32: m_specific->m_sys_format = pix_format_bgra32; m_specific->m_byte_order = LSBFirst; break; default: m_specific->m_byte_order = hw_byte_order; m_specific->m_sys_format = (hw_byte_order == MSBFirst) ? pix_format_argb32 : pix_format_bgra32; break; } } } break; } if(m_specific->m_sys_format == pix_format_undefined) { std::fprintf(stderr, "RGB masks are not compatible with AGG pixel formats:\n" "R=%08lx, R=%08lx, B=%08lx\n", r_mask, g_mask, b_mask); XCloseDisplay(m_specific->m_display); return false; } std::memset(&m_specific->m_window_attributes, 0, sizeof(m_specific->m_window_attributes)); m_specific->m_window_attributes.border_pixel = XBlackPixel(m_specific->m_display, m_specific->m_screen); m_specific->m_window_attributes.background_pixel = XWhitePixel(m_specific->m_display, m_specific->m_screen); m_specific->m_window_attributes.override_redirect = 0; unsigned long window_mask = CWBackPixel | CWBorderPixel; m_specific->m_window = XCreateWindow(m_specific->m_display, XDefaultRootWindow(m_specific->m_display), 0, 0, width, height, 0, m_specific->m_depth, InputOutput, CopyFromParent, window_mask, &m_specific->m_window_attributes); m_specific->m_gc = XCreateGC(m_specific->m_display, m_specific->m_window, 0, 0); m_specific->m_buf_window = new unsigned char[width * height * (m_bpp / 8)]; std::memset(m_specific->m_buf_window, 255, width * height * (m_bpp / 8)); m_rbuf_window.attach(m_specific->m_buf_window, width, height, m_flip_y ? -width * (m_bpp / 8) : width * (m_bpp / 8)); m_specific->m_ximg_window = XCreateImage(m_specific->m_display, m_specific->m_visual, //CopyFromParent, m_specific->m_depth, ZPixmap, 0, (char*)m_specific->m_buf_window, width, height, m_specific->m_sys_bpp, width * (m_specific->m_sys_bpp / 8)); m_specific->m_ximg_window->byte_order = m_specific->m_byte_order; m_specific->caption(m_caption); m_initial_width = width; m_initial_height = height; if(!m_specific->m_initialized) { on_init(); m_specific->m_initialized = true; } trans_affine_resizing(width, height); on_resize(width, height); m_specific->m_update_flag = true; XSizeHints *hints = XAllocSizeHints(); if(hints) { if(flags & window_resize) { hints->min_width = 32; hints->min_height = 32; hints->max_width = 4096; hints->max_height = 4096; } else { hints->min_width = width; hints->min_height = height; hints->max_width = width; hints->max_height = height; } hints->flags = PMaxSize | PMinSize; XSetWMNormalHints(m_specific->m_display, m_specific->m_window, hints); XFree(hints); } XMapWindow(m_specific->m_display, m_specific->m_window); XSelectInput(m_specific->m_display, m_specific->m_window, xevent_mask); m_specific->m_close_atom = XInternAtom(m_specific->m_display, "WM_DELETE_WINDOW", false); XSetWMProtocols(m_specific->m_display, m_specific->m_window, &m_specific->m_close_atom, 1); return true; } //------------------------------------------------------------------------ void platform_support::update_window() { m_specific->put_image(&m_rbuf_window); // When m_wait_mode is true we can discard all the events // came while the image is being drawn. In this case // the X server does not accumulate mouse motion events. // When m_wait_mode is false, i.e. we have some idle drawing // we cannot afford to miss any events XSync(m_specific->m_display, m_wait_mode); } //------------------------------------------------------------------------ int platform_support::run() { XFlush(m_specific->m_display); bool quit = false; unsigned flags; int cur_x; int cur_y; while(!quit) { if(m_specific->m_update_flag) { on_draw(); update_window(); m_specific->m_update_flag = false; } if(!m_wait_mode) { if(XPending(m_specific->m_display) == 0) { on_idle(); continue; } } XEvent x_event; XNextEvent(m_specific->m_display, &x_event); // In the Idle mode discard all intermediate MotionNotify events if(!m_wait_mode && x_event.type == MotionNotify) { XEvent te = x_event; for(;;) { if(XPending(m_specific->m_display) == 0) break; XNextEvent(m_specific->m_display, &te); if(te.type != MotionNotify) break; } x_event = te; } switch(x_event.type) { case ConfigureNotify: { if(x_event.xconfigure.width != int(m_rbuf_window.width()) || x_event.xconfigure.height != int(m_rbuf_window.height())) { int width = x_event.xconfigure.width; int height = x_event.xconfigure.height; delete [] m_specific->m_buf_window; m_specific->m_ximg_window->data = 0; XDestroyImage(m_specific->m_ximg_window); m_specific->m_buf_window = new unsigned char[width * height * (m_bpp / 8)]; m_rbuf_window.attach(m_specific->m_buf_window, width, height, m_flip_y ? -width * (m_bpp / 8) : width * (m_bpp / 8)); m_specific->m_ximg_window = XCreateImage(m_specific->m_display, m_specific->m_visual, //CopyFromParent, m_specific->m_depth, ZPixmap, 0, (char*)m_specific->m_buf_window, width, height, m_specific->m_sys_bpp, width * (m_specific->m_sys_bpp / 8)); m_specific->m_ximg_window->byte_order = m_specific->m_byte_order; trans_affine_resizing(width, height); on_resize(width, height); on_draw(); update_window(); } } break; case Expose: m_specific->put_image(&m_rbuf_window); XFlush(m_specific->m_display); XSync(m_specific->m_display, false); break; case KeyPress: { KeySym key = XLookupKeysym(&x_event.xkey, 0); flags = 0; if(x_event.xkey.state & Button1Mask) flags |= mouse_left; if(x_event.xkey.state & Button3Mask) flags |= mouse_right; if(x_event.xkey.state & ShiftMask) flags |= kbd_shift; if(x_event.xkey.state & ControlMask) flags |= kbd_ctrl; bool left = false; bool up = false; bool right = false; bool down = false; switch(m_specific->m_keymap[key & 0xFF]) { case key_left: left = true; break; case key_up: up = true; break; case key_right: right = true; break; case key_down: down = true; break; case key_f2: copy_window_to_img(max_images - 1); save_img(max_images - 1, "screenshot"); break; } if(m_ctrls.on_arrow_keys(left, right, down, up)) { on_ctrl_change(); force_redraw(); } else { on_key(x_event.xkey.x, m_flip_y ? m_rbuf_window.height() - x_event.xkey.y : x_event.xkey.y, m_specific->m_keymap[key & 0xFF], flags); } } break; case ButtonPress: { flags = 0; if(x_event.xbutton.state & ShiftMask) flags |= kbd_shift; if(x_event.xbutton.state & ControlMask) flags |= kbd_ctrl; if(x_event.xbutton.button == Button1) flags |= mouse_left; if(x_event.xbutton.button == Button3) flags |= mouse_right; cur_x = x_event.xbutton.x; cur_y = m_flip_y ? m_rbuf_window.height() - x_event.xbutton.y : x_event.xbutton.y; if(flags & mouse_left) { if(m_ctrls.on_mouse_button_down(cur_x, cur_y)) { m_ctrls.set_cur(cur_x, cur_y); on_ctrl_change(); force_redraw(); } else { if(m_ctrls.in_rect(cur_x, cur_y)) { if(m_ctrls.set_cur(cur_x, cur_y)) { on_ctrl_change(); force_redraw(); } } else { on_mouse_button_down(cur_x, cur_y, flags); } } } if(flags & mouse_right) { on_mouse_button_down(cur_x, cur_y, flags); } //m_specific->m_wait_mode = m_wait_mode; //m_wait_mode = true; } break; case MotionNotify: { flags = 0; if(x_event.xmotion.state & Button1Mask) flags |= mouse_left; if(x_event.xmotion.state & Button3Mask) flags |= mouse_right; if(x_event.xmotion.state & ShiftMask) flags |= kbd_shift; if(x_event.xmotion.state & ControlMask) flags |= kbd_ctrl; cur_x = x_event.xbutton.x; cur_y = m_flip_y ? m_rbuf_window.height() - x_event.xbutton.y : x_event.xbutton.y; if(m_ctrls.on_mouse_move(cur_x, cur_y, (flags & mouse_left) != 0)) { on_ctrl_change(); force_redraw(); } else { if(!m_ctrls.in_rect(cur_x, cur_y)) { on_mouse_move(cur_x, cur_y, flags); } } } break; case ButtonRelease: { flags = 0; if(x_event.xbutton.state & ShiftMask) flags |= kbd_shift; if(x_event.xbutton.state & ControlMask) flags |= kbd_ctrl; if(x_event.xbutton.button == Button1) flags |= mouse_left; if(x_event.xbutton.button == Button3) flags |= mouse_right; cur_x = x_event.xbutton.x; cur_y = m_flip_y ? m_rbuf_window.height() - x_event.xbutton.y : x_event.xbutton.y; if(flags & mouse_left) { if(m_ctrls.on_mouse_button_up(cur_x, cur_y)) { on_ctrl_change(); force_redraw(); } } if(flags & (mouse_left | mouse_right)) { on_mouse_button_up(cur_x, cur_y, flags); } } //m_wait_mode = m_specific->m_wait_mode; break; case ClientMessage: if((x_event.xclient.format == 32) && (x_event.xclient.data.l[0] == int(m_specific->m_close_atom))) { quit = true; } break; } } unsigned i = platform_support::max_images; while(i--) { if(m_specific->m_buf_img[i]) { delete [] m_specific->m_buf_img[i]; } } delete [] m_specific->m_buf_window; m_specific->m_ximg_window->data = 0; XDestroyImage(m_specific->m_ximg_window); XFreeGC(m_specific->m_display, m_specific->m_gc); XDestroyWindow(m_specific->m_display, m_specific->m_window); XCloseDisplay(m_specific->m_display); return 0; } //------------------------------------------------------------------------ const char* platform_support::img_ext() const { return ".ppm"; } //------------------------------------------------------------------------ const char* platform_support::full_file_name(const char* file_name) { return file_name; } //------------------------------------------------------------------------ bool platform_support::load_img(unsigned idx, const char* file) { if(idx < max_images) { char buf[1024]; std::strcpy(buf, file); int len = std::strlen(buf); if(len < 4 || strcasecmp(buf + len - 4, ".ppm") != 0) { std::strcat(buf, ".ppm"); } FILE* fd = std::fopen(buf, "rb"); if(fd == 0) return false; if((len = std::fread(buf, 1, 1022, fd)) == 0) { fclose(fd); return false; } buf[len] = 0; if(buf[0] != 'P' && buf[1] != '6') { std::fclose(fd); return false; } char* ptr = buf + 2; while(*ptr && !std::isdigit((unsigned char)(*ptr))) ptr++; if(*ptr == 0) { std::fclose(fd); return false; } unsigned width = std::atoi(ptr); if(width == 0 || width > 4096) { std::fclose(fd); return false; } while(*ptr && isdigit((unsigned char)(*ptr))) ptr++; while(*ptr && !isdigit((unsigned char)(*ptr))) ptr++; if(*ptr == 0) { std::fclose(fd); return false; } unsigned height = std::atoi(ptr); if(height == 0 || height > 4096) { std::fclose(fd); return false; } while(*ptr && isdigit((unsigned char)(*ptr))) ptr++; while(*ptr && !isdigit((unsigned char)(*ptr))) ptr++; if(std::atoi(ptr) != 255) { std::fclose(fd); return false; } while(*ptr && isdigit((unsigned char)(*ptr))) ptr++; if(*ptr == 0) { std::fclose(fd); return false; } ptr++; std::fseek(fd, long(ptr - buf), SEEK_SET); create_img(idx, width, height); bool ret = true; if(m_format == pix_format_rgb24) { std::size_t sz = std::fread(m_specific->m_buf_img[idx], 1, width * height * 3, fd); if (sz != width * height * 3) ret = false; } else { unsigned char* buf_img = new unsigned char [width * height * 3]; rendering_buffer rbuf_img; rbuf_img.attach(buf_img, width, height, m_flip_y ? -width * 3 : width * 3); std::size_t sz = std::fread(buf_img, 1, width * height * 3, fd); if (sz != width * height * 3) ret = false; switch(m_format) { case pix_format_sgray8: convert(m_rbuf_img+idx, &rbuf_img); break; case pix_format_gray8: convert(m_rbuf_img+idx, &rbuf_img); break; case pix_format_gray16: convert(m_rbuf_img+idx, &rbuf_img); break; case pix_format_gray32: convert(m_rbuf_img+idx, &rbuf_img); break; case pix_format_rgb555: color_conv(m_rbuf_img+idx, &rbuf_img, color_conv_rgb24_to_rgb555()); break; case pix_format_rgb565: color_conv(m_rbuf_img+idx, &rbuf_img, color_conv_rgb24_to_rgb565()); break; case pix_format_sbgr24: convert(m_rbuf_img+idx, &rbuf_img); break; case pix_format_rgb24: convert(m_rbuf_img+idx, &rbuf_img); break; case pix_format_bgr24: convert(m_rbuf_img+idx, &rbuf_img); break; case pix_format_srgba32: convert(m_rbuf_img+idx, &rbuf_img); break; case pix_format_sargb32: convert(m_rbuf_img+idx, &rbuf_img); break; case pix_format_sbgra32: convert(m_rbuf_img+idx, &rbuf_img); break; case pix_format_sabgr32: convert(m_rbuf_img+idx, &rbuf_img); break; case pix_format_rgba32: convert(m_rbuf_img+idx, &rbuf_img); break; case pix_format_argb32: convert(m_rbuf_img+idx, &rbuf_img); break; case pix_format_bgra32: convert(m_rbuf_img+idx, &rbuf_img); break; case pix_format_abgr32: convert(m_rbuf_img+idx, &rbuf_img); break; case pix_format_rgb48: convert(m_rbuf_img+idx, &rbuf_img); break; case pix_format_bgr48: convert(m_rbuf_img+idx, &rbuf_img); break; case pix_format_rgba64: convert(m_rbuf_img+idx, &rbuf_img); break; case pix_format_argb64: convert(m_rbuf_img+idx, &rbuf_img); break; case pix_format_bgra64: convert(m_rbuf_img+idx, &rbuf_img); break; case pix_format_abgr64: convert(m_rbuf_img+idx, &rbuf_img); break; case pix_format_rgb96: convert(m_rbuf_img+idx, &rbuf_img); break; case pix_format_bgr96: convert(m_rbuf_img+idx, &rbuf_img); break; case pix_format_rgba128: convert(m_rbuf_img+idx, &rbuf_img); break; case pix_format_argb128: convert(m_rbuf_img+idx, &rbuf_img); break; case pix_format_bgra128: convert(m_rbuf_img+idx, &rbuf_img); break; case pix_format_abgr128: convert(m_rbuf_img+idx, &rbuf_img); break; default: ret = false; } delete [] buf_img; } std::fclose(fd); return ret; } return false; } //------------------------------------------------------------------------ bool platform_support::save_img(unsigned idx, const char* file) { if(idx < max_images && rbuf_img(idx).buf()) { char buf[1024]; std::strcpy(buf, file); int len = std::strlen(buf); if(len < 4 || strcasecmp(buf + len - 4, ".ppm") != 0) { std::strcat(buf, ".ppm"); } FILE* fd = std::fopen(buf, "wb"); if(fd == 0) return false; unsigned w = rbuf_img(idx).width(); unsigned h = rbuf_img(idx).height(); std::fprintf(fd, "P6\n%d %d\n255\n", w, h); unsigned y; unsigned char* tmp_buf = new unsigned char [w * 3]; for(y = 0; y < rbuf_img(idx).height(); y++) { const unsigned char* src = rbuf_img(idx).row_ptr(m_flip_y ? h - 1 - y : y); switch(m_format) { case pix_format_sgray8: color_conv_row(tmp_buf, src, w, conv_row()); break; case pix_format_gray8: color_conv_row(tmp_buf, src, w, conv_row()); break; case pix_format_gray16: color_conv_row(tmp_buf, src, w, conv_row()); break; case pix_format_gray32: color_conv_row(tmp_buf, src, w, conv_row()); break; default: break; case pix_format_rgb555: color_conv_row(tmp_buf, src, w, color_conv_rgb555_to_rgb24()); break; case pix_format_rgb565: color_conv_row(tmp_buf, src, w, color_conv_rgb565_to_rgb24()); break; case pix_format_sbgr24: color_conv_row(tmp_buf, src, w, conv_row()); break; case pix_format_srgb24: color_conv_row(tmp_buf, src, w, conv_row()); break; case pix_format_bgr24: color_conv_row(tmp_buf, src, w, conv_row()); break; case pix_format_rgb24: color_conv_row(tmp_buf, src, w, conv_row()); break; case pix_format_srgba32: color_conv_row(tmp_buf, src, w, conv_row()); break; case pix_format_sargb32: color_conv_row(tmp_buf, src, w, conv_row()); break; case pix_format_sbgra32: color_conv_row(tmp_buf, src, w, conv_row()); break; case pix_format_sabgr32: color_conv_row(tmp_buf, src, w, conv_row()); break; case pix_format_rgba32: color_conv_row(tmp_buf, src, w, conv_row()); break; case pix_format_argb32: color_conv_row(tmp_buf, src, w, conv_row()); break; case pix_format_bgra32: color_conv_row(tmp_buf, src, w, conv_row()); break; case pix_format_abgr32: color_conv_row(tmp_buf, src, w, conv_row()); break; case pix_format_bgr48: color_conv_row(tmp_buf, src, w, conv_row()); break; case pix_format_rgb48: color_conv_row(tmp_buf, src, w, conv_row()); break; case pix_format_rgba64: color_conv_row(tmp_buf, src, w, conv_row()); break; case pix_format_argb64: color_conv_row(tmp_buf, src, w, conv_row()); break; case pix_format_bgra64: color_conv_row(tmp_buf, src, w, conv_row()); break; case pix_format_abgr64: color_conv_row(tmp_buf, src, w, conv_row()); break; case pix_format_bgr96: color_conv_row(tmp_buf, src, w, conv_row()); break; case pix_format_rgb96: color_conv_row(tmp_buf, src, w, conv_row()); break; case pix_format_rgba128: color_conv_row(tmp_buf, src, w, conv_row()); break; case pix_format_argb128: color_conv_row(tmp_buf, src, w, conv_row()); break; case pix_format_bgra128: color_conv_row(tmp_buf, src, w, conv_row()); break; case pix_format_abgr128: color_conv_row(tmp_buf, src, w, conv_row()); break; } std::fwrite(tmp_buf, 1, w * 3, fd); } delete [] tmp_buf; std::fclose(fd); return true; } return false; } //------------------------------------------------------------------------ bool platform_support::create_img(unsigned idx, unsigned width, unsigned height) { if(idx < max_images) { if(width == 0) width = rbuf_window().width(); if(height == 0) height = rbuf_window().height(); delete [] m_specific->m_buf_img[idx]; m_specific->m_buf_img[idx] = new unsigned char[width * height * (m_bpp / 8)]; m_rbuf_img[idx].attach(m_specific->m_buf_img[idx], width, height, m_flip_y ? -width * (m_bpp / 8) : width * (m_bpp / 8)); return true; } return false; } //------------------------------------------------------------------------ void platform_support::force_redraw() { m_specific->m_update_flag = true; } //------------------------------------------------------------------------ void platform_support::message(const char* msg) { std::fprintf(stderr, "%s\n", msg); } //------------------------------------------------------------------------ void platform_support::start_timer() { m_specific->m_sw_start = clock(); } //------------------------------------------------------------------------ double platform_support::elapsed_time() const { std::clock_t stop = std::clock(); return double(stop - m_specific->m_sw_start) * 1000.0 / CLOCKS_PER_SEC; } //------------------------------------------------------------------------ void platform_support::on_init() {} void platform_support::on_resize(int sx, int sy) {} void platform_support::on_idle() {} void platform_support::on_mouse_move(int x, int y, unsigned flags) {} void platform_support::on_mouse_button_down(int x, int y, unsigned flags) {} void platform_support::on_mouse_button_up(int x, int y, unsigned flags) {} void platform_support::on_key(int x, int y, unsigned key, unsigned flags) {} void platform_support::on_ctrl_change() {} void platform_support::on_draw() {} void platform_support::on_post_draw(void* raw_handler) {} } int agg_main(int argc, char* argv[]); int main(int argc, char* argv[]) { return agg_main(argc, argv); }