Advertisement
alien_fx_fiend

Memory DC PaintCanvas Projectv10 Experimental Broken

Jul 12th, 2024
76
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 13.75 KB | None | 0 0
  1. #include <vector>
  2. #include <windows.h>
  3. #include <fstream>
  4. #include <string>
  5. #include <commdlg.h>
  6. #include <codecvt>
  7. #include <algorithm>
  8.  
  9. using namespace std;
  10.  
  11. struct Brushstroke;
  12. struct Eraserstroke;
  13. HWND hWnd;
  14. HINSTANCE hInst;
  15. bool IsPointInClientRect(HWND hwnd, int x, int y) {
  16.     RECT rect;
  17.     GetClientRect(hwnd, &rect);
  18.     return (x >= 0 && x < rect.right&& y >= 0 && y < rect.bottom);
  19. }
  20.  
  21. struct Brushstroke {
  22.     int x;
  23.     int y;
  24.     int size;
  25.     COLORREF color;
  26.     void serialize(ofstream& outFile) const {
  27.         outFile << "B " << x << " " << y << " " << size << " "
  28.             << (int)GetRValue(color) << " "
  29.             << (int)GetGValue(color) << " "
  30.             << (int)GetBValue(color) << endl;
  31.     }
  32. };
  33.  
  34. struct Eraserstroke {
  35.     int x;
  36.     int y;
  37.     int size;
  38.     COLORREF color;
  39.     void serialize(ofstream& outFile) const {
  40.         outFile << "E " << x << " " << y << " " << size << endl;
  41.     }
  42. };
  43.  
  44. std::vector<Brushstroke> storedBrushstrokes;
  45. std::vector<Eraserstroke> storedEraserstrokes;
  46.  
  47. void RedrawStrokes();
  48. void SaveDrawing(const string& filename);
  49. void LoadDrawing(const string& filename);
  50.  
  51. POINT previousPoint;
  52. HDC hdc, memDC;
  53. HBITMAP memBitmap;
  54.  
  55. bool isPaintbrushSelected = true;
  56. bool isDrawing = false;
  57. bool isErasing = false;
  58. bool isClearing = false;
  59. bool isEraserSelected = false;
  60. int brushSize = 10;
  61.  
  62. void DrawBrush(HDC hdc, int x, int y) {
  63.     if (!IsPointInClientRect(hWnd, x, y)) return;
  64.     HGDIOBJ originalBrush = SelectObject(hdc, CreateSolidBrush(RGB(255, 0, 0)));
  65.     HGDIOBJ originalPen = SelectObject(hdc, GetStockObject(NULL_PEN));
  66.     Ellipse(hdc, x - brushSize, y - brushSize, x + brushSize, y + brushSize);
  67.     DeleteObject(SelectObject(hdc, originalBrush));
  68.     DeleteObject(SelectObject(hdc, originalPen));
  69. }
  70.  
  71. void Erase(HDC hdc, int x, int y, int eraserSize) {
  72.     if (!IsPointInClientRect(hWnd, x, y)) return;
  73.     HBRUSH hBrush = CreateSolidBrush(RGB(255, 255, 255));
  74.     SelectObject(hdc, GetStockObject(NULL_PEN));
  75.     SelectObject(hdc, hBrush);
  76.     Ellipse(hdc, x - eraserSize, y - eraserSize, x + eraserSize, y + eraserSize);
  77.     DeleteObject(hBrush);
  78.  
  79.     // Remove brushstrokes that intersect with the eraser
  80.     storedBrushstrokes.erase(
  81.         std::remove_if(storedBrushstrokes.begin(), storedBrushstrokes.end(),
  82.             [x, y, eraserSize](const Brushstroke& stroke) {
  83.                 int dx = stroke.x - x;
  84.                 int dy = stroke.y - y;
  85.                 return (dx * dx + dy * dy) <= (eraserSize + stroke.size) * (eraserSize + stroke.size);
  86.             }),
  87.         storedBrushstrokes.end()
  88.                 );
  89. }
  90.  
  91. // Update the ClearDrawing function
  92. void ClearDrawing(HWND hwnd) {
  93.     RECT rect;
  94.     GetClientRect(hwnd, &rect);
  95.     HBRUSH hBrush = CreateSolidBrush(RGB(255, 255, 255));
  96.  
  97.     // Clear both hdc AND memDC
  98.     HDC hdc = GetDC(hwnd);
  99.     FillRect(hdc, &rect, hBrush);
  100.     FillRect(memDC, &rect, hBrush);
  101.     ReleaseDC(hwnd, hdc);
  102.  
  103.     DeleteObject(hBrush);
  104.     storedBrushstrokes.clear();
  105.  
  106.     InvalidateRect(hwnd, NULL, FALSE);
  107.     UpdateWindow(hwnd);
  108. }
  109.  
  110. void DrawSmoothBrush(HDC hdc, int x, int y) {
  111.     if (isDrawing && (isPaintbrushSelected || isEraserSelected)) {
  112.         int numPoints = 3;
  113.         POINT currentPoint = { x, y };
  114.         for (int i = 1; i <= numPoints; i++) {
  115.             float t = (float)i / (float)numPoints;
  116.             int smoothX = (int)(previousPoint.x + t * (currentPoint.x - previousPoint.x));
  117.             int smoothY = (int)(previousPoint.y + t * (currentPoint.y - previousPoint.y));
  118.             if (isPaintbrushSelected) {
  119.                 DrawBrush(hdc, smoothX, smoothY);
  120.                 Brushstroke newBrushstroke;
  121.                 newBrushstroke.x = smoothX;
  122.                 newBrushstroke.y = smoothY;
  123.                 newBrushstroke.size = brushSize;
  124.                 newBrushstroke.color = RGB(255, 0, 0);
  125.                 storedBrushstrokes.push_back(newBrushstroke);
  126.             }
  127.             else if (isEraserSelected) {
  128.                 Erase(hdc, smoothX, smoothY, brushSize);
  129.                 Eraserstroke newEraserstroke;
  130.                 newEraserstroke.x = smoothX;
  131.                 newEraserstroke.y = smoothY;
  132.                 newEraserstroke.size = brushSize;
  133.                 newEraserstroke.color = RGB(255, 255, 255);
  134.                 storedEraserstrokes.push_back(newEraserstroke);
  135.             }
  136.         }
  137.         previousPoint = currentPoint;
  138.     }
  139. }
  140.  
  141. void RedrawStrokes() {
  142.     // Clear the entire drawing area
  143.     RECT rect;
  144.     GetClientRect(hWnd, &rect);
  145.     HBRUSH hBrush = CreateSolidBrush(RGB(255, 255, 255));
  146.     FillRect(memDC, &rect, hBrush);
  147.     DeleteObject(hBrush);
  148.  
  149.     // Redraw all brushstrokes
  150.     for (const auto& brushstroke : storedBrushstrokes) {
  151.         HGDIOBJ originalBrush = SelectObject(memDC, CreateSolidBrush(brushstroke.color));
  152.         HGDIOBJ originalPen = SelectObject(memDC, GetStockObject(NULL_PEN));
  153.         Ellipse(memDC, brushstroke.x - brushstroke.size, brushstroke.y - brushstroke.size,
  154.             brushstroke.x + brushstroke.size, brushstroke.y + brushstroke.size);
  155.         DeleteObject(SelectObject(memDC, originalBrush));
  156.         DeleteObject(SelectObject(memDC, originalPen));
  157.     }
  158.  
  159.     // Update the window
  160.     InvalidateRect(hWnd, NULL, FALSE);
  161.     UpdateWindow(hWnd);
  162. }
  163.  
  164. void SaveDrawing(const string& filename) {
  165.     ofstream outFile(filename);
  166.     if (outFile.is_open()) {
  167.         outFile << storedBrushstrokes.size() << endl;
  168.         for (const auto& brushstroke : storedBrushstrokes) {
  169.             brushstroke.serialize(outFile);
  170.         }
  171.         outFile.close();
  172.     }
  173. }
  174.  
  175. void LoadDrawing(const string& filename) {
  176.     ifstream inFile(filename);
  177.     if (inFile.is_open()) {
  178.         int numBrushstrokes;
  179.         inFile >> numBrushstrokes;
  180.         storedBrushstrokes.clear();
  181.         storedBrushstrokes.reserve(numBrushstrokes);
  182.         for (int i = 0; i < numBrushstrokes; ++i) {
  183.             char type;
  184.             Brushstroke brushstroke;
  185.             int r, g, b;
  186.             inFile >> type >> brushstroke.x >> brushstroke.y >> brushstroke.size >> r >> g >> b;
  187.             brushstroke.color = RGB(r, g, b);
  188.             storedBrushstrokes.push_back(brushstroke);
  189.         }
  190.         inFile.close();
  191.         RedrawStrokes();
  192.     }
  193. }
  194.  
  195. void SaveDrawingDialog(HWND hwnd) {
  196.     OPENFILENAME ofn;
  197.     wchar_t szFileName[MAX_PATH] = L"";
  198.  
  199.     ZeroMemory(&ofn, sizeof(ofn));
  200.     ofn.lStructSize = sizeof(ofn);
  201.     ofn.hwndOwner = hwnd;
  202.     ofn.lpstrFilter = L"Text Files (*.txt)\0*.txt\0All Files (*.*)\0*.*\0";
  203.     ofn.lpstrFile = szFileName;
  204.     ofn.nMaxFile = MAX_PATH;
  205.     ofn.Flags = OFN_EXPLORER | OFN_OVERWRITEPROMPT;
  206.     ofn.lpstrDefExt = L"txt";
  207.  
  208.     if (GetSaveFileName(&ofn)) {
  209.         std::wstring_convert < std::codecvt_utf8 < wchar_t>> converter;
  210.         std::string filenameStr = converter.to_bytes(szFileName);
  211.         SaveDrawing(filenameStr);
  212.         MessageBox(hwnd, L"Save Complete", L"Doodle App", MB_OK | MB_ICONINFORMATION);
  213.     }
  214. }
  215.  
  216. void LoadDrawingDialog(HWND hwnd) {
  217.     OPENFILENAME ofn;
  218.     wchar_t szFileName[MAX_PATH] = L"";
  219.  
  220.     ZeroMemory(&ofn, sizeof(ofn));
  221.     ofn.lStructSize = sizeof(ofn);
  222.     ofn.hwndOwner = hwnd;
  223.     ofn.lpstrFilter = L"Text Files (*.txt)\0*.txt\0All Files (*.*)\0*.*\0";
  224.     ofn.lpstrFile = szFileName;
  225.     ofn.nMaxFile = MAX_PATH;
  226.     ofn.Flags = OFN_EXPLORER | OFN_FILEMUSTEXIST;
  227.  
  228.     if (GetOpenFileName(&ofn)) {
  229.         std::wstring_convert<std::codecvt_utf8<wchar_t>> converter;
  230.         std::string filenameStr = converter.to_bytes(szFileName);
  231.         LoadDrawing(filenameStr);
  232.     }
  233. }
  234.  
  235. void SanitizeAndSaveDrawing(const string& filename) {
  236.     ofstream outFile(filename);
  237.     if (outFile.is_open()) {
  238.         RECT rect;
  239.         GetClientRect(hWnd, &rect);
  240.  
  241.         vector<Brushstroke> validBrushstrokes;
  242.         for (const auto& brushstroke : storedBrushstrokes) {
  243.             if (IsPointInClientRect(hWnd, brushstroke.x, brushstroke.y)) {
  244.                 validBrushstrokes.push_back(brushstroke);
  245.             }
  246.         }
  247.  
  248.         outFile << validBrushstrokes.size() << endl;
  249.         for (const auto& brushstroke : validBrushstrokes) {
  250.             brushstroke.serialize(outFile);
  251.         }
  252.         outFile.close();
  253.     }
  254. }
  255. LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
  256.     switch (uMsg) {
  257.     case WM_CREATE:
  258.     {
  259.         hWnd = hwnd;
  260.         RECT rect;
  261.         GetClientRect(hwnd, &rect);
  262.         HDC hdc = GetDC(hwnd);
  263.         memDC = CreateCompatibleDC(hdc);
  264.         memBitmap = CreateCompatibleBitmap(hdc, rect.right - rect.left, rect.bottom - rect.top);
  265.         SelectObject(memDC, memBitmap);
  266.         ReleaseDC(hwnd, hdc);
  267.         HBRUSH hBrush = CreateSolidBrush(RGB(255, 255, 255));
  268.         FillRect(memDC, &rect, hBrush);
  269.         DeleteObject(hBrush);
  270.         isPaintbrushSelected = true;
  271.         LoadDrawing("drawing.txt");
  272.     }
  273.     break;
  274.     case WM_KEYDOWN:
  275.         if (wParam == VK_ADD) {
  276.             brushSize += 5;
  277.         }
  278.         else if (wParam == VK_SUBTRACT) {
  279.             if (brushSize > 5) {
  280.                 brushSize -= 5;
  281.             }
  282.         }
  283.         else if (wParam == 0x43) { // 'C' key
  284.             if (!(GetKeyState(VK_CONTROL) & 0x8000)) {
  285.                 ClearDrawing(hwnd);
  286.             }
  287.         }
  288.         else if (wParam == 0x50) {
  289.             isPaintbrushSelected = true;
  290.             isEraserSelected = false;
  291.         }
  292.         else if (wParam == 0x45) {
  293.             isEraserSelected = true;
  294.             isPaintbrushSelected = false;
  295.         }
  296.         else if (wParam == 'S' && (GetKeyState(VK_CONTROL) & 0x8000)) {
  297.             SaveDrawingDialog(hwnd);
  298.         }
  299.         else if (wParam == 'O' && (GetKeyState(VK_CONTROL) & 0x8000)) {
  300.             LoadDrawingDialog(hwnd);
  301.         }
  302.         break;
  303.     case WM_LBUTTONDOWN:
  304.         if (isPaintbrushSelected || isEraserSelected) {
  305.             previousPoint.x = LOWORD(lParam);
  306.             previousPoint.y = HIWORD(lParam);
  307.         }
  308.         isDrawing = true;
  309.         break;
  310.     case WM_LBUTTONUP:
  311.         isDrawing = false;
  312.         break;
  313.     case WM_MOUSEMOVE:
  314.         if (isDrawing && isPaintbrushSelected) {
  315.             int x = LOWORD(lParam);
  316.             int y = HIWORD(lParam);
  317.             DrawSmoothBrush(memDC, x, y);
  318.             InvalidateRect(hwnd, NULL, FALSE);
  319.             if (IsPointInClientRect(hWnd, x, y)) {
  320.                 Brushstroke newBrushstroke;
  321.                 newBrushstroke.x = x;
  322.                 newBrushstroke.y = y;
  323.                 newBrushstroke.size = brushSize;
  324.                 newBrushstroke.color = RGB(255, 0, 0);
  325.                 storedBrushstrokes.push_back(newBrushstroke);
  326.             }
  327.         }
  328.         else if (isDrawing && isEraserSelected) {
  329.             int x = LOWORD(lParam);
  330.             int y = HIWORD(lParam);
  331.             Erase(memDC, x, y, brushSize);
  332.             InvalidateRect(hwnd, NULL, FALSE);
  333.         }
  334.         break;
  335.     case WM_SIZE:
  336.     {
  337.         static bool isMinimized = false;
  338.         if (wParam == SIZE_MINIMIZED)
  339.         {
  340.             isMinimized = true;
  341.         }
  342.         else if (wParam == SIZE_MAXIMIZED || wParam == SIZE_RESTORED)
  343.         {
  344.             if (isMinimized)
  345.             {
  346.                 isMinimized = false;
  347.             }
  348.             InvalidateRect(hwnd, NULL, TRUE);
  349.         }
  350.         RECT rect;
  351.         GetClientRect(hwnd, &rect);
  352.         if (memDC)
  353.         {
  354.             DeleteDC(memDC);
  355.             DeleteObject(memBitmap);
  356.         }
  357.         HDC hdc = GetDC(hwnd);
  358.         memDC = CreateCompatibleDC(hdc);
  359.         memBitmap = CreateCompatibleBitmap(hdc, rect.right - rect.left, rect.bottom - rect.top);
  360.         SelectObject(memDC, memBitmap);
  361.         ReleaseDC(hwnd, hdc);
  362.         HBRUSH hBrush = CreateSolidBrush(RGB(255, 255, 255));
  363.         FillRect(memDC, &rect, hBrush);
  364.         DeleteObject(hBrush);
  365.         RedrawStrokes();
  366.     }
  367.     break;
  368.     case WM_PAINT:
  369.     {
  370.         PAINTSTRUCT ps;
  371.         HDC hdc = BeginPaint(hwnd, &ps);
  372.         BitBlt(hdc, 0, 0, ps.rcPaint.right, ps.rcPaint.bottom, memDC, 0, 0, SRCCOPY);
  373.         EndPaint(hwnd, &ps);
  374.     }
  375.     break;
  376.     case WM_SETCURSOR:
  377.         if (LOWORD(lParam) == HTCLIENT) {
  378.             SetCursor(LoadCursor(NULL, IDC_ARROW));
  379.             return TRUE;
  380.         }
  381.         break;
  382.     case WM_CLOSE:
  383.         // Sanitize and save before closing
  384.         SanitizeAndSaveDrawing("drawing.txt");
  385.         DestroyWindow(hwnd);
  386.         break;
  387.     case WM_DESTROY:
  388.         DeleteDC(memDC);
  389.         DeleteObject(memBitmap);
  390.         PostQuitMessage(0);
  391.         break;
  392.     default:
  393.         return DefWindowProc(hwnd, uMsg, wParam, lParam);
  394.     }
  395. }
  396.  
  397. int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
  398.     const wchar_t CLASS_NAME[] = L"PaintCanvasWindowClass";
  399.     WNDCLASS wc = { };
  400.  
  401.     wc.lpfnWndProc = WindowProc;
  402.     wc.hInstance = hInstance;
  403.     wc.lpszClassName = CLASS_NAME;
  404.  
  405.     RegisterClass(&wc);
  406.     HWND hwnd = CreateWindowEx(
  407.         0,                              // Optional window styles
  408.         CLASS_NAME,                     // Window class
  409.         L"Paint Canvas App",            // Window text
  410.         WS_OVERLAPPEDWINDOW | WS_MAXIMIZE,            // Window style
  411.  
  412.         // Size and position
  413.         CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
  414.  
  415.         NULL,       // Parent window    
  416.         NULL,       // Menu
  417.         hInstance,  // Instance handle
  418.         NULL        // Additional application data
  419.     );
  420.  
  421.     if (hwnd == NULL) {
  422.         return 0;
  423.     }
  424.  
  425.     ShowWindow(hwnd, SW_SHOWMAXIMIZED);
  426.     // Run the message loop
  427.     MSG msg = { };
  428.     while (GetMessage(&msg, NULL, 0, 0)) {
  429.         TranslateMessage(&msg);
  430.         DispatchMessage(&msg);
  431.     }
  432.  
  433.     return 0;
  434. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement