Advertisement
alien_fx_fiend

Memory DC PaintCanvas v10 Final (Claude3.5 Sonnet (Working))

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