alien_fx_fiend

Memory DC PaintCanvas Projectv4 (Draw Out-of-Bounds bug)

Jul 12th, 2024
35
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 11.41 KB | None | 0 0
  1. #include <vector>
  2. #include <windows.h>
  3. #include <fstream>
  4. #include <string>
  5. using namespace std;
  6. struct Brushstroke;
  7. struct Eraserstroke;
  8. void DrawBrush(HDC hdc, int x, int y);
  9. void Erase(HDC hdc, int x, int y);
  10. void ClearDrawing(HDC hdc, int width, int height);
  11. void DrawSmoothBrush(HDC hdc, int x, int y);
  12. bool isPaintbrushSelected = true;
  13. POINT previousPoint;
  14. HDC hdc, memDC;
  15. HBITMAP memBitmap;
  16. HWND hWnd;
  17. struct Brushstroke {
  18.     int x;
  19.     int y;
  20.     int size;
  21.     COLORREF color;
  22.     void serialize(ofstream& outFile) const {
  23.         outFile << "B " << x << " " << y << " " << size << " " << (int)GetRValue(color) << " " << (int)GetGValue(color) << " " << (int)GetBValue(color) << endl;
  24.     }
  25. };
  26. struct Eraserstroke {
  27.     int x;
  28.     int y;
  29.     int size;
  30.     COLORREF color;
  31.     void serialize(ofstream& outFile) const {
  32.         outFile << "E " << x << " " << y << " " << size << endl;
  33.     }
  34. };
  35. std::vector<Brushstroke> storedBrushstrokes;
  36. std::vector<Eraserstroke> storedEraserstrokes;
  37. void RedrawStrokes() {
  38.     for (const auto& brushstroke : storedBrushstrokes) {
  39.         HGDIOBJ originalBrush = SelectObject(memDC, CreateSolidBrush(brushstroke.color));
  40.         HGDIOBJ originalPen = SelectObject(memDC, GetStockObject(NULL_PEN));
  41.         Ellipse(memDC, brushstroke.x - brushstroke.size, brushstroke.y - brushstroke.size,
  42.             brushstroke.x + brushstroke.size, brushstroke.y + brushstroke.size);
  43.         DeleteObject(SelectObject(memDC, originalBrush));
  44.         DeleteObject(SelectObject(memDC, originalPen));
  45.     }
  46.     for (const auto& erasepoint : storedEraserstrokes) {
  47.         HBRUSH hBrush = CreateSolidBrush(RGB(255, 255, 255));
  48.         SelectObject(memDC, GetStockObject(NULL_PEN));
  49.         SelectObject(memDC, hBrush);
  50.         Ellipse(memDC, erasepoint.x - erasepoint.size, erasepoint.y - erasepoint.size,
  51.             erasepoint.x + erasepoint.size, erasepoint.y + erasepoint.size);
  52.         DeleteObject(hBrush);
  53.     }
  54. }
  55. void SaveDrawing(const string& filename) {
  56.     ofstream outFile(filename);
  57.     if (outFile.is_open()) {
  58.         outFile << storedBrushstrokes.size() << " " << storedEraserstrokes.size() << endl;
  59.         for (const auto& brushstroke : storedBrushstrokes) {
  60.             brushstroke.serialize(outFile);
  61.         }
  62.         for (const auto& eraserstroke : storedEraserstrokes) {
  63.             eraserstroke.serialize(outFile);
  64.         }
  65.         outFile.close();
  66.     }
  67. }
  68. void LoadDrawing(const string& filename) {
  69.     ifstream inFile(filename);
  70.     if (inFile.is_open()) {
  71.         int numBrushstrokes, numEraserstrokes;
  72.         inFile >> numBrushstrokes >> numEraserstrokes;
  73.         storedBrushstrokes.clear();
  74.         storedEraserstrokes.clear();
  75.         storedBrushstrokes.reserve(numBrushstrokes);
  76.         storedEraserstrokes.reserve(numEraserstrokes);
  77.         for (int i = 0; i < numBrushstrokes; ++i) {
  78.             char type;
  79.             Brushstroke brushstroke;
  80.             int r, g, b;
  81.             inFile >> type >> brushstroke.x >> brushstroke.y >> brushstroke.size >> r >> g >> b;
  82.             brushstroke.color = RGB(r, g, b);
  83.             storedBrushstrokes.push_back(brushstroke);
  84.         }
  85.         for (int i = 0; i < numEraserstrokes; ++i) {
  86.             char type;
  87.             Eraserstroke eraserstroke;
  88.             inFile >> type >> eraserstroke.x >> eraserstroke.y >> eraserstroke.size;
  89.             storedEraserstrokes.push_back(eraserstroke);
  90.         }
  91.         inFile.close();
  92.         RedrawStrokes();
  93.         InvalidateRect(hWnd, NULL, TRUE); // Force a repaint
  94.     }
  95. }
  96. LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
  97. HINSTANCE hInst;
  98. bool isDrawing = false;
  99. bool isErasing = false;
  100. bool isClearing = false;
  101. bool isEraserSelected = false;
  102. int brushSize = 10;
  103. void DrawBrush(HDC hdc, int x, int y) {
  104.     HGDIOBJ originalBrush = SelectObject(hdc, CreateSolidBrush(RGB(255, 0, 0)));
  105.     HGDIOBJ originalPen = SelectObject(hdc, GetStockObject(NULL_PEN));
  106.     Ellipse(hdc, x - brushSize, y - brushSize, x + brushSize, y + brushSize);
  107.     DeleteObject(SelectObject(hdc, originalBrush));
  108.     DeleteObject(SelectObject(hdc, originalPen));
  109. }
  110. void Erase(HDC hdc, int x, int y) {
  111.     HBRUSH hBrush = CreateSolidBrush(RGB(255, 255, 255));
  112.     SelectObject(hdc, GetStockObject(NULL_PEN));
  113.     SelectObject(hdc, hBrush);
  114.     Ellipse(hdc, x - brushSize, y - brushSize, x + brushSize, y + brushSize);
  115.     DeleteObject(hBrush);
  116. }
  117. void ClearDrawing(HDC hdc, int width, int height) {
  118.     RECT rect = { 0, 0, width, height };
  119.     HBRUSH hBrush = CreateSolidBrush(RGB(255, 255, 255));
  120.     FillRect(hdc, &rect, hBrush);
  121.     DeleteObject(hBrush);
  122.     storedBrushstrokes.clear();
  123.     storedEraserstrokes.clear();
  124. }
  125. void DrawSmoothBrush(HDC hdc, int x, int y) {
  126.     if (isDrawing && (isPaintbrushSelected || isEraserSelected)) {
  127.         int numPoints = 3;
  128.         POINT currentPoint = { x, y };
  129.         for (int i = 1; i <= numPoints; i++) {
  130.             float t = (float)i / (float)numPoints;
  131.             int smoothX = (int)(previousPoint.x + t * (currentPoint.x - previousPoint.x));
  132.             int smoothY = (int)(previousPoint.y + t * (currentPoint.y - previousPoint.y));
  133.             if (isPaintbrushSelected) {
  134.                 DrawBrush(hdc, smoothX, smoothY);
  135.                 Brushstroke newBrushstroke;
  136.                 newBrushstroke.x = smoothX;
  137.                 newBrushstroke.y = smoothY;
  138.                 newBrushstroke.size = brushSize;
  139.                 newBrushstroke.color = RGB(255, 0, 0);
  140.                 storedBrushstrokes.push_back(newBrushstroke);
  141.             }
  142.             else if (isEraserSelected) {
  143.                 Erase(hdc, smoothX, smoothY);
  144.                 Eraserstroke newEraserstroke;
  145.                 newEraserstroke.x = smoothX;
  146.                 newEraserstroke.y = smoothY;
  147.                 newEraserstroke.size = brushSize;
  148.                 newEraserstroke.color = RGB(255, 255, 255);
  149.                 storedEraserstrokes.push_back(newEraserstroke);
  150.             }
  151.         }
  152.         previousPoint = currentPoint;
  153.     }
  154. }
  155. LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
  156.     switch (uMsg) {
  157.     case WM_CREATE:
  158.     {
  159.         hWnd = hwnd; // Store the window handle
  160.         RECT rect;
  161.         GetClientRect(hwnd, &rect);
  162.         HDC hdc = GetDC(hwnd);
  163.         memDC = CreateCompatibleDC(hdc);
  164.         memBitmap = CreateCompatibleBitmap(hdc, rect.right - rect.left, rect.bottom - rect.top);
  165.         SelectObject(memDC, memBitmap);
  166.         ReleaseDC(hwnd, hdc);
  167.         HBRUSH hBrush = CreateSolidBrush(RGB(255, 255, 255));
  168.         FillRect(memDC, &rect, hBrush);
  169.         DeleteObject(hBrush);
  170.         isPaintbrushSelected = true;
  171.         LoadDrawing("drawing.txt");
  172.     }
  173.     break;
  174.     case WM_KEYDOWN:
  175.         if (wParam == VK_ADD) {
  176.             brushSize += 5;
  177.         }
  178.         else if (wParam == VK_SUBTRACT) {
  179.             if (brushSize > 5) {
  180.                 brushSize -= 5;
  181.             }
  182.         }
  183.         else if (wParam == 0x43) {
  184.             if (!(GetKeyState(VK_CONTROL) & 0x8000)) {
  185.                 isClearing = true;
  186.             }
  187.         }
  188.         else if (wParam == 0x50) {
  189.             isPaintbrushSelected = true;
  190.             isEraserSelected = false;
  191.         }
  192.         else if (wParam == 0x45) {
  193.             isEraserSelected = true;
  194.             isPaintbrushSelected = false;
  195.         }
  196.         break;
  197.     case WM_LBUTTONDOWN:
  198.         if (isPaintbrushSelected || isEraserSelected) {
  199.             previousPoint.x = LOWORD(lParam);
  200.             previousPoint.y = HIWORD(lParam);
  201.         }
  202.         isDrawing = true;
  203.         break;
  204.     case WM_LBUTTONUP:
  205.         isDrawing = false;
  206.         break;
  207.     case WM_MOUSEMOVE:
  208.         if (isDrawing && isPaintbrushSelected) {
  209.             int x = LOWORD(lParam);
  210.             int y = HIWORD(lParam);
  211.             DrawSmoothBrush(memDC, x, y);
  212.             InvalidateRect(hwnd, NULL, FALSE);
  213.             Brushstroke newBrushstroke;
  214.             newBrushstroke.x = x;
  215.             newBrushstroke.y = y;
  216.             newBrushstroke.size = brushSize;
  217.             newBrushstroke.color = RGB(255, 0, 0);
  218.             storedBrushstrokes.push_back(newBrushstroke);
  219.         }
  220.         else if (isDrawing && isEraserSelected) {
  221.             int x = LOWORD(lParam);
  222.             int y = HIWORD(lParam);
  223.             Erase(memDC, x, y);
  224.             InvalidateRect(hwnd, NULL, FALSE);
  225.             Eraserstroke newEraserStroke;
  226.             newEraserStroke.x = x;
  227.             newEraserStroke.y = y;
  228.             newEraserStroke.size = brushSize;
  229.             newEraserStroke.color = RGB(255, 255, 255);
  230.             storedEraserstrokes.push_back(newEraserStroke);
  231.         }
  232.         else if (isClearing) {
  233.             HDC hdc = GetDC(hwnd);
  234.             RECT rect;
  235.             GetClientRect(hwnd, &rect);
  236.             ClearDrawing(hdc, rect.right, rect.bottom);
  237.             ReleaseDC(hwnd, hdc);
  238.             isClearing = false;
  239.         }
  240.         break;
  241.     case WM_SIZE:
  242.     {
  243.         static bool isMinimized = false;
  244.         if (wParam == SIZE_MINIMIZED)
  245.         {
  246.             isMinimized = true;
  247.         }
  248.         else if (wParam == SIZE_MAXIMIZED || wParam == SIZE_RESTORED)
  249.         {
  250.             if (isMinimized)
  251.             {
  252.                 isMinimized = false;
  253.             }
  254.             InvalidateRect(hwnd, NULL, TRUE);
  255.         }
  256.         RECT rect;
  257.         GetClientRect(hwnd, &rect);
  258.         if (memDC)
  259.         {
  260.             DeleteDC(memDC);
  261.             DeleteObject(memBitmap);
  262.         }
  263.         HDC hdc = GetDC(hwnd);
  264.         memDC = CreateCompatibleDC(hdc);
  265.         memBitmap = CreateCompatibleBitmap(hdc, rect.right - rect.left, rect.bottom - rect.top);
  266.         SelectObject(memDC, memBitmap);
  267.         ReleaseDC(hwnd, hdc);
  268.         HBRUSH hBrush = CreateSolidBrush(RGB(255, 255, 255));
  269.         FillRect(memDC, &rect, hBrush);
  270.         DeleteObject(hBrush);
  271.         RedrawStrokes();
  272.     }
  273.     break;
  274.     case WM_PAINT:
  275.     {
  276.         PAINTSTRUCT ps;
  277.         HDC hdc = BeginPaint(hwnd, &ps);
  278.         BitBlt(hdc, 0, 0, ps.rcPaint.right - ps.rcPaint.left, ps.rcPaint.bottom - ps.rcPaint.top, memDC, 0, 0, SRCCOPY);
  279.         EndPaint(hwnd, &ps);
  280.     }
  281.     break;
  282.     case WM_SETCURSOR:
  283.         if (LOWORD(lParam) == HTCLIENT) {
  284.             SetCursor(LoadCursor(NULL, IDC_ARROW));
  285.             return TRUE;
  286.         }
  287.         break;
  288.     case WM_DESTROY:
  289.         SaveDrawing("drawing.txt");
  290.         DeleteDC(memDC);
  291.         DeleteObject(memBitmap);
  292.         PostQuitMessage(0);
  293.         return 0;
  294.     default:
  295.         return DefWindowProc(hwnd, uMsg, wParam, lParam);
  296.     }
  297.     return 0;
  298. }
  299. int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
  300.     const wchar_t CLASS_NAME[] = L"DoodleAppClass";
  301.     WNDCLASS wc = { };
  302.     wc.lpfnWndProc = WindowProc;
  303.     wc.hInstance = hInstance;
  304.     wc.lpszClassName = CLASS_NAME;
  305.     RegisterClass(&wc);
  306.     hInst = hInstance;
  307.     HWND hwnd = CreateWindowEx(
  308.         0,
  309.         CLASS_NAME,
  310.         L"Doodle App",
  311.         WS_OVERLAPPEDWINDOW | WS_MAXIMIZE,
  312.         CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
  313.         NULL,
  314.         NULL,
  315.         hInstance,
  316.         NULL
  317.     );
  318.     hdc = GetDC(hwnd);
  319.     if (hwnd == NULL) {
  320.         return 0;
  321.     }
  322.     ShowWindow(hwnd, SW_SHOWMAXIMIZED);
  323.     MSG msg = {};
  324.     while (GetMessage(&msg, NULL, 0, 0)) {
  325.         TranslateMessage(&msg);
  326.         DispatchMessage(&msg);
  327.     }
  328.     return 0;
  329. }
Add Comment
Please, Sign In to add comment