Пример #1
0
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;
        }
    }
}
Пример #2
0
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");
	}
}
Пример #3
0
 virtual void clear(const GColor& color) {
     src_rect(fDevice, fIBounds, color.premulToPixel());
 }
Пример #4
0
// 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;
}
Пример #5
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);
}
Пример #6
0
	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;
						
					}
					
				}
				
			}
			
		}
		
	}
Пример #7
0
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;
}
Пример #8
0
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;
}
Пример #9
0
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;
		}
	}
}