As others have already pointed out, cleardevice() is unnecessary and can be omitted, as everything is always redrawn anyway. If it still flickers, you would need double buffers and prepare the complete image in memory first.
The cause of the black blocks is to be found in the EasyX function loadimage() and not in the function putimage_alpha().
Although the EasyX function loadimage() can in principle load a png with alpha channel and even rescale the image while retaining the alpha channel, the quality is not satisfactory. For comparison, I tested the function load_image_with_transparency() with GDI+ and found that the effort is considerably higher, but the result is much better.
Here is a comparison of the functions:
IMAGE load_image_with_transparency1(const wchar_t* filename, int width, int height)
{
IMAGE img;
loadimage(&img, filename, width, height); return img;
}
IMAGE load_image_with_transparency2(const wchar_t* filename, int width, int height)
{
GDIPlusBitmap gdiPlusBitmap(filename, width, height);
HBITMAP hBitmap = gdiPlusBitmap.getHBitmap();
IMAGE img;
getimage(&img, 0, 0, width, height);
HDC hdcDest = GetImageHDC(&img);
HDC hdcMem = CreateCompatibleDC(hdcDest);
SelectObject(hdcMem, hBitmap);
BitBlt(hdcDest, 0, 0, width, height, hdcMem, 0, 0, SRCCOPY);
DeleteDC(hdcMem);
return img;
}
Whereby the GDIPlusBitmap is packaged as an object to keep it convenient and readable:
#include <memory>
class GDIPlusBitmap {
public:
GDIPlusBitmap(const wchar_t* filename, int width, int height) {
bitmap.reset(new Bitmap(filename));
scaledBitmap.reset(new Bitmap(width, height));
graphics.reset(Graphics::FromImage(scaledBitmap.get()));
graphics->SetInterpolationMode(InterpolationModeHighQualityBicubic);
graphics->DrawImage(bitmap.get(), 0, 0, width, height);
scaledBitmap->GetHBITMAP(Color(0, 0, 0, 0), &hBitmap);
}
~GDIPlusBitmap() {
if (hBitmap) {
DeleteObject(hBitmap);
}
}
HBITMAP getHBitmap() const {
return hBitmap;
}
private:
std::unique_ptr<Bitmap> bitmap;
std::unique_ptr<Bitmap> scaledBitmap;
std::unique_ptr<Graphics> graphics;
HBITMAP hBitmap = nullptr;
};
// edit1:
EasyX already uses double buffering when BeginBatchDraw() and EndBatchDraw() are used. Alternative implementations of the drawing functions may undermine the system, which could make the use of a separate buffer system useful. BeginBatchDraw() and EndBatchDraw() are sufficient and easy to use for many applications with EasyX. For more performance-intensive applications, however, more powerful graphics frameworks such as SFML or SDL are required. These offer extensive functions for game development and graphical applications, including advanced buffering techniques.
// edit2:
In the given code, both FlushBatchDraw() and EndBatchDraw() are called for each run, which does not seem to make sense. FlushBatchDraw() would be sufficient here.
FlushBatchDraw();