惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Scott Helme
Scott Helme
Cisco Talos Blog
Cisco Talos Blog
I
Intezer
P
Privacy International News Feed
T
Threatpost
P
Palo Alto Networks Blog
Cyberwarzone
Cyberwarzone
V
Vulnerabilities – Threatpost
L
Lohrmann on Cybersecurity
C
CERT Recently Published Vulnerability Notes
C
Cisco Blogs
Simon Willison's Weblog
Simon Willison's Weblog
C
Cyber Attacks, Cyber Crime and Cyber Security
T
Tenable Blog
Know Your Adversary
Know Your Adversary
量子位
T
The Exploit Database - CXSecurity.com
G
Google Developers Blog
N
Netflix TechBlog - Medium
酷 壳 – CoolShell
酷 壳 – CoolShell
C
Cybersecurity and Infrastructure Security Agency CISA
罗磊的独立博客
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
腾讯CDC
I
InfoQ
The Hacker News
The Hacker News
S
Schneier on Security
Recorded Future
Recorded Future
C
CXSECURITY Database RSS Feed - CXSecurity.com
Latest news
Latest news
T
Threat Research - Cisco Blogs
Security Latest
Security Latest
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
S
Securelist
AWS News Blog
AWS News Blog
NISL@THU
NISL@THU
L
LangChain Blog
GbyAI
GbyAI
T
Tor Project blog
Last Week in AI
Last Week in AI
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
F
Fortinet All Blogs
Recent Announcements
Recent Announcements
爱范儿
爱范儿
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
博客园 - Franky
P
Proofpoint News Feed
G
GRAHAM CLULEY
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
Martin Fowler
Martin Fowler

Все публикации подряд на Хабре

