Advertisement
alien_fx_fiend

Memory DC PaintCanvas Projectv6 (fixing bug + adding saveload)

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