Анимация пикселей в GDI

Я пытаюсь анимировать цветовой эффект радуги в GDI, пока что я создал статическую радугу, которая не анимируется.

Мой подход к анимации заключался в том, что я должен переместить элементы массива на следующую позицию, например [0,1,2] станет [2,0,1] и вызвать setpixelv() again. Но я считаю, что это отнимает много времени и неэффективно.

Вот мой фактический код:

#include <windows.h>

const int WINDOW_WIDTH = 800;
const int WINDOW_HEIGHT = 600;
const int BAR_WIDTH = 600;
const int BAR_HEIGHT = 50;

int imageData[498 * 1] = {0xFB017D, 0xFB0278, 0xFB017D, 0xFC0280, 0xFB027A, 0xFB027A, 0xFB017C, 0xFA0175, 0xFC026E, 0xFC026C, 0xFC036B, 0xFC0266,
                          0xFC0263, 0xFC015E, 0xFC025B, 0xFB015A, 0xFB0351, 0xFB0351, 0xFC014E, 0xFC024C, 0xFC0249, 0xFC0146, 0xFC0242, 0xFC0241, 0xFD0237, 0xFD0237, 0xFD0237, 0xFD0235, 0xFD0132, 0xFD022D, 0xFD0329, 0xFC0226, 0xFC0228, 0xFC0323, 0xFC021D, 0xFC0319, 0xFE0219, 0xFD0116, 0xFD0213, 0xFC020E, 0xFC020C, 0xFC030B, 0xFB0206, 0xFB0304, 0xFB0303, 0xF90403, 0xF90304, 0xF90306, 0xFD0002, 0xFE0606, 0xFB0905, 0xF90C04, 0xFC1005, 0xFD1104, 0xFB1404, 0xFC1906, 0xF81A03, 0xFB2004, 0xFB2203, 0xFA2402, 0xFA2805, 0xF82A05, 0xF82D04, 0xFB3204, 0xFB3705, 0xF93A06, 0xFA3D06, 0xFC3F05, 0xFF4105, 0xFE4203, 0xFC4604, 0xFB4A06, 0xFB5106, 0xFC5207, 0xFB5406, 0xFC5707, 0xFB5904, 0xFB5B03, 0xFC5D02, 0xFC5E03, 0xFC6303, 0xFB6504, 0xFC6804, 0xFB6E04, 0xFC7205, 0xFC7605, 0xFC7905, 0xFD7A04, 0xF97B02, 0xFC7E03, 0xFB8102, 0xFB8402, 0xFC8A05, 0xFC8C04, 0xFA8F03, 0xFD9204, 0xFB9703, 0xFC9804, 0xFC9A03, 0xFC9D03, 0xFBA103, 0xFCA603, 0xFDAA06, 0xFEAD06, 0xFBAE06, 0xFDB306, 0xFDB805, 0xFCBC05, 0xFBBD06, 0xFAC005, 0xFCC304, 0xFEC502, 0xFACC05, 0xFBCD05, 0xFBD007, 0xFDD305, 0xFAD403, 0xFAD703, 0xF9DA03, 0xFBDC05, 0xFDE104, 0xFAE202, 0xF8E703, 0xFBED06, 0xFDEF06, 0xFCEE05, 0xFAF005, 0xFAF307, 0xFAF503, 0xF8F603, 0xF7F605, 0xF2F504, 0xF0F505, 0xEDF605, 0xECF703, 0xEBF904, 0xE6FC06, 0xE1F903, 0xDDF904, 0xDCFC05, 0xD7FB05, 0xD4FC06, 0xD3FB05, 0xCEF801, 0xCEF703, 0xCCF803, 0xC8FA05, 0xC2FA03, 0xBEFA04, 0xBAFA05, 0xB6FB04, 0xB3F902, 0xB4FA04, 0xB3F903, 0xB0FA03, 0xADFB05, 0xAAFC06,
                          0xA2FA05, 0x9EF904, 0x9CFB07, 0x98FA05, 0x94F802, 0x92F703, 0x8FF903, 0x8DFB06, 0x89FB06, 0x84FA04, 0x82FA03, 0x83FB06, 0x7DF905, 0x77F905, 0x77FA06, 0x77FA08, 0x73F906, 0x6EFA03, 0x6AFB02, 0x6AFA04, 0x68F802, 0x68FA04, 0x63F904, 0x5DF703, 0x58F804, 0x56FA05, 0x52FA04, 0x53F903, 0x4DF903, 0x4AFA04, 0x47F905, 0x47F905, 0x45F806, 0x3FF902, 0x3BF901, 0x3BFC05, 0x36FA02, 0x32F803, 0x2EF804, 0x2CF906, 0x27F904, 0x27F904, 0x26FA05, 0x1FFB03, 0x1CFB04, 0x18FA03, 0x14FA04, 0x10FA05, 0x0CFA04, 0x0CFA04, 0x0BFB04, 0x04F904, 0x04F904, 0x04F904, 0x04F904, 0x04F904, 0x04F904, 0x04F904, 0x04F904, 0x03FA0B, 0x03FA0B, 0x03FA0D, 0x04FA0F, 0x04FA13, 0x03FA15, 0x04FA19, 0x04FA1B, 0x02F922, 0x03FA23, 0x03FA27, 0x03F92A, 0x04F92F, 0x05FA33, 0x04FA37, 0x04F939, 0x05F93F, 0x06FA42, 0x05FA43, 0x05FA47, 0x04FB4B, 0x04FA4F, 0x04FA51, 0x05FA54, 0x04FA57, 0x04FA57, 0x04FA5B, 0x03FB5D, 0x03FA61, 0x03FA65, 0x04FA67, 0x04FA69, 0x04F96D, 0x04F96E, 0x04F970, 0x04F976, 0x04F97A, 0x05F980, 0x04F982, 0x04F984, 0x05F988, 0x07FB8A, 0x05FB8E, 0x03FA8F, 0x03FA92, 0x04FB93, 0x06FB96, 0x06FB96, 0x05FA9B, 0x05FA9F, 0x03FAA1, 0x04FAA5, 0x04F9A9, 0x04FBAC, 0x04FBAC, 0x04FBAC, 0x04FBB5, 0x04FBB7, 0x04FAB9, 0x04FABB, 0x04F8C2, 0x05F9C5, 0x03F9C6, 0x03F9C8, 0x04F9CE, 0x02F7CC, 0x05F7CF, 0x06F7D4, 0x03F6D8, 0x04F8DE, 0x05F8E4, 0x02F7E5, 0x03F8E7, 0x03F8E7, 0x03F8E9, 0x03F7ED, 0x04F7F1, 0x04F6F7, 0x04F6FA, 0x03F4FB, 0x05F1FF, 0x02EEFC, 0x05EEFD, 0x04E9FC, 0x05E8FB, 0x06E7FD,
                          0x04E1FB, 0x05E2FC, 0x06DDF9, 0x02D6FE, 0x01D5FA, 0x04D6F7, 0x04D1FE, 0x05CEF8, 0x06CBF6, 0x03C4FD, 0x05C2FC, 0x02BEFB, 0x03BCFC, 0x05BBFD, 0x04B5FB, 0x03B1FA, 0x04B0FC, 0x04AEFC, 0x02ABFC, 0x04ABFC, 0x03AAFB, 0x03A7FC, 0x04A4FC, 0x049FFC, 0x059BFC, 0x0498FC, 0x0592FE, 0x028FFB, 0x038BFB, 0x0389FC, 0x0586FD, 0x0482FB, 0x057FFC, 0x057FFE, 0x057CFE, 0x0277FB, 0x0474FC, 0x0671FD, 0x056BFC, 0x0468FC, 0x0468FE, 0x0466FF, 0x0361FE, 0x035BFB, 0x0659FD, 0x0354FB, 0x0354FD, 0x0654FE, 0x034FFA, 0x064EFA, 0x054AFD, 0x0446FC, 0x0343FC, 0x0442F9, 0x053FF8, 0x043BF7, 0x0338FA, 0x0536FF, 0x0734FF, 0x0530FB, 0x042DFB, 0x0528FC, 0x0223FA, 0x0521FE, 0x0720FF, 0x051DFD, 0x0517FD, 0x0415FB, 0x0412FB, 0x030FFB, 0x040DFC, 0x0509FE, 0x0406FB, 0x0203FB, 0x0201FC, 0x0402FD, 0x0601FD, 0x0600FE, 0x0302FD, 0x0402FD, 0x0801FC, 0x0B02FD, 0x0E02FA, 0x1502FC, 0x1A01FD, 0x1C01FC, 0x1C02FB, 0x2003FD, 0x2303FC, 0x2601FC, 0x2A01FB, 0x2B02FC, 0x2C02FC, 0x3001FD, 0x3201FB, 0x3801FC, 0x3A02FB, 0x3E03FD, 0x4202F9, 0x4601FC, 0x4A02FC, 0x4D02FD, 0x4D02FB, 0x4E02FA, 0x5202F7, 0x5501F7, 0x5B00FB, 0x5E02FB, 0x6303FB, 0x6502FB, 0x6701FA, 0x6802FB, 0x6B02FC, 0x6A01FC, 0x6C02FC, 0x7002FB, 0x7502FD, 0x7B02FD, 0x8002FC, 0x8401FC, 0x8602FD, 0x8902FE, 0x8D02FD, 0x8D02FD, 0x8F03FC, 0x9102FC, 0x9402FB, 0x9801FC, 0x9B02FB, 0x9E03FD, 0xA302FD, 0xA500FA, 0xAC03FE, 0xAC02FB, 0xAE01FB, 0xB203FC, 0xB500FB, 0xBC02FD, 0xBD00FC, 0xC001FE, 0xC403FE, 0xC502FC, 0xC602FA, 0xCA02FB, 0xCD02FA,
                          0xCD02FA, 0xD402FB, 0xD702FC, 0xD902FD, 0xDD02FC, 0xE102FB, 0xE402FC, 0xE802FB, 0xEC01FC, 0xED00FC, 0xF202F9, 0xF601FE, 0xF602F7, 0xF600FF, 0xF703F8, 0xFA02F9, 0xFD02F0, 0xFD02F0, 0xFD02F0, 0xFC01EE, 0xFC01EF, 0xFD03DF, 0xFC02E0, 0xFC02E0, 0xFC02DE, 0xFD03D9, 0xFC02D8, 0xFB03CD, 0xFD02CE, 0xFD02CD, 0xFD03C7, 0xFD01C6, 0xFC02BC, 0xFC02BE, 0xFB01BA, 0xFB02B4, 0xFD02B3, 0xFD02B3, 0xFC01B2, 0xFC02AE, 0xFC02AC, 0xFC01A8, 0xFC02A4, 0xFC02A1, 0xFC039F, 0xFC039F, 0xFB029E, 0xFC0298, 0xFB0294, 0xFC018F, 0xFC018E};