Ловим музу за клавиатуру: как айтишнику стать автором Что умеет Midjourney в 2026? Мой немного грустный разбор этого шикарного инструмента Никто не любит писать тесты, но ИИ может исправить это IPv8 выглядит как мечта. Поэтому почти наверняка не взлетит Производители вернули в продажу материнки с DDR3. Что происходит? Управление агентом с телефона через Telegram теперь в KodaCode От координации к лидерству: как меняется роль руководителя разработки Я сделала родителям бизнес вместо пенсии: зарабатываем 70 тысяч, мама не даёт продать В три раза быстрее приемка товара и оптимизация трудозатрат на 73%: как «РСТ-Инвент» помог Gulliver Group ИИ-шечный мир победил? О влиянии искусственного интеллекта на игропром Кремль снижает давление на Телеграмм пока Европа строит интернет по паспорту Как CEO, CTO и CIO за 8 часов собрали ИИ-директора, который умеет держать позицию под давлением Как (не) потерять домен за выходные Вместо 8 разных VPS: как я организовал практику студентам на одном сервере Почему твой Open Source проект не замечают? R&D: искусство управления неопределенностью в разработке AI-дефляция: вакансий для разработчиков больше, а рост зарплат — худший за 15 лет Мы отдали управление роботами OpenClaw. Что из этого вышло Галактический ID: система идентификации для всех форм разумной жизни Шесть основ бизнес-анализа: начинаем с вопроса «Кто в игре?» Код-ревью, в котором дело не в коде Данные переехали. Команда — нет Системной подход к сдаче OSWE в 2025 Почему комната управления реактором покрашена в цвет морской пены 4 YAML-файла вместо PySpark: как аналитикам строить пайплайны без разработчиков LLM-агент для поиска свободных доменов: автоматизируем подбор Когда, зачем и как правильно начинать новую сессию в Claude Code? Как я заставил нейросеть писать макросы для FreeCAD Анатомия ИИ‑агента для подбора персонала. От тысячи резюме к топ‑10 за минуты Опыт разработчика как экономика внимания Автономность как точка невозврата: кто будет субъектом в цифровом будущем Обучение ИИ в «диких» условиях: как рутинные действия превращаются в датасеты Как измерить LLM для задач кибербеза: обзор открытых бенчмарков Где хранить код? Сравнение GitHub, GitLab и Bitbucket Математика объясняет, почему нормальное распределение встречается повсюду Почему ваш FinOps не работает: 12 тезисов от практиков Как подписать проектную документацию УКЭП с использованием бесплатных лицензий Pilot Адаптивное администрирование Sigla Vision Я грузил уран в бочки, а потом 20 лет строил ИТ в атомной отрасли Чем позвонить с Эвереста? История и обзор спутниковой связи. Часть 2 Как языковая модель помогает контролировать качество инструктажей по охране труда в металлургии Как не передать на desktop свой IP в РКН Анатомия SAP Privileges: как устроено управление правами в macOS MoneyDev: Сказка про три главных слова Обновлённый токенизатор видео K-VAE 2.0 от Сбера Как сделать диспетчеризацию дома на 1284 квартиры почти бесплатно Как мы разогнали железную дорогу Мы дали агентам рутину. Теперь надо решить — что делать с освободившимся временем Токсичный контент, промпт-хакинг и защита ИИ — всё о Guardrails для LLM Умный город начинается с точного взгляда: как «Фалькон Тех» меняет пространство к лучшему Навайбкодил приложение для анализа графов Почему Дюну так интересно читать? Упрощаем работу с рутиной или как стать Гендальфом Белым Деконструкция Go: CPU, RAM и что там происходит. Go Assembler база. Часть 1.1 Какие профессии исчезнут из-за ИИ, а какие появятся? И что с этим делать Как мы построили IT-отдел, где хочется расти: архитектурные встречи, прозрачные метрики и книжные подарки Rufler: Делаем из Claude Code автономный рой через один YAML-конфиг Sing-box и белый список приложений Как построить надёжный обмен сообщениями в микросервисах: лучшие практики для enterprise OpenAI строит MLM-пирамиду, а McKinsey и Accenture помогают ей в этом Дом, который не построил Фишер (Часть 2) «Сверхзвуковой математик» против «Вдумчивого логиста»: битва алгоритмов 3D-упаковки Мультимодальные модели – грубый и дорогой инструмент Разговоры ничего не стоят. Код тоже Проверки физических лиц: с кого начнет ФНС Топ-10 бесплатных нейросетей для создания видео в 2026 году Первые слои кода: как наши решения сегодня определяют архитектуру ИИ на десятилетия Разработка нового статического анализатора: PVS-Studio JavaScript Поиск уязвимостей ПО: базовый минимум или роскошный максимум Почему оценка персонала не работает как инструмент управления Как мы разработали ИИ-ассистента и сократили рутину продуктовой команды на 50% Как я ушел из найма, нажарил косточек и продал на маркетплейсах на 168 млн в год Когда 1С:ERP уже внедрена, а нормального производственного плана всё ещё нет Как я сделал Claude мультимодальным, подключив к нему Qwen Omni Как приглашение на вакансию мечты превращается в атаку Infrastructure as Code: философия и лучшие практики IaC Тестируем Yandex Code Assistant на задаче, в которой нужно хранить секреты nxs-universal-chart v3.0: новое поколение универсального Helm-чарта Callback Injection: Техника, которая отправила Microsoft Defender в глухой нокаут «Все идеи на стол»: митап как способ вывести проект из тупика Сегодня я узнал нечто новое о GPU благодаря багу в своей игре Как заставить LLM ̶ ̶г̶а̶л̶л̶ю̶ ̶ эволюционировать Карта событий как фундамент аналитики: практический кейс для E-commerce Что выбрать для AI: x86, ARM или RISC-V? Дайджест железа за март Роль соматических мутаций в развитии аутоиммунных заболеваний: путь к избирательной терапии Mythos от Anthropic — тревожный сигнал для всех, а не только для банков Guardrails для LLM на Java: как приручить промпт‑инъекции и токсичные ответы Green-VLA: как мы собрали VLA-модель для реального антропоморфного робота и не потеряли обобщение Финансовая гонка вооружений: почему умные люди добровольно в ней участвуют Эра ИИ-агентов наступила: выбираем лучшего цифрового сотрудника # Практический опыт внедрения WinCC Redundancy на производственном предприятии Сделал MVP за 3 дня, а потом неделю прикручивал оплату. Оно того стоило? Физика против Маска: почему Starship V3 может оказаться ещё одной катастрофой Нефть Венесуэлы: крупнейшие запасы в мире, но не крупнейшая нефтяная держава JPA 4. Переосмысление Hibernate Почему зеркальная фотокамера Nikon D5 десятилетней давности идеально подошла для миссии «Артемида-2» Проект «Уровень-Спутник» или как мы сделали платформу для гидрологов «Замедлиться, чтобы ускориться»: почему ИИ повышает цену ошибок в требованиях и архитектуре Как с нуля поднять трафик IT-компании на 1657% при бюджете 55 тыс. и выжить Pixel-perfect Downsampling — идеальная отрисовка 50 миллионов точек без потерь
Direct 2D #9 О текстурах
Johnny_Depp · 2026-05-04 · via Все публикации подряд на Хабре

