Advertisement
alien_fx_fiend

Memory DC PaintCanvas Projectv1

Jul 12th, 2024 (edited)
86
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 9.70 KB | None | 0 0
  1. /* Pen brushstrokes are preserved immaculately but when you erase a painted region and redraw on it, it doesn't re-draw it properly when you Minimize + Restore. For that matter the Painted BrushStrokes over Erased Strokes aren't preserved correctly. Is it possible to improve the Minimize + Restore code logic for more robustness in dealing with Eraser tool as well as Paint tools used in tandem? Also sometimes it stops painting when you draw for a while. Here's the full code for the Memory DC Paint App: (show only modified changes and where to insert the code) */
  2. #include <vector>
  3. #include <windows.h>
  4. using namespace std;
  5. struct Brushstroke;
  6. struct Eraserstroke;
  7. void DrawBrush(HDC hdc, int x, int y);
  8. void Erase(HDC hdc, int x, int y);
  9. void ClearDrawing(HDC hdc, int width, int height);
  10. void DrawSmoothBrush(HDC hdc, int x, int y);
  11. bool isPaintbrushSelected = true;  
  12. POINT previousPoint;  
  13. HDC hdc, memDC;
  14. HBITMAP memBitmap;
  15. HWND hWnd;  
  16. struct Brushstroke {
  17.     int x;
  18.     int y;
  19.     int size;
  20.     COLORREF color;
  21. };
  22. struct Eraserstroke {
  23.     int x;
  24.     int y;
  25.     int size;
  26.     COLORREF color;
  27. };
  28. std::vector<Brushstroke> storedBrushstrokes;
  29. std::vector<Eraserstroke> storedEraserstrokes;
  30. std::vector<Brushstroke> minimizedDrawnBrushstrokes;
  31. std::vector<Eraserstroke> minimizedErasedBrushstrokes;
  32. void RedrawStrokes() {
  33.     for (const auto& brushstroke : storedBrushstrokes) {
  34.         DrawBrush(memDC, brushstroke.x, brushstroke.y);
  35.     }
  36.     for (const auto& erasepoint : storedEraserstrokes) {
  37.         Erase(memDC, erasepoint.x, erasepoint.y);
  38.     }
  39. }
  40. LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
  41. HINSTANCE hInst;
  42. bool isDrawing = false;
  43. bool isErasing = false;
  44. bool isClearing = false;
  45. bool isEraserSelected = false;
  46. int brushSize = 10;
  47. void DrawBrush(HDC hdc, int x, int y) {
  48.     HRGN hRgn = CreateEllipticRgn(x - brushSize, y - brushSize, x + brushSize, y + brushSize);
  49.     FillRgn(hdc, hRgn, CreateSolidBrush(RGB(255, 0, 0)));
  50.     DeleteObject(hRgn);
  51. }
  52. void Erase(HDC hdc, int x, int y) {
  53.     HBRUSH hBrush = CreateSolidBrush(RGB(255, 255, 255));
  54.     SelectObject(hdc, GetStockObject(NULL_PEN));
  55.     SelectObject(hdc, hBrush);
  56.     Ellipse(hdc, x - brushSize, y - brushSize, x + brushSize, y + brushSize);
  57.     DeleteObject(hBrush);
  58. }
  59. void ClearDrawing(HDC hdc, int width, int height) {
  60.     RECT rect = { 0, 0, width, height };
  61.     HBRUSH hBrush = CreateSolidBrush(RGB(255, 255, 255));
  62.     FillRect(hdc, &rect, hBrush);
  63.     DeleteObject(hBrush);
  64.     storedBrushstrokes.clear();
  65.     storedEraserstrokes.clear();
  66. }
  67. void DrawSmoothBrush(HDC hdc, int x, int y) {
  68.     if (isDrawing && (isPaintbrushSelected || isEraserSelected)) {
  69.         int numPoints = 3;
  70.         POINT currentPoint = { x, y };
  71.         for (int i = 1; i <= numPoints; i++) {
  72.             float t = (float)i / (float)numPoints;
  73.             int smoothX = (int)(previousPoint.x + t * (currentPoint.x - previousPoint.x));
  74.             int smoothY = (int)(previousPoint.y + t * (currentPoint.y - previousPoint.y));
  75.             if (isPaintbrushSelected) {
  76.                 DrawBrush(hdc, smoothX, smoothY);
  77.                 Brushstroke newBrushstroke;
  78.                 newBrushstroke.x = smoothX;
  79.                 newBrushstroke.y = smoothY;
  80.                 newBrushstroke.size = brushSize;
  81.                 newBrushstroke.color = RGB(255, 0, 0);
  82.                 storedBrushstrokes.push_back(newBrushstroke);
  83.             }
  84.             else if (isEraserSelected) {
  85.                 Erase(hdc, smoothX, smoothY);
  86.                 Eraserstroke newEraserstroke;
  87.                 newEraserstroke.x = smoothX;
  88.                 newEraserstroke.y = smoothY;
  89.                 newEraserstroke.size = brushSize;
  90.                 newEraserstroke.color = RGB(255, 255, 255);
  91.                 storedEraserstrokes.push_back(newEraserstroke);
  92.             }
  93.         }
  94.         previousPoint = currentPoint;
  95.     }
  96. }
  97. LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
  98.     switch (uMsg) {
  99.     case WM_CREATE:
  100.         {
  101.             RECT rect;
  102.             GetClientRect(hwnd, &rect);
  103.             HDC hdc = GetDC(hwnd);
  104.             memDC = CreateCompatibleDC(hdc);
  105.             memBitmap = CreateCompatibleBitmap(hdc, rect.right - rect.left, rect.bottom - rect.top);
  106.             SelectObject(memDC, memBitmap);
  107.             ReleaseDC(hwnd, hdc);
  108.             HBRUSH hBrush = CreateSolidBrush(RGB(255, 255, 255));
  109.             FillRect(memDC, &rect, hBrush);
  110.             DeleteObject(hBrush);
  111.             isPaintbrushSelected = true;
  112.         }
  113.         break;
  114.     case WM_KEYDOWN:
  115.         if (wParam == VK_ADD) {
  116.             brushSize += 5;
  117.         }
  118.         else if (wParam == VK_SUBTRACT) {
  119.             if (brushSize > 5) {
  120.                 brushSize -= 5;
  121.             }
  122.         }
  123.         else if (wParam == 0x43) {
  124.             if (!(GetKeyState(VK_CONTROL) & 0x8000)) {
  125.                 isClearing = true;
  126.             }
  127.         }
  128.         else if (wParam == 0x50) {
  129.             isPaintbrushSelected = true;
  130.             isEraserSelected = false;
  131.         }
  132.         else if (wParam == 0x45) {
  133.             isEraserSelected = true;
  134.             isPaintbrushSelected = false;
  135.         }
  136.         break;
  137.     case WM_LBUTTONDOWN:
  138.         if (isPaintbrushSelected || isEraserSelected) {
  139.             previousPoint.x = LOWORD(lParam);
  140.             previousPoint.y = HIWORD(lParam);
  141.         }
  142.         isDrawing = true;
  143.         break;
  144.     case WM_LBUTTONUP:
  145.         isDrawing = false;
  146.         break;
  147.     case WM_MOUSEMOVE:
  148.         if (isDrawing && isPaintbrushSelected) {
  149.             int x = LOWORD(lParam);
  150.             int y = HIWORD(lParam);
  151.             DrawSmoothBrush(memDC, x, y);
  152.             InvalidateRect(hwnd, NULL, FALSE);
  153.             Brushstroke newBrushstroke;
  154.             newBrushstroke.x = x;
  155.             newBrushstroke.y = y;
  156.             newBrushstroke.size = brushSize;
  157.             newBrushstroke.color = RGB(255, 0, 0);  
  158.             storedBrushstrokes.push_back(newBrushstroke);
  159.         }
  160.         else if (isDrawing && isEraserSelected) {
  161.             int x = LOWORD(lParam);
  162.             int y = HIWORD(lParam);
  163.             Erase(memDC, x, y);
  164.             InvalidateRect(hwnd, NULL, FALSE);
  165.             Eraserstroke newEraserStroke;
  166.             newEraserStroke.x = x;
  167.             newEraserStroke.y = y;
  168.             newEraserStroke.size = brushSize;  
  169.             newEraserStroke.color = RGB(255, 255, 255);  
  170.             storedEraserstrokes.push_back(newEraserStroke);
  171.         }
  172.         else if (isClearing) {
  173.             HDC hdc = GetDC(hwnd);
  174.             RECT rect;
  175.             GetClientRect(hwnd, &rect);
  176.             ClearDrawing(hdc, rect.right, rect.bottom);
  177.             ReleaseDC(hwnd, hdc);
  178.             isClearing = false;
  179.         }
  180.         break;
  181.     case WM_SIZE:
  182.         {
  183.             static bool isMinimized = false;
  184.             if (wParam == SIZE_MINIMIZED)
  185.             {
  186.                 isMinimized = true;
  187.             }
  188.             else if (wParam == SIZE_MAXIMIZED || wParam == SIZE_RESTORED)
  189.             {
  190.                 if (isMinimized)
  191.                 {
  192.                     HDC hdc = GetDC(hwnd);
  193.                     BitBlt(hdc, 0, 0, LOWORD(lParam), HIWORD(lParam), memDC, 0, 0, SRCCOPY);
  194.                     ReleaseDC(hwnd, hdc);
  195.                     minimizedDrawnBrushstrokes = storedBrushstrokes;
  196.                     minimizedErasedBrushstrokes = storedEraserstrokes;
  197.                     isMinimized = false;
  198.                 }
  199.                 InvalidateRect(hwnd, NULL, TRUE);
  200.             }
  201.             RECT rect;
  202.             GetClientRect(hwnd, &rect);
  203.             if (memDC)
  204.             {
  205.                 DeleteDC(memDC);
  206.                 DeleteObject(memBitmap);
  207.             }
  208.             HDC hdc = GetDC(hwnd);
  209.             memDC = CreateCompatibleDC(hdc);
  210.             memBitmap = CreateCompatibleBitmap(hdc, rect.right - rect.left, rect.bottom - rect.top);
  211.             SelectObject(memDC, memBitmap);
  212.             ReleaseDC(hwnd, hdc);
  213.             HBRUSH hBrush = CreateSolidBrush(RGB(255, 255, 255));
  214.             FillRect(memDC, &rect, hBrush);
  215.             DeleteObject(hBrush);
  216.             RedrawStrokes();
  217.         }
  218.         break;
  219.     case WM_PAINT:
  220.         {
  221.             PAINTSTRUCT ps;
  222.             HDC hdc = BeginPaint(hwnd, &ps);
  223.             BitBlt(hdc, 0, 0, ps.rcPaint.right - ps.rcPaint.left, ps.rcPaint.bottom - ps.rcPaint.top, memDC, 0, 0, SRCCOPY);
  224.             EndPaint(hwnd, &ps);
  225.         }
  226.         break;
  227.     case WM_SETCURSOR:
  228.         if (LOWORD(lParam) == HTCLIENT) {
  229.             SetCursor(LoadCursor(NULL, IDC_ARROW));
  230.             return TRUE;
  231.         }
  232.         break;
  233.     case WM_DESTROY:
  234.         DeleteDC(memDC);
  235.         DeleteObject(memBitmap);
  236.         PostQuitMessage(0);
  237.         return 0;
  238.     default:
  239.         return DefWindowProc(hwnd, uMsg, wParam, lParam);
  240.     }
  241.     return 0;
  242. }
  243. int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
  244.     const wchar_t CLASS_NAME[] = L"DoodleAppClass";
  245.     WNDCLASS wc = { };
  246.     wc.lpfnWndProc = WindowProc;
  247.     wc.hInstance = hInstance;
  248.     wc.lpszClassName = CLASS_NAME;
  249.     RegisterClass(&wc);
  250.     hInst = hInstance;
  251.     HWND hwnd = CreateWindowEx(
  252.         0,
  253.         CLASS_NAME,
  254.         L"Doodle App",
  255.         WS_OVERLAPPEDWINDOW | WS_MAXIMIZE,
  256.         CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
  257.         NULL,
  258.         NULL,
  259.         hInstance,
  260.         NULL
  261.     );
  262.     hdc = GetDC(hwnd);
  263.     if (hwnd == NULL) {
  264.         return 0;
  265.     }
  266.     ShowWindow(hwnd, SW_SHOWMAXIMIZED);
  267.     MSG msg = {};
  268.     while (GetMessage(&msg, NULL, 0, 0)) {
  269.         TranslateMessage(&msg);
  270.         DispatchMessage(&msg);
  271.     }
  272.     return 0;
  273. }
  274.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement