CStretchEngine::CStretchEngine(IFX_ScanlineComposer* pDestBitmap, FXDIB_Format dest_format, int dest_width, int dest_height, const FX_RECT& clip_rect, const CFX_DIBSource* pSrcBitmap, int flags) { m_State = 0; m_DestFormat = dest_format; m_DestBpp = dest_format & 0xff; m_SrcBpp = pSrcBitmap->GetFormat() & 0xff; m_bHasAlpha = pSrcBitmap->GetFormat() & 0x200; m_pSrcPalette = pSrcBitmap->GetPalette(); m_pDestBitmap = pDestBitmap; m_DestWidth = dest_width; m_DestHeight = dest_height; m_pInterBuf = NULL; m_pExtraAlphaBuf = NULL; m_pDestMaskScanline = NULL; m_DestClip = clip_rect; FX_DWORD size = clip_rect.Width(); if (size && m_DestBpp > (int)(INT_MAX / size)) { return; } size *= m_DestBpp; if (size > INT_MAX - 31) { return; } size += 31; size = size / 32 * 4; m_pDestScanline = FX_TryAlloc(FX_BYTE, size); if (m_pDestScanline == NULL) { return; } if (dest_format == FXDIB_Rgb32) { FXSYS_memset8(m_pDestScanline, 255, size); } m_InterPitch = (m_DestClip.Width() * m_DestBpp + 31) / 32 * 4; m_ExtraMaskPitch = (m_DestClip.Width() * 8 + 31) / 32 * 4; m_pInterBuf = NULL; m_pSource = pSrcBitmap; m_SrcWidth = pSrcBitmap->GetWidth(); m_SrcHeight = pSrcBitmap->GetHeight(); m_SrcPitch = (m_SrcWidth * m_SrcBpp + 31) / 32 * 4; if ((flags & FXDIB_NOSMOOTH) == 0) { FX_BOOL bInterpol = flags & FXDIB_INTERPOL || flags & FXDIB_BICUBIC_INTERPOL; if (!bInterpol && FXSYS_abs(dest_width) != 0 && FXSYS_abs(dest_height) < m_SrcWidth * m_SrcHeight * 8 / FXSYS_abs(dest_width)) { flags = FXDIB_INTERPOL; } m_Flags = flags; } else { m_Flags = FXDIB_NOSMOOTH; if (flags & FXDIB_DOWNSAMPLE) { m_Flags |= FXDIB_DOWNSAMPLE; } } double scale_x = FXSYS_Div((FX_FLOAT)(m_SrcWidth), (FX_FLOAT)(m_DestWidth)); double scale_y = FXSYS_Div((FX_FLOAT)(m_SrcHeight), (FX_FLOAT)(m_DestHeight)); double base_x = m_DestWidth > 0 ? 0.0f : (FX_FLOAT)(m_DestWidth); double base_y = m_DestHeight > 0 ? 0.0f : (FX_FLOAT)(m_DestHeight); double src_left = FXSYS_Mul(scale_x, (FX_FLOAT)(clip_rect.left) + base_x); double src_right = FXSYS_Mul(scale_x, (FX_FLOAT)(clip_rect.right) + base_x); double src_top = FXSYS_Mul(scale_y, (FX_FLOAT)(clip_rect.top) + base_y); double src_bottom = FXSYS_Mul(scale_y, (FX_FLOAT)(clip_rect.bottom) + base_y); if (src_left > src_right) { double temp = src_left; src_left = src_right; src_right = temp; } if (src_top > src_bottom) { double temp = src_top; src_top = src_bottom; src_bottom = temp; } m_SrcClip.left = (int)FXSYS_floor((FX_FLOAT)src_left); m_SrcClip.right = (int)FXSYS_ceil((FX_FLOAT)src_right); m_SrcClip.top = (int)FXSYS_floor((FX_FLOAT)src_top); m_SrcClip.bottom = (int)FXSYS_ceil((FX_FLOAT)src_bottom); FX_RECT src_rect(0, 0, m_SrcWidth, m_SrcHeight); m_SrcClip.Intersect(src_rect); if (m_SrcBpp == 1) { if (m_DestBpp == 8) { m_TransMethod = 1; } else { m_TransMethod = 2; } } else if (m_SrcBpp == 8) { if (m_DestBpp == 8) { if (!m_bHasAlpha) { m_TransMethod = 3; } else { m_TransMethod = 4; } } else { if (!m_bHasAlpha) { m_TransMethod = 5; } else { m_TransMethod = 6; } } } else { if (!m_bHasAlpha) { m_TransMethod = 7; } else { m_TransMethod = 8; } } }
void OpImageBackground::OnPaint(OpWidgetPainter* widget_painter, const OpRect &paint_rect) { if (m_image.IsEmpty()) return OpWidget::OnPaint(widget_painter, paint_rect); const OpRect bounds_rect = GetBounds(); const OpRect content_rect(bounds_rect); OpRect src_rect(0, 0, m_image.Width(), m_image.Height()); switch (m_layout) { case BEST_FIT: { // Best fit aka Crop aka proportional stretch float width_ratio = (float)content_rect.width / (float)src_rect.width; float height_ratio = (float)content_rect.height / (float)src_rect.height; if (width_ratio > height_ratio) { INT32 height_of_src_to_use = src_rect.height - ((((float)src_rect.height * width_ratio) - (float)content_rect.height) / width_ratio); // find out how much to remove on the top or bottom: INT32 height_to_crop = (src_rect.height - height_of_src_to_use) / 2; if (height_to_crop<0) height_to_crop = - height_to_crop; src_rect.Set(0, height_to_crop, m_image.Width(), height_of_src_to_use); } else { INT32 width_of_src_to_use = src_rect.width - ((((float)src_rect.width * height_ratio) - (float)content_rect.width) / height_ratio); // find out how much to remove on the left or right : INT32 width_to_crop = (src_rect.width - width_of_src_to_use) / 2; if (width_to_crop<0) width_to_crop = - width_to_crop; src_rect.Set(width_to_crop, 0 , width_of_src_to_use, m_image.Height()); } // using src_rect with 0 width or height will crash if (src_rect.height < 1) src_rect.height = 1; if (src_rect.width < 1 ) src_rect.width = 1; GetVisualDevice()->ImageOut(m_image, src_rect, content_rect); break; } case STRETCH: GetVisualDevice()->ImageOut(m_image, src_rect, content_rect); break; case TILE: GetVisualDevice()->ImageOutTiled(m_image, content_rect, OpPoint(0, 0), null_image_listener, 100, 100, 0, 0, m_image.Width(), m_image.Height()); break; case CENTER: { OpRect center_rect; center_rect.x = (bounds_rect.width - (INT32)m_image.Width()) / 2; center_rect.y = (bounds_rect.height - (INT32)m_image.Height()) / 2; center_rect.width = m_image.Width(); center_rect.height = m_image.Height(); if(center_rect.x < 0) { src_rect.x -= center_rect.x; center_rect.x = 0; } if(center_rect.y < 0) { src_rect.y -= center_rect.y; center_rect.y = 0; } GetVisualDevice()->ImageOut(m_image, src_rect, center_rect); break; } default: OP_ASSERT(!"Unknown layout type"); } }
virtual void clear(const GColor& color) { src_rect(fDevice, fIBounds, color.premulToPixel()); }
// The start of the Application int App::start(const std::vector<CL_String> &args) { quit = false; // Create a console window for text-output if not available CL_ConsoleWindow console("Console", 80, 200); try { // Set the window // This opens a 640 x 480 window, including the frame size // If you want more control over the window, pass CL_DisplayWindowDescription to CL_DisplayWindow // (This is useful to create a borderless window of a specific size) // If you require target specific control over the window, use the derived CL_OpenGLWindowDescription // (This contains the multisampling options) #ifdef USE_SWRENDER CL_DisplayWindowDescription desc; #else CL_OpenGLWindowDescription desc; // desc.set_multisampling(4); #endif desc.set_title("ClanLib 2D Test"); desc.set_size(CL_Size(800, 600), true); CL_DisplayWindow window(desc); // Connect the Window close event CL_Slot slot_quit = window.sig_window_close().connect(this, &App::on_window_close); // Connect a keyboard handler to on_key_up() CL_Slot slot_input_up = (window.get_ic().get_keyboard()).sig_key_up().connect(this, &App::on_input_up); // Get the graphic context CL_GraphicContext gc = window.get_gc(); CL_Texture texture_image(gc, "tux.png"); texture_image.set_wrap_mode(cl_wrap_repeat, cl_wrap_repeat, cl_wrap_repeat); texture_image.set_min_filter(cl_filter_linear); texture_image.set_mag_filter(cl_filter_linear); CL_ResourceManager resources("resources.xml"); CL_Sprite sprite(gc, "test", &resources); //sprite.set_linear_filter(true); CL_Font small_font = CL_Font(gc, "Tahoma", 12); float test_base_angle = 0.0f; float test_angle = 0.0f; float test_angle_pitch = 0.0f; float test_angle_yaw = 0.0f; float test_scale = 1.0f; bool test_scale_dir = false; // Run until someone presses escape while (!quit) { gc.clear(CL_Colorf(0.0f,0.0f,0.2f)); gc.set_map_mode(CL_MapMode(cl_map_2d_upper_left)); // CL_Draw::point() for (int xcnt=0; xcnt<8; xcnt++) { for (int ycnt=0; ycnt<6; ycnt++) { CL_Draw::point(gc, xcnt*2, ycnt*2, CL_Colorf(1.0f, 1.0f, 1.0f, 1.0f)); } } small_font.draw_text(gc, 32, 10, "8*6 Points (0 + 2x), (0 + 2y)"); // CL_Draw::line() for (int xcnt=0; xcnt<4; xcnt++) { for (int ycnt=0; ycnt<3; ycnt++) { const int offset_y = 16; const int line_length = 6; const int spacing = 8; CL_Draw::line(gc, xcnt*spacing, (ycnt*spacing) + offset_y, line_length + (xcnt*spacing), (line_length + (ycnt*spacing)) + offset_y, CL_Colorf(1.0f, 1.0f, 1.0f, 1.0f)); } } small_font.draw_text(gc, 48, 30, "4*3 Lines (0 + 8x), (32 + 8y), (6 + 8x), (38 + 8y)"); // CL_Draw::box() for (int xcnt=0; xcnt<4; xcnt++) { for (int ycnt=0; ycnt<3; ycnt++) { const int offset_y = 48; const int line_length = 6; const int spacing = 8; CL_Draw::box(gc, xcnt*spacing, (ycnt*spacing) + offset_y, line_length + (xcnt*spacing), (line_length + (ycnt*spacing)) + offset_y, CL_Colorf(1.0f, 1.0f, 1.0f, 1.0f)); } } small_font.draw_text(gc, 48, 66, "4*3 Box (0 + 8x), (32 + 8y), (6 + 8x), (38 + 8y)"); // CL_Draw::fill() for (int xcnt=0; xcnt<4; xcnt++) { for (int ycnt=0; ycnt<3; ycnt++) { const int offset_y = 80; const int line_length = 6; const int spacing = 8; CL_Draw::fill(gc, xcnt*spacing, (ycnt*spacing) + offset_y, line_length + (xcnt*spacing), (line_length + (ycnt*spacing)) + offset_y, CL_Colorf(1.0f, 1.0f, 1.0f, 1.0f)); } } small_font.draw_text(gc, 48, 90, "4*3 Fill (0 + 8x), (32 + 8y), (6 + 8x), (38 + 8y)"); // CL_Draw::gradient_fill() CL_Gradient gradient; gradient.top_left = CL_Colorf(1.0f, 1.0f, 1.0f, 1.0f); gradient.top_right = CL_Colorf(1.0f, 0.0f, 0.0f, 1.0f); gradient.bottom_left = CL_Colorf(0.0f, 0.0f, 1.0f, 1.0f); gradient.bottom_right = CL_Colorf(0.0f, 1.0f, 0.0f, 1.0f); for (int xcnt=0; xcnt<4; xcnt++) { for (int ycnt=0; ycnt<3; ycnt++) { const int offset_y = 110; const int line_length = 6; const int spacing = 8; CL_Draw::gradient_fill(gc, xcnt*spacing, (ycnt*spacing) + offset_y, line_length + (xcnt*spacing), (line_length + (ycnt*spacing)) + offset_y, gradient); } } small_font.draw_text(gc, 48, 115, "4*3 GradientFill (0 + 8x), (32 + 8y), (6 + 8x), (38 + 8y)"); small_font.draw_text(gc, 48, 125, "top left = white. top right = red"); small_font.draw_text(gc, 48, 135, "bottom left = blue. bottom right = green"); // CL_Draw::circle() { const int offset_y = 140; int radius = 5; CL_Draw::circle(gc, radius, offset_y + radius, radius, CL_Colorf(1.0f, 1.0f, 1.0f, 1.0f)); const int offset_x = 16; radius = 16; CL_Draw::circle(gc, offset_x + radius, offset_y + radius, radius, CL_Colorf(1.0f, 1.0f, 1.0f, 1.0f)); } small_font.draw_text(gc, 54, 149, "Circle (5, 145) Radius = 5"); small_font.draw_text(gc, 54, 159, "Circle (32, 156) Radius = 16"); // CL_Draw::gradient_circle() { CL_Gradient gradient; gradient.top_left = CL_Colorf(1.0f, 1.0f, 1.0f, 1.0f); gradient.top_right = CL_Colorf(0.0f, 0.0f, 0.0f, 1.0f); gradient.bottom_left = CL_Colorf(0.0f, 0.0f, 0.0f, 1.0f); gradient.bottom_right = CL_Colorf(1.0f, 0.0f, 0.0f, 1.0f); const int offset_y = 180; float radius = 17.0; float xpos = radius; float ypos = offset_y + radius; CL_Draw::gradient_circle(gc, CL_Pointf( xpos, ypos ), CL_Pointf(radius/2.0, 0.0f), radius, gradient); const int offset_x = 40; radius = 17.0; xpos = offset_x + radius; ypos = offset_y + radius; CL_Draw::gradient_circle(gc, CL_Pointf( xpos, ypos), CL_Pointf(0.0f, radius/2.0), radius, gradient); } small_font.draw_text(gc, 80, 189, "Gradient Circle (16, 196) Radius = 17. Gradient right"); small_font.draw_text(gc, 80, 199, "Gradient Circle (56, 196) Radius = 17. Gradient up"); small_font.draw_text(gc, 80, 209, "centre = white, outer = red"); // CL_Draw::triangle() { const float offset_y = 220.0f; const float size = 12.0f; CL_Draw::triangle(gc, CL_Pointf(0.0f, offset_y), CL_Pointf(0.0f, offset_y + size), CL_Pointf(size, offset_y + size), CL_Colorf(1.0f, 1.0f, 1.0f, 1.0f)); float offset_x = 16.0f; CL_Draw::triangle(gc, CL_Pointf(offset_x + 0.0f, offset_y + size), CL_Pointf(offset_x + size, offset_y + size), CL_Pointf(offset_x + 0.0f, offset_y), CL_Colorf(1.0f, 1.0f, 1.0f, 1.0f)); offset_x = 32.0f; CL_Draw::triangle(gc, CL_Pointf(offset_x + size, offset_y + size), CL_Pointf(offset_x + 0.0f, offset_y), CL_Pointf(offset_x + 0.0f, offset_y + size), CL_Colorf(1.0f, 1.0f, 1.0f, 1.0f)); } small_font.draw_text(gc, 48, 229, "3 Triangles (12 pixel size) (Left vertical edge)."); small_font.draw_text(gc, 48, 239, "Top Left: (0,220) (16,220) (32,220)"); // CL_Draw::texture() gc.set_texture(0, texture_image); { float offset_x = 0.0f; float offset_y = 250.0f; CL_Rectf src_rect(offset_x, offset_y, CL_Sizef(31, 47)); CL_Rectf texture_coords(0.0, 0.0, 1.0f, 1.0f); CL_Colorf color(1.0f, 1.0f, 1.0f, 1.0f); CL_Draw::texture(gc, src_rect, color, texture_coords); offset_x = 33.0f; src_rect = CL_Rectf(offset_x, offset_y, CL_Sizef(31, 47)); texture_coords = CL_Rectf(0.25f, 0.25f, 0.75f, 0.75f); color = CL_Colorf(1.0f, 0.0f, 0.0f, 1.0f); CL_Draw::texture(gc, src_rect, color, texture_coords); } gc.reset_texture(0); small_font.draw_text(gc, 76, 260, "Texture (0, 250) size=(31,47)"); small_font.draw_text(gc, 76, 275, "Texture (33, 250) size=(31,47) (red, magnify*2)"); // CL_RoundedRect { CL_RoundedRect roundedrect(CL_Sizef(64.0f, 32.0f), 15.0f); float offset_x = 0.0f; float offset_y = 300.0f; CL_Origin origin = origin_top_left; roundedrect.draw(gc, CL_Pointf(offset_x, offset_y), CL_Colorf(1.0f, 1.0f, 1.0f, 1.0f), origin); offset_y = 340.0f; roundedrect.fill(gc, CL_Pointf(offset_x, offset_y), CL_Colorf(1.0f, 1.0f, 1.0f, 1.0f), origin); offset_y = 380.0f; CL_Gradient gradient; gradient.top_left = CL_Colorf(1.0f, 1.0f, 1.0f, 1.0f); gradient.top_right = CL_Colorf(1.0f, 0.0f, 0.0f, 1.0f); gradient.bottom_left = CL_Colorf(0.0f, 0.0f, 1.0f, 1.0f); gradient.bottom_right = CL_Colorf(0.0f, 1.0f, 0.0f, 1.0f); roundedrect.fill(gc, CL_Pointf(offset_x, offset_y), gradient, origin); offset_y = 420.0f; roundedrect.set_control_point_bl(CL_Pointf(0.4f, 0.8f)); roundedrect.set_rounding_bottom_left(CL_Sizef(0.2f, 0.6f)); roundedrect.set_control_point_tl(CL_Pointf(0.2f, 0.4f)); roundedrect.set_rounding_top_left(CL_Sizef(0.4f, 0.2f)); roundedrect.set_control_point_tr(CL_Pointf(0.6f, 0.2f)); roundedrect.set_rounding_top_right(CL_Sizef(0.8f, 0.4f)); roundedrect.set_control_point_br(CL_Pointf(0.6f, 0.8f)); roundedrect.set_rounding_bottom_right(CL_Sizef(0.8f, 0.6f)); roundedrect.fill(gc, CL_Pointf(offset_x, offset_y), gradient, origin); } small_font.draw_text(gc, 76, 310, "RoundedRect - draw (0, 300) size=(64,32)"); small_font.draw_text(gc, 76, 325, "(RoundedRect - draw gradient - is not implemented)"); small_font.draw_text(gc, 76, 350, "RoundedRect - fill (0, 340) size=(64,32)"); small_font.draw_text(gc, 76, 390, "RoundedRect - fill gradient (0, 380) size=(64,32)"); small_font.draw_text(gc, 76, 400, "top left = white. top right = red"); small_font.draw_text(gc, 76, 410, "bottom left = blue. bottom right = green"); small_font.draw_text(gc, 76, 430, "RoundedRect - fill gradient (0, 420) size=(64,32)"); small_font.draw_text(gc, 76, 440, "Controling control / rounding points"); // CL_Sprite { test_base_angle+=5.0f; if (test_base_angle >= 360.0f) { test_base_angle = 0.0f; } #ifndef USE_SWRENDER clEnable(GL_MULTISAMPLE); #endif sprite.set_base_angle(CL_Angle(test_base_angle, cl_degrees)); sprite.draw(gc, 350, 20); sprite.set_base_angle(CL_Angle(0, cl_degrees)); #ifndef USE_SWRENDER clDisable(GL_MULTISAMPLE); #endif } small_font.draw_text(gc, 370, 20, "Sprite - Base angle"); small_font.draw_text(gc, 370, 35, "Multisampling enabled"); { test_angle+=5.0f; if (test_angle >= 360.0f) { test_angle = 0.0f; } sprite.set_angle(CL_Angle(test_angle, cl_degrees)); sprite.draw(gc, 350, 60); sprite.set_angle(CL_Angle(0, cl_degrees)); } small_font.draw_text(gc, 370, 60, "Sprite - Angle"); { test_angle_pitch+=5.0f; if (test_angle_pitch >= 360.0f) { test_angle_pitch = 0.0f; } sprite.set_angle_pitch(CL_Angle(test_angle_pitch, cl_degrees)); sprite.draw(gc, 350, 100); sprite.set_angle_pitch(CL_Angle(0, cl_degrees)); } small_font.draw_text(gc, 370, 100, "Sprite - Angle Pitch"); { test_angle_yaw+=5.0f; if (test_angle_yaw >= 360.0f) { test_angle_yaw = 0.0f; } sprite.set_angle_yaw(CL_Angle(test_angle_yaw, cl_degrees)); sprite.draw(gc, 350, 140); sprite.set_angle_yaw(CL_Angle(0, cl_degrees)); } small_font.draw_text(gc, 370, 140, "Sprite - Angle Yaw"); { if (test_scale_dir) { test_scale += 0.1f; if (test_scale >= 2.0f) { test_scale = 2.0f; test_scale_dir = false; } }else { test_scale -= 0.1f; if (test_scale <= -2.0f) { test_scale = -2.0f; test_scale_dir = true; } } sprite.set_scale(test_scale, 1.0f); sprite.draw(gc, 350, 180); sprite.set_scale(1.0f, test_scale); sprite.draw(gc, 390, 180); sprite.set_scale(1.0f, 1.0f); } small_font.draw_text(gc, 420, 180, "Sprite - Set Scale (x), (y)"); // Flip the display, showing on the screen what we have drawed // since last call to flip() window.flip(1); // This call processes user input and other events CL_KeepAlive::process(); } small_font = CL_Font(); } catch(CL_Exception& exception) { CL_Console::write_line("Exception caught:"); CL_Console::write_line(exception.message); // Display the stack trace (if available) std::vector<CL_String> stacktrace = exception.get_stack_trace(); int size = stacktrace.size(); if (size > 0) { CL_Console::write_line("Stack Trace:"); for (int cnt=0; cnt < size; cnt++) { CL_Console::write_line(stacktrace[cnt]); } } console.display_close_message(); return -1; } return 0; }
void Text::Draw(Bitmap& dest, int x, int y, int color, std::string const& text, Text::Alignment align) { if (text.length() == 0) return; FontRef font = dest.GetFont(); Rect dst_rect = Font::Default()->GetSize(text); switch (align) { case Text::AlignCenter: dst_rect.x = x - dst_rect.width / 2; break; case Text::AlignRight: dst_rect.x = x - dst_rect.width; break; case Text::AlignLeft: dst_rect.x = x; break; default: assert(false); } dst_rect.y = y; dst_rect.width += 1; dst_rect.height += 1; // Need place for shadow if (dst_rect.IsOutOfBounds(dest.GetWidth(), dest.GetHeight())) return; BitmapRef text_surface; // Complete text will be on this surface text_surface = Bitmap::Create(dst_rect.width, dst_rect.height, true); text_surface->SetTransparentColor(dest.GetTransparentColor()); text_surface->Clear(); // Load the system file for the shadow and text color BitmapRef system = Cache::System(Data::system.system_name); // Load the exfont-file BitmapRef exfont = Cache::Exfont(); // Get the Shadow color Color shadow_color(Cache::system_info.sh_color); // If shadow is pure black, increase blue channel // so it doesn't become transparent if ((shadow_color.red == 0) && (shadow_color.green == 0) && (shadow_color.blue == 0) ) { if (text_surface->bytes() >= 3) { shadow_color.blue++; } else { shadow_color.blue += 8; } } // Where to draw the next glyph (x pos) int next_glyph_pos = 0; // The current char is an exfont bool is_exfont = false; // This loops always renders a single char, color blends it and then puts // it onto the text_surface (including the drop shadow) for (boost::u8_to_u32_iterator<std::string::const_iterator> c(text.begin(), text.begin(), text.end()), end(text.end(), text.begin(), text.end()); c != end; ++c) { Rect next_glyph_rect(next_glyph_pos, 0, 0, 0); boost::u8_to_u32_iterator<std::string::const_iterator> next_c_it = boost::next(c); uint32_t const next_c = std::distance(c, end) > 1? *next_c_it : 0; // ExFont-Detection: Check for A-Z or a-z behind the $ if (*c == utf('$') && std::isalpha(next_c)) { int exfont_value = -1; // Calculate which exfont shall be rendered if (islower(next_c)) { exfont_value = 26 + next_c - utf('a'); } else if (isupper(next_c)) { exfont_value = next_c - utf('A'); } else { assert(false); } is_exfont = true; BitmapRef mask = Bitmap::Create(12, 12, true); // Get exfont from graphic Rect const rect_exfont((exfont_value % 13) * 12, (exfont_value / 13) * 12, 12, 12); // Create a mask mask->Clear(); mask->Blit(0, 0, *exfont, rect_exfont, 255); // Get color region from system graphic Rect clip_system(8+16*(color%10), 4+48+16*(color/10), 6, 12); BitmapRef char_surface = Bitmap::Create(mask->GetWidth(), mask->GetHeight(), true); char_surface->SetTransparentColor(dest.GetTransparentColor()); char_surface->Clear(); // Blit gradient color background (twice because of full glyph) char_surface->Blit(0, 0, *system, clip_system, 255); char_surface->Blit(6, 0, *system, clip_system, 255); // Blit mask onto background char_surface->MaskBlit(0, 0, *mask, mask->GetRect()); BitmapRef char_shadow = Bitmap::Create(mask->GetWidth(), mask->GetHeight(), true); char_shadow->SetTransparentColor(dest.GetTransparentColor()); char_shadow->Clear(); // Blit solid color background char_shadow->Fill(shadow_color); // Blit mask onto background char_shadow->MaskBlit(0, 0, *mask, mask->GetRect()); // Blit first shadow and then text text_surface->Blit(next_glyph_rect.x + 1, next_glyph_rect.y + 1, *char_shadow, char_shadow->GetRect(), 255); text_surface->Blit(next_glyph_rect.x, next_glyph_rect.y, *char_surface, char_surface->GetRect(), 255); } else { // Not ExFont, draw normal text font->Render(*text_surface, next_glyph_rect.x, next_glyph_rect.y, *system, color, *c); } // If it's a full size glyph, add the size of a half-size glypth twice if (is_exfont) { is_exfont = false; next_glyph_pos += 12; // Skip the next character ++c; } else { std::string const glyph(c.base(), next_c_it.base()); next_glyph_pos += Font::Default()->GetSize(glyph).width; } } BitmapRef text_bmp = Bitmap::Create(*text_surface, text_surface->GetRect()); Rect src_rect(0, 0, dst_rect.width, dst_rect.height); int iy = dst_rect.y; if (dst_rect.height > text_bmp->GetHeight()) { iy += ((dst_rect.height - text_bmp->GetHeight()) / 2); } int ix = dst_rect.x; dest.Blit(ix, iy, *text_bmp, src_rect, 255); }
void SimpleSurface::BlitChannel (const RenderTarget &outTarget, const Rect &inSrcRect, int inPosX, int inPosY, int inSrcChannel, int inDestChannel) const { bool src_alpha = (mPixelFormat == pfAlpha); bool dest_alpha = (outTarget.mPixelFormat == pfAlpha); // Flash API does not have alpha images (might be useful somewhere else?) if (src_alpha || dest_alpha) return; if (inDestChannel == CHAN_ALPHA && !(outTarget.Format () & pfHasAlpha)) return; bool set_255 = (inSrcChannel == CHAN_ALPHA && !(mPixelFormat & pfHasAlpha)); // Translate inSrcRect src_rect to dest ... Rect src_rect (inPosX, inPosY, inSrcRect.w, inSrcRect.h); // clip ... src_rect = src_rect.Intersect (outTarget.mRect); // translate back to source-coordinates ... src_rect.Translate (inSrcRect.x - inPosX, inSrcRect.y - inPosY); // clip to origial rect... src_rect = src_rect.Intersect (inSrcRect); if (src_rect.HasPixels ()) { int dx = inPosX + src_rect.x; int dy = inPosY + src_rect.y; bool c0_red = gC0IsRed != ((mPixelFormat & pfSwapRB) != 0); int src_ch = (inSrcChannel == CHAN_ALPHA ? 3 : inSrcChannel == CHAN_BLUE ? (c0_red ? 2 : 0) : inSrcChannel == CHAN_GREEN ? 1 : (c0_red ? 0 : 2)); c0_red = gC0IsRed != ((outTarget.Format () & pfSwapRB) != 0); int dest_ch = (inDestChannel == CHAN_ALPHA ? 3 : inDestChannel == CHAN_BLUE ? (c0_red ? 2 : 0) : inDestChannel == CHAN_GREEN ? 1 : (c0_red ? 0 : 2)); for (int y = 0; y < src_rect.h; y++) { uint8 *d = outTarget.Row (y + dy) + (dx * 4) + dest_ch; if (set_255) { for (int x = 0; x < src_rect.w; x++) { *d = 255; d += 4; } } else { const uint8 *s = Row (y + src_rect.y) + (src_rect.x * 4) + src_ch; for(int x = 0; x < src_rect.w; x++) { *d = *s; d += 4; s += 4; } } } } }
bool CurveWarp::accelerated_cairorender(Context context, cairo_t *cr, int quality, const RendDesc &renddesc_, ProgressCallback *cb)const { Point start_point=param_start_point.get(Point()); Point end_point=param_end_point.get(Point()); SuperCallback stageone(cb,0,9000,10000); SuperCallback stagetwo(cb,9000,10000,10000); RendDesc renddesc(renddesc_); // Untransform the render desc if(!cairo_renddesc_untransform(cr, renddesc)) return false; int x,y; const Real pw(renddesc.get_pw()),ph(renddesc.get_ph()); Point tl(renddesc.get_tl()); Point br(renddesc.get_br()); const int w(renddesc.get_w()); const int h(renddesc.get_h()); // find a bounding rectangle for the context we need to render // todo: find a better way of doing this - this way doesn't work Rect src_rect(transform(tl)); Point pos1, pos2; Real dist, along; Real min_dist(999999), max_dist(-999999), min_along(999999), max_along(-999999); #define UPDATE_DIST \ if (dist < min_dist) min_dist = dist; \ if (dist > max_dist) max_dist = dist; \ if (along < min_along) min_along = along; \ if (along > max_along) max_along = along // look along the top and bottom edges pos1[0] = pos2[0] = tl[0]; pos1[1] = tl[1]; pos2[1] = br[1]; for (x = 0; x < w; x++, pos1[0] += pw, pos2[0] += pw) { src_rect.expand(transform(pos1, &dist, &along)); UPDATE_DIST; src_rect.expand(transform(pos2, &dist, &along)); UPDATE_DIST; } // look along the left and right edges pos1[0] = tl[0]; pos2[0] = br[0]; pos1[1] = pos2[1] = tl[1]; for (y = 0; y < h; y++, pos1[1] += ph, pos2[1] += ph) { src_rect.expand(transform(pos1, &dist, &along)); UPDATE_DIST; src_rect.expand(transform(pos2, &dist, &along)); UPDATE_DIST; } // look along the diagonals const int max_wh(std::max(w,h)); const Real inc_x((br[0]-tl[0])/max_wh),inc_y((br[1]-tl[1])/max_wh); pos1[0] = pos2[0] = tl[0]; pos1[1] = tl[1]; pos2[1] = br[1]; for (x = 0; x < max_wh; x++, pos1[0] += inc_x, pos2[0] = pos1[0], pos1[1]+=inc_y, pos2[1]-=inc_y) { src_rect.expand(transform(pos1, &dist, &along)); UPDATE_DIST; src_rect.expand(transform(pos2, &dist, &along)); UPDATE_DIST; } #if 0 // look at each blinepoint std::vector<synfig::BLinePoint>::const_iterator iter; for (iter=bline.begin(); iter!=bline.end(); iter++) src_rect.expand(transform(iter->get_vertex()+origin, &dist, &along)); UPDATE_DIST; #endif Point src_tl(src_rect.get_min()); Point src_br(src_rect.get_max()); Vector ab((end_point - start_point).norm()); Angle::tan ab_angle(ab[1], ab[0]); Real used_length = max_along - min_along; Real render_width = max_dist - min_dist; int src_w = (abs(used_length*Angle::cos(ab_angle).get()) + abs(render_width*Angle::sin(ab_angle).get())) / abs(pw); int src_h = (abs(used_length*Angle::sin(ab_angle).get()) + abs(render_width*Angle::cos(ab_angle).get())) / abs(ph); Real src_pw((src_br[0] - src_tl[0]) / src_w); Real src_ph((src_br[1] - src_tl[1]) / src_h); if (src_pw > abs(pw)) { src_w = int((src_br[0] - src_tl[0]) / abs(pw)); src_pw = (src_br[0] - src_tl[0]) / src_w; } if (src_ph > abs(ph)) { src_h = int((src_br[1] - src_tl[1]) / abs(ph)); src_ph = (src_br[1] - src_tl[1]) / src_h; } #define MAXPIX 10000 if (src_w > MAXPIX) src_w = MAXPIX; if (src_h > MAXPIX) src_h = MAXPIX; // this is an attempt to remove artifacts around tile edges - the // cubic interpolation uses at most 2 pixels either side of the // target pixel, so add an extra 2 pixels around the tile on all // sides src_tl -= (Point(src_pw,src_ph)*2); src_br += (Point(src_pw,src_ph)*2); src_w += 4; src_h += 4; src_pw = (src_br[0] - src_tl[0]) / src_w; src_ph = (src_br[1] - src_tl[1]) / src_h; // set up a renddesc for the context to render RendDesc src_desc(renddesc); //src_desc.clear_flags(); src_desc.set_tl(src_tl); src_desc.set_br(src_br); src_desc.set_wh(src_w, src_h); // New expanded renddesc values const double wpw=src_desc.get_pw(); const double wph=src_desc.get_ph(); const double wtlx=src_desc.get_tl()[0]; const double wtly=src_desc.get_tl()[1]; // render the context onto a new surface cairo_surface_t* csource, *cresult; csource=cairo_surface_create_similar(cairo_get_target(cr),CAIRO_CONTENT_COLOR_ALPHA, src_w, src_h); cresult=cairo_surface_create_similar(cairo_get_target(cr),CAIRO_CONTENT_COLOR_ALPHA, w, h); cairo_t *subcr=cairo_create(csource); cairo_scale(subcr, 1/wpw, 1/wph); cairo_translate(subcr, -wtlx, -wtly); if(!context.accelerated_cairorender(subcr,quality,src_desc,&stageone)) return false; // don't needed anymore cairo_destroy(subcr); //access to pixels CairoSurface source(csource); source.map_cairo_image(); CairoSurface result(cresult); result.map_cairo_image(); float u,v; Point pos, tmp; if(quality<=4) // CUBIC for(y=0,pos[1]=tl[1];y<h;y++,pos[1]+=ph) { for(x=0,pos[0]=tl[0];x<w;x++,pos[0]+=pw) { tmp=transform(pos); u=(tmp[0]-src_tl[0])/src_pw; v=(tmp[1]-src_tl[1])/src_ph; if(u<0 || v<0 || u>=src_w || v>=src_h || isnan(u) || isnan(v)) result[y][x]=CairoColor(context.get_color(tmp)).premult_alpha(); else result[y][x]=source.cubic_sample_cooked(u,v); } if((y&31)==0 && cb && !stagetwo.amount_complete(y,h)) return false; } else if (quality<=6) // INTERPOLATION_LINEAR for(y=0,pos[1]=tl[1];y<h;y++,pos[1]+=ph) { for(x=0,pos[0]=tl[0];x<w;x++,pos[0]+=pw) { tmp=transform(pos); u=(tmp[0]-src_tl[0])/src_pw; v=(tmp[1]-src_tl[1])/src_ph; if(u<0 || v<0 || u>=src_w || v>=src_h || isnan(u) || isnan(v)) result[y][x]=CairoColor(context.get_color(tmp)).premult_alpha(); else result[y][x]=source.linear_sample_cooked(u,v); } if((y&31)==0 && cb && !stagetwo.amount_complete(y,h)) return false; } else // NEAREST_NEIGHBOR for(y=0,pos[1]=tl[1];y<h;y++,pos[1]+=ph) { for(x=0,pos[0]=tl[0];x<w;x++,pos[0]+=pw) { tmp=transform(pos); u=(tmp[0]-src_tl[0])/src_pw; v=(tmp[1]-src_tl[1])/src_ph; if(u<0 || v<0 || u>=src_w || v>=src_h || isnan(u) || isnan(v)) result[y][x]=CairoColor(context.get_color(tmp)).premult_alpha(); else result[y][x]=source[floor_to_int(v)][floor_to_int(u)]; } if((y&31)==0 && cb && !stagetwo.amount_complete(y,h)) return false; } result.unmap_cairo_image(); source.unmap_cairo_image(); cairo_surface_destroy(csource); // Now paint it on the context cairo_save(cr); cairo_translate(cr, tl[0], tl[1]); cairo_scale(cr, pw, ph); cairo_set_source_surface(cr, cresult, 0, 0); cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE); cairo_paint(cr); cairo_restore(cr); cairo_surface_destroy(cresult); // Mark our progress as finished if(cb && !cb->amount_complete(10000,10000)) return false; return true; }
bool CurveWarp::accelerated_render(Context context,Surface *surface,int quality, const RendDesc &renddesc, ProgressCallback *cb)const { Point start_point=param_start_point.get(Point()); Point end_point=param_end_point.get(Point()); SuperCallback stageone(cb,0,9000,10000); SuperCallback stagetwo(cb,9000,10000,10000); int x,y; const Real pw(renddesc.get_pw()),ph(renddesc.get_ph()); Point tl(renddesc.get_tl()); Point br(renddesc.get_br()); const int w(renddesc.get_w()); const int h(renddesc.get_h()); // find a bounding rectangle for the context we need to render // todo: find a better way of doing this - this way doesn't work Rect src_rect(transform(tl)); Point pos1, pos2; Real dist, along; Real min_dist(999999), max_dist(-999999), min_along(999999), max_along(-999999); #define UPDATE_DIST \ if (dist < min_dist) min_dist = dist; \ if (dist > max_dist) max_dist = dist; \ if (along < min_along) min_along = along; \ if (along > max_along) max_along = along // look along the top and bottom edges pos1[0] = pos2[0] = tl[0]; pos1[1] = tl[1]; pos2[1] = br[1]; for (x = 0; x < w; x++, pos1[0] += pw, pos2[0] += pw) { src_rect.expand(transform(pos1, &dist, &along)); UPDATE_DIST; src_rect.expand(transform(pos2, &dist, &along)); UPDATE_DIST; } // look along the left and right edges pos1[0] = tl[0]; pos2[0] = br[0]; pos1[1] = pos2[1] = tl[1]; for (y = 0; y < h; y++, pos1[1] += ph, pos2[1] += ph) { src_rect.expand(transform(pos1, &dist, &along)); UPDATE_DIST; src_rect.expand(transform(pos2, &dist, &along)); UPDATE_DIST; } // look along the diagonals const int max_wh(std::max(w,h)); const Real inc_x((br[0]-tl[0])/max_wh),inc_y((br[1]-tl[1])/max_wh); pos1[0] = pos2[0] = tl[0]; pos1[1] = tl[1]; pos2[1] = br[1]; for (x = 0; x < max_wh; x++, pos1[0] += inc_x, pos2[0] = pos1[0], pos1[1]+=inc_y, pos2[1]-=inc_y) { src_rect.expand(transform(pos1, &dist, &along)); UPDATE_DIST; src_rect.expand(transform(pos2, &dist, &along)); UPDATE_DIST; } #if 0 // look at each blinepoint std::vector<synfig::BLinePoint>::const_iterator iter; for (iter=bline.begin(); iter!=bline.end(); iter++) src_rect.expand(transform(iter->get_vertex()+origin, &dist, &along)); UPDATE_DIST; #endif Point src_tl(src_rect.get_min()); Point src_br(src_rect.get_max()); Vector ab((end_point - start_point).norm()); Angle::tan ab_angle(ab[1], ab[0]); Real used_length = max_along - min_along; Real render_width = max_dist - min_dist; int src_w = (abs(used_length*Angle::cos(ab_angle).get()) + abs(render_width*Angle::sin(ab_angle).get())) / abs(pw); int src_h = (abs(used_length*Angle::sin(ab_angle).get()) + abs(render_width*Angle::cos(ab_angle).get())) / abs(ph); Real src_pw((src_br[0] - src_tl[0]) / src_w); Real src_ph((src_br[1] - src_tl[1]) / src_h); if (src_pw > abs(pw)) { src_w = int((src_br[0] - src_tl[0]) / abs(pw)); src_pw = (src_br[0] - src_tl[0]) / src_w; } if (src_ph > abs(ph)) { src_h = int((src_br[1] - src_tl[1]) / abs(ph)); src_ph = (src_br[1] - src_tl[1]) / src_h; } #define MAXPIX 10000 if (src_w > MAXPIX) src_w = MAXPIX; if (src_h > MAXPIX) src_h = MAXPIX; // this is an attempt to remove artifacts around tile edges - the // cubic interpolation uses at most 2 pixels either side of the // target pixel, so add an extra 2 pixels around the tile on all // sides src_tl -= (Point(src_pw,src_ph)*2); src_br += (Point(src_pw,src_ph)*2); src_w += 4; src_h += 4; src_pw = (src_br[0] - src_tl[0]) / src_w; src_ph = (src_br[1] - src_tl[1]) / src_h; // set up a renddesc for the context to render RendDesc src_desc(renddesc); src_desc.clear_flags(); src_desc.set_tl(src_tl); src_desc.set_br(src_br); src_desc.set_wh(src_w, src_h); // render the context onto a new surface Surface source; source.set_wh(src_w,src_h); if(!context.accelerated_render(&source,quality,src_desc,&stageone)) return false; float u,v; Point pos, tmp; surface->set_wh(w,h); surface->clear(); if(quality<=4) // CUBIC for(y=0,pos[1]=tl[1];y<h;y++,pos[1]+=ph) { for(x=0,pos[0]=tl[0];x<w;x++,pos[0]+=pw) { tmp=transform(pos); u=(tmp[0]-src_tl[0])/src_pw; v=(tmp[1]-src_tl[1])/src_ph; if(u<0 || v<0 || u>=src_w || v>=src_h || isnan(u) || isnan(v)) (*surface)[y][x]=context.get_color(tmp); else (*surface)[y][x]=source.cubic_sample(u,v); } if((y&31)==0 && cb && !stagetwo.amount_complete(y,h)) return false; } else if (quality<=6) // INTERPOLATION_LINEAR for(y=0,pos[1]=tl[1];y<h;y++,pos[1]+=ph) { for(x=0,pos[0]=tl[0];x<w;x++,pos[0]+=pw) { tmp=transform(pos); u=(tmp[0]-src_tl[0])/src_pw; v=(tmp[1]-src_tl[1])/src_ph; if(u<0 || v<0 || u>=src_w || v>=src_h || isnan(u) || isnan(v)) (*surface)[y][x]=context.get_color(tmp); else (*surface)[y][x]=source.linear_sample(u,v); } if((y&31)==0 && cb && !stagetwo.amount_complete(y,h)) return false; } else // NEAREST_NEIGHBOR for(y=0,pos[1]=tl[1];y<h;y++,pos[1]+=ph) { for(x=0,pos[0]=tl[0];x<w;x++,pos[0]+=pw) { tmp=transform(pos); u=(tmp[0]-src_tl[0])/src_pw; v=(tmp[1]-src_tl[1])/src_ph; if(u<0 || v<0 || u>=src_w || v>=src_h || isnan(u) || isnan(v)) (*surface)[y][x]=context.get_color(tmp); else (*surface)[y][x]=source[floor_to_int(v)][floor_to_int(u)]; } if((y&31)==0 && cb && !stagetwo.amount_complete(y,h)) return false; } // Mark our progress as finished if(cb && !cb->amount_complete(10000,10000)) return false; return true; }
void Window::Draw() { if (!visible) return; if (width <= 0 || height <= 0) return; if (x < -width || x > DisplayUi->GetWidth() || y < -height || y > DisplayUi->GetHeight()) return; if (windowskin) { if (width > 4 && height > 4 && (back_opacity * opacity / 255 > 0)) { if (background_needs_refresh) RefreshBackground(); if (animation_frames > 0) { int ianimation_count = (int)animation_count; Rect src_rect(0, height / 2 - ianimation_count, width, ianimation_count * 2); background->BlitScreen(x, y + src_rect.y, src_rect); } else { background->BlitScreen(x, y); } } if (width > 0 && height > 0 && opacity > 0) { if (frame_needs_refresh) RefreshFrame(); if (animation_frames > 0) { int ianimation_count = (int)animation_count; if (ianimation_count > 8) { Rect src_rect(0, height / 2 - ianimation_count, 8, ianimation_count * 2 - 16); frame_left->BlitScreen(x, y + 8 + src_rect.y, src_rect); frame_right->BlitScreen(x + width - 8, y + 8 + src_rect.y, src_rect); frame_up->BlitScreen(x, y + height / 2 - ianimation_count); frame_down->BlitScreen(x, y + height / 2 + ianimation_count - 8); } else { frame_up->BlitScreen(x, y + height / 2 - ianimation_count, Rect(0, 0, width, ianimation_count)); frame_down->BlitScreen(x, y + height / 2, Rect(0, 8 - ianimation_count, width, ianimation_count)); } } else { frame_up->BlitScreen(x, y); frame_down->BlitScreen(x, y + height - 8); frame_left->BlitScreen(x, y + 8); frame_right->BlitScreen(x + width - 8, y + 8); } } if (width > 16 && height > 16 && cursor_rect.width > 4 && cursor_rect.height > 4 && animation_frames == 0) { if (cursor_needs_refresh) RefreshCursor(); Rect src_rect( -min(cursor_rect.x + border_x, 0), -min(cursor_rect.y + border_y, 0), min(cursor_rect.width, width - cursor_rect.x + border_x), min(cursor_rect.height, height - cursor_rect.y + border_y) ); if (cursor_frame < 16) cursor1->BlitScreen(x + cursor_rect.x + border_x, y + cursor_rect.y + border_y, src_rect); else cursor2->BlitScreen(x + cursor_rect.x + border_x, y + cursor_rect.y + border_y, src_rect); } } if (contents) { if (width > 2 * border_x && height > 2 * border_y && -ox < width - 2 * border_x && -oy < height - 2 * border_y && contents_opacity > 0 && animation_frames == 0) { Rect src_rect(-min(-ox, 0), -min(-oy, 0), min(width - 2 * border_x, width - 2 * border_x + ox), min(height - 2 * border_y, height - 2 * border_y + oy)); contents_screen->SetOpacityEffect(contents_opacity); contents_screen->BlitScreen(max(x + border_x, x + border_x - ox), max(y + border_y, y + border_y - oy), src_rect); } } if (pause && pause_frame > 16 && animation_frames <= 0) { Rect src_rect(40, 16, 16, 8); windowskin_screen->BlitScreen(x + width / 2 - 8, y + height - 8, src_rect); } if (up_arrow) { Rect src_rect(40, 8, 16, 8); windowskin_screen->BlitScreen(x + width / 2 - 8, y, src_rect); } if (down_arrow) { Rect src_rect(40, 16, 16, 8); windowskin_screen->BlitScreen(x + width / 2 - 8, y + height - 8, src_rect); } if (animation_frames > 0) { // Open/Close Animation animation_frames -= 1; animation_count += animation_increment; if (closing && animation_frames <= 0) { visible = false; closing = false; } } }