Уровень сложностиПростой

Время на прочтение8 мин

Охват и читатели37

Туториал

Здравствуйте! После разбора WIC начинается работа с данными, для которой он как раз и пригодится.

Сразу скажу, что спрайты будут в следующей статье, так как понадобится немного залезть в Direct3D, рассказать про DXGI-цепочки и всё что будет важным для понимания этих вещей. Поэтому эта статья не очень длинная, но касается текстур - а текстуры, к слову, будут использоваться спрайтами.

Кстати, о разнице между спрайтами и текстурой:

Текстура - после того как вы декодировали файл с изображением и конвертировали его в нужный пиксельный формат, вы можете передать данные в видеопамять (такие данные в видеопамяти - это текстура).

Спрайт - ссылается на текстуру и содержит описание того, как её отрисовать, и т.п. То есть если нужно отрисовать текстуру по-разному, вы прибегаете к спрайтам.

Просто напоминаю, что пиксельные форматы описывают хранение одного пикселя. Вот весь их список в Direct2D.

Ну а теперь - процесс получения текстуры. Как я говорил ранее, необходимо декодировать файл с изображением и конвертировать его в один из пиксельных форматов. Так как это было в статье #8, здесь будет не полный код:

1. Получаем доступ к фабрике WIC

IWICImagingFactory* pWicFactory;
CoCreateInstance(CLSID_WICImagingFactory, ...);

2. Декодируем файл

IWICBitmapDecoder* pDecoder;
pWicFactory->CreateDecoderFromFilename(L"image.png", ..., &pDecoder);

3. Извлекаем кадр

IWICBitmapFrameDecode* pFrame;
pDecoder->GetFrame(0, &pFrame);

4. Конвертируем в понятный Direct2D формат

IWICFormatConverter* pConverter;
pWicFactory->CreateFormatConverter(&pConverter);
pConverter->Initialize(pFrame, GUID_WICPixelFormat32bppPBGRA, ...);

Теперь создание текстуры:

ID2D1Bitmap* pBitmap;
pRenderTarget->CreateBitmapFromWicBitmap(pConverter, nullptr, &pBitmap);

После этого текстура находится в видеопамяти. Теперь о том, что можно сделать с битмапом:

  1. D2D1_SIZE_F GetSize() - возвращает размеры битмапа с учётом DPI.

  2. D2D1_SIZE_U GetPixelSize() - возвращает размеры без учёта DPI

  3. D2D1_PIXEL_FORMAT GetPixelFormat() - возвращает формат пикселей.

  4. void GetDpi(FLOAT* dpiX, FLOAT* dpiY) - возвращает значения DPI, с которыми был создан битмап.

  5. HRESULT CopyFromMemory(const D2D1_RECT_U* dstRect, const void* srcData, UINT32 pitch) - копирует пиксели из памяти в битмап. dstRect - область в битмапе, куда копируем (если nullptr, то во весь битмап). srcData - указатель на данные в системной памяти, pitch - ширина строки данных в байтах.

  6. HRESULT CopyFromBitmap(const D2D1_POINT_2U* destPoint, ID2D1Bitmap* bitmap, const D2D1_RECT_U* srcRect) - копирует пиксели из другого битмапа в текущий. Аргументы аналогичны CopyFromMemory.

  7. HRESULT CopyFromRenderTarget(const D2D1_POINT_2U* destPoint, ID2D1RenderTarget* renderTarget, const D2D1_RECT_U* srcRect) - копирует пиксели с рендер-таргета. Аргументы аналогичны CopyFromBitmap.

  8. HRESULT CreateBitmapBrush(ID2D1Bitmap* bitmap, const D2D1_BITMAP_BRUSH_PROPERTIES* bitmapBrushProperties, const D2D1_BRUSH_PROPERTIES* brushProperties, ID2D1BitmapBrush** bitmapBrush) - создаёт кисть из текстуры. bitmapBrushProperties - свойства кисти (можно передать nullptr для значений по умолчанию), brushProperties - общие свойства (непрозрачность, матрица трансформации и т.п.).

Отрисовку разберём, когда дойдём до этого пункта. К слову, начиная с Windows 8 существует также интерфейс ID2D1Bitmap1, в котором есть пара дополнительных функций:

  1. HRESULT Map(D2D1_MAP_OPTIONS options, D2D1_MAPPED_RECT* mappedRect) - предоставляет прямой доступ к данным битмапа в видеопамяти. Пока битмап замаплен, его нельзя использовать для рисования. options - опции: D2D1_MAP_OPTIONS_READ (только чтение), D2D1_MAP_OPTIONS_WRITE (только запись), а также их комбинация.

  2. HRESULT Unmap() - завершает доступ, начатый Map.

Теперь о отрисовке:

  1. void DrawBitmap( ID2D1Bitmap* bitmap, const D2D1_RECT_F& destinationRectangle, FLOAT opacity, D2D1_BITMAP_INTERPOLATION_MODE interpolationMode, const D2D1_RECT_F* sourceRectangle = nullptr ) - упрощённая версия на ID2D1RenderTarget:

    1. bitmap - рисуемый битмап

    2. destinationRectangle - координаты где рисовать

    3. opacity - непрозрачность от 0.0 (полностью прозрачно) до 1.0 (непрозрачно)

    4. interpolationMode - режим интерполяции: LINEAR (сглаживание) или NEAREST_NEIGHBOR (без сглаживания)

    5. sourceRectangle - область исходного битмапа (в пикселях) для рисования. nullptr - рисуется целиком .

  2. void DrawBitmap( ID2D1Bitmap* bitmap, const D2D1_RECT_F* destinationRectangle, FLOAT opacity, D2D1_INTERPOLATION_MODE interpolationMode, const D2D1_RECT_F* sourceRectangle, const D2D1_MATRIX_4X4_F* perspectiveTransform ) - расширенная версия на ID2D1DeviceContext:

    1. bitmap - битмап

    2. destinationRectangle - координаты

    3. opacity - непрозрачность

    4. interpolationMode - D2D1_INTERPOLATION_MODE (аналог предыдущего, но включает дополнительные опции, например, ANISOTROPIC)

    5. sourceRectangle - как раньше

    6. perspectiveTransform - матрица 4×4 для перспективного преобразования. Позволяет рисовать битмап с эффектом наклона или трёхмерного поворота

Собственно, код, который использует все эти методы (с комментариями):

Информация о изображении: image.png (RGBA, 200×200). Содержимое:

