ObjReader Community

GDImage => The concept => Topic started by: Patrice Terrier on April 13, 2024, 07:32:58 pm

Title: Tutor_19 "Circular text" (C++ VS2022 GDImage64 tutorial)
Post by: Patrice Terrier on April 13, 2024, 07:32:58 pm
About Tutor_19
Its purpose is to create one single or multiple circular text objects to use for logo or animaion.

It uses a new API named ZD_CreateCircularTextBitmap
using 7 parameters:
WCHAR* zText, the unicode string to create the circular text from.
WCHAR* zFont, the unicode string for the font to use (could be a .ttf private font).
long fontSize, the font size height.
long fontSyle, for example FontStyleBold.
long radius, the inner radius of the circular text.
DWORD ColrARGB, the ARGB color to use.
float step, the distance between each character.

The function returns a BITMAP handle that can be used by the ZD_DrawBitmapToCtrl API.

The AngleRotation procedure is using direct call to the GDIPLUS FLAT API to compute the correct rotation angle.

The window itself works in DWM transparent composited mode using the GDImage ZI_DwmEnable API.

(http://www.objreader.com/download/images/Tutor_19.jpg)


Title: D2D "Circular text"
Post by: Patrice Terrier on April 14, 2024, 06:38:01 pm
As a matter of comparison here is the code to draw a circular text using the D2D API

Code: [Select]
#include <windows.h>
#include <d2d1.h>
#include <dwrite.h>
#include <cmath>

#pragma comment(lib, "d2d1.lib")
#pragma comment(lib, "dwrite.lib")

constexpr auto IDI_ICON1     = 101;

// Global pointers for Direct2D and DirectWrite interfaces
ID2D1Factory* pD2DFactory = nullptr;
ID2D1HwndRenderTarget* pRenderTarget = nullptr;
ID2D1SolidColorBrush* pBrush = nullptr;
IDWriteFactory* pDWriteFactory = nullptr;
IDWriteTextFormat* pTextFormat = nullptr;

static void Initialize() {
    D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, &pD2DFactory);
    DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory), reinterpret_cast<IUnknown**>(&pDWriteFactory));
}

static void CreateGraphicsResources(HWND hwnd) {
    if (!pRenderTarget) {
        RECT rc;
        GetClientRect(hwnd, &rc);
        D2D1_SIZE_U size = D2D1::SizeU(rc.right, rc.bottom);
        pD2DFactory->CreateHwndRenderTarget(D2D1::RenderTargetProperties(), D2D1::HwndRenderTargetProperties(hwnd, size), &pRenderTarget);

        pRenderTarget->CreateSolidColorBrush(D2D1::ColorF(0xFF037BFA), &pBrush);

        pDWriteFactory->CreateTextFormat(
            L"Segoe GUI emoji",
            nullptr,
            DWRITE_FONT_WEIGHT_BOLD,
            DWRITE_FONT_STYLE_NORMAL,
            DWRITE_FONT_STRETCH_NORMAL,
            50.0f,
            L"", //locale
            &pTextFormat
        );

        pTextFormat->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_CENTER);
        pTextFormat->SetParagraphAlignment(DWRITE_PARAGRAPH_ALIGNMENT_CENTER);
    }
}

static void DiscardGraphicsResources() {
    if (pBrush) pBrush->Release();
    if (pRenderTarget) pRenderTarget->Release();
    if (pTextFormat) pTextFormat->Release();
    pBrush = nullptr;
    pRenderTarget = nullptr;
    pTextFormat = nullptr;
}

static void OnPaint(HWND hwnd) {
    PAINTSTRUCT ps;
    BeginPaint(hwnd, &ps);
    CreateGraphicsResources(hwnd);
    pRenderTarget->BeginDraw();
    pRenderTarget->Clear(D2D1::ColorF(D2D1::ColorF::White));
    D2D1_SIZE_F size = pRenderTarget->GetSize();

    const WCHAR* text = L"This is a Circular text using the D2D API.";
    const float radius = 200.0f;
    const D2D1_POINT_2F center = D2D1::Point2F(size.width / 2, size.height / 2);
    const size_t length = wcslen(text);
    const float angleStep = 360.0f / static_cast<float>(length);

    for (size_t i = 0; i < length; ++i) {
        WCHAR letter[2] = { text[i], 0 };

        float angle = DegreesToRadians(angleStep * i);
        D2D1_POINT_2F position = {
            center.x + cos(angle) * radius,
            center.y + sin(angle) * radius
        };

        D2D1_MATRIX_3X2_F rotation = D2D1::Matrix3x2F::Rotation(angleStep * i + 90, position);
        pRenderTarget->SetTransform(rotation);

        pRenderTarget->DrawText(
            letter,
            ARRAYSIZE(letter),
            pTextFormat,
            D2D1::RectF(position.x - 20, position.y - 20, position.x + 20, position.y + 20),
            pBrush
        );

        pRenderTarget->SetTransform(D2D1::Matrix3x2F::Identity());
    }

    HRESULT hr = pRenderTarget->EndDraw();
    if (FAILED(hr) || hr == D2DERR_RECREATE_TARGET) {
        DiscardGraphicsResources();
    }
    EndPaint(hwnd, &ps);
}

static LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
    switch (uMsg) {
        case WM_DESTROY:
            PostQuitMessage(0);
            return 0;

        case WM_PAINT:
            OnPaint(hwnd);
            return 0;
    }
    return DefWindowProc(hwnd, uMsg, wParam, lParam);
}

int WINAPI wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPWSTR lpCmdLine, _In_ int nCmdShow) {
    Initialize();

    // Register the window class
    const wchar_t CLASS_NAME[] = L"Sample Window Class";
    WNDCLASS wc = {};
    wc.lpfnWndProc = WindowProc;
    wc.hInstance = hInstance;
    wc.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_ICON1));
    wc.lpszClassName = CLASS_NAME;

    RegisterClass(&wc);

    // Create the window
    HWND hwnd = CreateWindowEx(
        0,
        CLASS_NAME,
        L"Circular Text with Direct2D",
        WS_OVERLAPPEDWINDOW,
        CW_USEDEFAULT, CW_USEDEFAULT, 600, 600,
        nullptr,
        nullptr,
        hInstance,
        nullptr
    );

    if (hwnd == nullptr) {
        return 0;
    }

    ShowWindow(hwnd, nCmdShow);
    UpdateWindow(hwnd);

    // Run the message loop
    MSG msg = {};
    while (GetMessage(&msg, nullptr, 0, 0)) {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    DiscardGraphicsResources();
    if (pD2DFactory) pD2DFactory->Release();
    if (pDWriteFactory) pDWriteFactory->Release();

    return 0;
}
Title: Re: Tutor_19 "Circular text" (C++ VS2022 GDImage64 tutorial)
Post by: Patrice Terrier on April 20, 2024, 10:24:39 am
And here is the PowerBASIC translation using the new GDImage.dll 32-bit version 7.01