void AnimateRainbowBar(HDC hdc)
{
  for (int i = 0; i < 498; i++)
  {
    SetPixel(hdc, 100 + i, 100, imageData[i]);
  }
}

LRESULT CALLBACK WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
  switch (msg)
  {
  case WM_PAINT:
  {
    PAINTSTRUCT ps;
    HDC hdc = BeginPaint(hwnd, &ps);

    AnimateRainbowBar(hdc);

    EndPaint(hwnd, &ps);
    return 0;
  }
  case WM_DESTROY:
    PostQuitMessage(0);
    return 0;
  default:
    return DefWindowProc(hwnd, msg, wParam, lParam);
  }
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
  WNDCLASSEX wc = {sizeof(WNDCLASSEX)};
  wc.cbSize = sizeof(WNDCLASSEX);
  wc.lpfnWndProc = WindowProc;
  wc.hInstance = hInstance;
  wc.hCursor = LoadCursor(NULL, IDC_ARROW);
  wc.hbrBackground = (HBRUSH)CreateSolidBrush(RGB(0, 0, 0)); // Use window background color
  wc.lpszClassName = "RainbowBarWindow";
  RegisterClassEx(&wc);

  HWND hwnd = CreateWindowEx(0, "RainbowBarWindow", "Rainbow Bar", WS_OVERLAPPEDWINDOW,
                             100, 100, WINDOW_WIDTH, WINDOW_HEIGHT, NULL, NULL, hInstance, NULL);

  ShowWindow(hwnd, nCmdShow);

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

  return (int)msg.wParam;
}
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
0
91
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Вы можете сделать это с помощью таймера , примерно так:

  • Прежде чем звонить SetTimer(hwnd, 1, 2, NULL);, позвоните ShowWindow. Таймер будет срабатывать каждые 2 миллисекунды.
  • Обработайте сообщение WM_TIMER, в котором вы циклически меняете цвета и аннулируете окно, чтобы оно перерисовывалось.
  • Это почти все
  case WM_DESTROY:
    PostQuitMessage(0);
    return 0;

  // Add this: (will be called automatically)
  case WM_TIMER:
    CycleColors();
    InvalidateRect(hwnd, NULL, FALSE);  // invalidate Window so it will be redrawn automaticalle
    return 0;
    break;
  // end Add

  default:
    return DefWindowProc(hwnd, msg, wParam, lParam);

Затем напишите функцию CycleColors(), которая настраивает imageData. Я позволяю тебе написать это.

Подсказка: используйте std::deque<int> вместо imageData вместо необработанного массива C, тогда функцию CycleColors() можно будет тривиально записать в 3 строки.

Побеспокойтесь об эффективности позже, действительно SetPixel работает очень медленно, как указано в этом ответе:

спасибо за помощь, я создал функцию, которая изменяет массив с помощью deque. Работает, но мерцает ;(

Sjskwk Eikskaw 29.04.2024 13:31

Попробуйте справиться WM_ERASEBKGD. Смотрите комментарии по этому поводу в моем ответе.

paddy 29.04.2024 21:23

SetPixel очень медленный и бесполезный для какой-либо производительности.

Если вам нужен прямой GDI, вам нужно создать собственный буфер и выполнять все операции с пикселями непосредственно в памяти. Это означает, что вы используете CreateDIBitmap для создания HBITMAP объекта, предоставляя данные вашего изображения в качестве буфера (в соответствующем формате пикселей).

Затем, когда вы рисуете (например, при обработке WM_PAINT или WM_ERASEBKGD ), вам нужно создать CreateCompatibleDC , чтобы создать новый DC, выбрать растровый объект в этом DC и выполнить побитовую обработку ( BitBlt), чтобы скопировать данные изображения в клиентскую область окна.

Это обрабатывает все изображение сразу, как если бы вы сделали много звонков на SetPixel, но намного быстрее.

например

// Example variables that might hold your bitmap info
int nWidth = 498;
int nHeight = 1;
uint8_t pixelBuffer;   //<-- your image data (BGR-triples)
HBITMAP hBitmap;       //<-- result of CreateDIBitmap

// Example co-ordinate to draw at (top-left)
POINT target = { 100, 100 };

void AnimateRainbowBar(HDC hdc)
{
    // Draw my bitmap to buffer
    HDC hdcBitmap = CreateCompatibleDC(hdc);
    HBITMAP hBitmapOld = SelectBitmap(hdcBitmap, hBitmap);
    BitBlt(hdc, target.x, target.y, nWidth, nHeight, hdcBitmap, 0, 0, SRCCOPY);

    // Cleanup Bitamap DC
    SelectBitmap(hdcBitmap, hBitmapOld);
    DeleteDC(hdcBitmap);
}

Если вы хотите анимировать, вам нужен таймер , который будет регулярно срабатывать и либо аннулировать, либо непосредственно закрашивать ваше окно. Вы можете обновить анимацию перед рисованием. Если вы начинаете мерцать, возможно, проблема связана с фоном. Вы можете справиться с WM_ERASEBKGD и игнорировать его.

Это несколько сложно для новичка, но да, это правильный подход.

Jabberwocky 29.04.2024 12:03

Хорошо работает с вашим ответом, посвященным настройке таймера :) Я пропустил, как правильно создать растровое изображение, но, вероятно, в Stack Overflow есть много примеров.

paddy 29.04.2024 12:05

Мне любопытно, почему кто-то захочет сделать это в GDI, а не в Direct2D.

Peter Constable 29.04.2024 15:45

Другие вопросы по теме