При запуске кода появится сообщение с информацией о файле:

После нажатия "OK" будет такое содержимое окна:

Код
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <d2d1.h>
#include <d2d1_1.h>        // ID2D1Bitmap1
#include <wincodec.h>
#include <cstdio>
#include <comdef.h>        

#pragma comment(lib, "d2d1.lib")
#pragma comment(lib, "windowscodecs.lib")
#pragma comment(lib, "ole32.lib")


ID2D1Factory* g_pD2DFactory = nullptr;
ID2D1HwndRenderTarget* g_pRT = nullptr;
ID2D1Bitmap* g_pBitmap = nullptr;   
ID2D1Bitmap* g_pCopyBitmap = nullptr;   
ID2D1BitmapBrush* g_pBrush = nullptr;   
IWICImagingFactory* g_pWICFactory = nullptr;

HWND g_hwnd;

// Загрузка битмапа через WIC
HRESULT LoadBitmapFromFile(ID2D1RenderTarget* pRT, const wchar_t* filename, ID2D1Bitmap** ppBitmap)
{
    IWICBitmapDecoder* pDecoder = nullptr;
    HRESULT hr = g_pWICFactory->CreateDecoderFromFilename(
        filename, nullptr, GENERIC_READ,
        WICDecodeMetadataCacheOnLoad, &pDecoder);
    if (FAILED(hr)) return hr;

    IWICBitmapFrameDecode* pFrame = nullptr;
    hr = pDecoder->GetFrame(0, &pFrame);
    pDecoder->Release();
    if (FAILED(hr)) return hr;

    IWICFormatConverter* pConverter = nullptr;
    hr = g_pWICFactory->CreateFormatConverter(&pConverter);
    if (SUCCEEDED(hr))
    {
        hr = pConverter->Initialize(
            pFrame,
            GUID_WICPixelFormat32bppPBGRA,
            WICBitmapDitherTypeNone,
            nullptr, 0.f,
            WICBitmapPaletteTypeMedianCut);
    }
    pFrame->Release();
    if (FAILED(hr)) return hr;

    hr = pRT->CreateBitmapFromWicBitmap(pConverter, nullptr, ppBitmap);
    pConverter->Release();
    return hr;
}

// Инициализация Direct2D и демонстрация методов
HRESULT InitD2D(HWND hWnd)
{
    HRESULT hr;

    // 1. Фабрика Direct2D
    hr = D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, &g_pD2DFactory);
    if (FAILED(hr)) {
        MessageBox(hWnd, L"Failed to create D2D factory", L"Error", MB_ICONERROR);
        return hr;
    }

    // 2. WIC-фабрика
    hr = CoCreateInstance(
        CLSID_WICImagingFactory, nullptr, CLSCTX_INPROC_SERVER,
        IID_PPV_ARGS(&g_pWICFactory));
    if (FAILED(hr)) {
        MessageBox(hWnd, L"Failed to create WIC factory", L"Error", MB_ICONERROR);
        return hr;
    }

    // 3. Создание HWND render target
    RECT rc;
    GetClientRect(hWnd, &rc);
    D2D1_SIZE_U size = D2D1::SizeU(rc.right - rc.left, rc.bottom - rc.top);

    hr = g_pD2DFactory->CreateHwndRenderTarget(
        D2D1::RenderTargetProperties(),
        D2D1::HwndRenderTargetProperties(hWnd, size),
        &g_pRT);
    if (FAILED(hr)) {
        MessageBox(hWnd, L"Failed to create render target", L"Error", MB_ICONERROR);
        return hr;
    }

    // 4. Загрузка текстуры
    hr = LoadBitmapFromFile(g_pRT, L"image.png", &g_pBitmap);
    if (FAILED(hr)) {
        wchar_t buf[256];
        wsprintf(buf, L"Failed to load image.png\nHRESULT: 0x%08X", hr);
        MessageBox(hWnd, buf, L"Error", MB_ICONERROR);
        return hr;
    }

    // ------------------- GetSize / GetPixelSize / GetPixelFormat / GetDpi ------------------
    D2D1_SIZE_F dipSize = g_pBitmap->GetSize();
    D2D1_SIZE_U pxSize = g_pBitmap->GetPixelSize();
    D2D1_PIXEL_FORMAT fmt = g_pBitmap->GetPixelFormat();
    FLOAT dpiX, dpiY;
    g_pBitmap->GetDpi(&dpiX, &dpiY);

    char msg[256];
    sprintf_s(msg, "Size (DIP): %.1f x %.1f\nPixel size: %u x %u\nFormat: %u, Alpha: %u\nDPI: %.0f x %.0f",
        dipSize.width, dipSize.height, pxSize.width, pxSize.height, fmt.format, fmt.alphaMode, dpiX, dpiY);
    MessageBoxA(hWnd, msg, "Bitmap Info", MB_OK);

    // ------------------- CopyFromMemory ------------------
    UINT w = pxSize.width, h = pxSize.height;
    // Полупрозрачный красный квадрат 100x100
    BYTE* redData = new BYTE[w * h * 4];
    for (UINT y = 0; y < h; ++y)
        for (UINT x = 0; x < w; ++x)
        {
            UINT idx = (y * w + x) * 4;
            redData[idx + 0] = 0;        // B
            redData[idx + 1] = 0;        // G
            redData[idx + 2] = 255;      // R
            redData[idx + 3] = 128;      // A
        }
    D2D1_RECT_U dstRect = D2D1::RectU(0, 0, 100, 100);
    g_pBitmap->CopyFromMemory(&dstRect, redData, w * 4);
    delete[] redData;

    // ------------------- CopyFromBitmap ------------------
    D2D1_BITMAP_PROPERTIES bmpProps = D2D1::BitmapProperties(g_pBitmap->GetPixelFormat());
    g_pRT->CreateBitmap(pxSize, bmpProps, &g_pCopyBitmap);
    g_pCopyBitmap->CopyFromBitmap(nullptr, g_pBitmap, nullptr);

    // ------------------- CopyFromRenderTarget ------------------
    ID2D1BitmapRenderTarget* pBmpRT = nullptr;
    g_pRT->CreateCompatibleRenderTarget(D2D1::SizeF((FLOAT)w, (FLOAT)h), &pBmpRT);
    pBmpRT->BeginDraw();
    pBmpRT->Clear(D2D1::ColorF(D2D1::ColorF::LimeGreen));
    pBmpRT->EndDraw();
    D2D1_POINT_2U destPoint = { 0, 100 };
    D2D1_RECT_U srcRect = D2D1::RectU(0, 0, 100, 100);
    g_pBitmap->CopyFromRenderTarget(&destPoint, pBmpRT, &srcRect);
    pBmpRT->Release();

    // ------------------- Map / Unmap (ID2D1Bitmap1) ------------------
    ID2D1Bitmap1* pBitmap1 = nullptr;
    hr = g_pBitmap->QueryInterface(IID_PPV_ARGS(&pBitmap1));
    if (SUCCEEDED(hr))
    {
        D2D1_MAPPED_RECT mapped;
        hr = pBitmap1->Map(D2D1_MAP_OPTIONS_WRITE, &mapped);
        if (SUCCEEDED(hr))
        {
            // Заливаем верхний правый квадрат (100,0)-(200,100)
            for (UINT y = 0; y < 100; ++y)
            {
                BYTE* pixel = mapped.bits + y * mapped.pitch + 100 * 4;
                for (UINT x = 100; x < 200; ++x)
                {
                    pixel[0] = 255;  // B
                    pixel[1] = 0;    // G
                    pixel[2] = 0;    // R
                    pixel[3] = 255;  // A
                    pixel += 4;
                }
            }
            pBitmap1->Unmap();
        }
        pBitmap1->Release();
    }

    // ------------------- CreateBitmapBrush ------------------
    D2D1_BITMAP_BRUSH_PROPERTIES brushProps = D2D1::BitmapBrushProperties(
        D2D1_EXTEND_MODE_WRAP, D2D1_EXTEND_MODE_WRAP,
        D2D1_BITMAP_INTERPOLATION_MODE_LINEAR);
    g_pRT->CreateBitmapBrush(g_pCopyBitmap, brushProps, &g_pBrush);
    D2D1_MATRIX_3X2_F translate = D2D1::Matrix3x2F::Translation(50.0f, 50.0f);
    g_pBrush->SetTransform(translate);

    return S_OK;
}

void Render()
{
    g_pRT->BeginDraw();
    g_pRT->Clear(D2D1::ColorF(D2D1::ColorF::White));

    // Модифицированный битмап (с тремя цветными квадратами)
    g_pRT->DrawBitmap(g_pBitmap, D2D1::RectF(10, 10, 210, 210));
    // Копия
    g_pRT->DrawBitmap(g_pCopyBitmap, D2D1::RectF(220, 10, 420, 210));
    // Эллипс, заполненный текстурной кистью
    D2D1_ELLIPSE ellipse = D2D1::Ellipse(D2D1::Point2F(350.0f, 350.0f), 150.0f, 100.0f);
    g_pRT->FillEllipse(ellipse, g_pBrush);

    g_pRT->EndDraw();
}

void Cleanup()
{
    if (g_pBrush)       g_pBrush->Release();
    if (g_pCopyBitmap)  g_pCopyBitmap->Release();
    if (g_pBitmap)      g_pBitmap->Release();
    if (g_pRT)          g_pRT->Release();
    if (g_pWICFactory)  g_pWICFactory->Release();
    if (g_pD2DFactory)  g_pD2DFactory->Release();
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    switch (msg)
    {
    case WM_PAINT:
        Render();
        ValidateRect(hWnd, nullptr);
        return 0;
    case WM_DESTROY:
        Cleanup();
        PostQuitMessage(0);
        return 0;
    }
    return DefWindowProc(hWnd, msg, wParam, lParam);
}

int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE, PWSTR, int nCmdShow)
{
    // Инициализация COM для WIC
    CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED);

    WNDCLASS wc = {};
    wc.lpfnWndProc = WndProc;
    wc.hInstance = hInstance;
    wc.lpszClassName = L"BitmapDemo";
    RegisterClass(&wc);

    g_hwnd = CreateWindow(
        wc.lpszClassName, L"ID2D1Bitmap Methods Demo",
        WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 600, 500,
        nullptr, nullptr, hInstance, nullptr);

    HRESULT hr = InitD2D(g_hwnd);
    if (FAILED(hr))
    {
        wchar_t buf[128];
        wsprintf(buf, L"Initialization failed! HRESULT: 0x%08X", hr);
        MessageBox(g_hwnd, buf, L"Fatal Error", MB_ICONERROR);
        CoUninitialize();
        return 1;
    }

    ShowWindow(g_hwnd, nCmdShow);
    UpdateWindow(g_hwnd);

    MSG msg;
    while (GetMessage(&msg, nullptr, 0, 0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    CoUninitialize();
    return (int)msg.wParam;
}

На этом всё :D Да, статья получилась небольшой, но дальше будут спрайты — там будет о чём рассказать. К слову, когда требуется обработать много объектов и наложить на них текстуры, спрайты оказываются в разы производительнее.

На этом всё :D Да, статья получилась небольшой, но дальше будут спрайты - там будет о чём рассказать. К слову, когда требуется обработать много объектов и наложить на них текстуры, спрайты оказываются в разы производительнее.

При желании материально подержать перевод и структурирование информации — средства можете отправить через сбор в ЮМани .