Forgotten Coder craziest idea

Pages: 123
Hi

I forgot it. Got you.

How about building a graphics library for c++ ?
Don't kill me just yet ...
I know there tons of graphic libraries for c++ so why the need to invent the wheel again ? well ...
1st: Even new wheels are invented and reinvented.
2nd: People need simplicity and i hate Win32 nightmare :)

The libray will have simple commands like this:

x=0; y=0; width=100; height=200;
screen(x,y,width,height);
putpixel(10,10,RED);

We can start in Windows OS (i don't know any linux programming or others).
When i say "we" is for everyone who wants to contribute with something only if they want of coarse.

The library needs a have a name. Do you like any of the list below ?

1- cppGL ?
2- cppGraphicsLibrary ?
3- GLCPP ?

Any suggestions or advice ? On Windows OS is better to build on top of win32 right ? i am using embarcadero dev c++ ide

Note: you can call me crazy i deserve it BIG LOL
Last edited on
Have you looked at the offerings here:

https://project-awesome.org/fffaraz/awesome-cpp
Hi Duthomhas

Thanks for link.

I searched all the libraries in GUI section and they all basicly suck in simplicity. "Nana" tried simplicity more than all rest putted together but I think project is dead now.
Last edited on
'GL' is taken and has implications. It would imply a derivation of opengl to many readers.

warning, pixel at a time won't cut it. Its just too slow compared to dumping blocks at a time.

windows depends on what you want. directx is king, followed by engines like sdl, unity, etc. If you want to draw in a windows gui form, microsoft all but destroyed c++ for that, c# is the choice or 32 bit is still supported.
Duthomhas: Ooh!

forgottencoder: What's the motivation? What are you trying to solve? If you want to quickly make simple interactive programs with graphics, there are plenty of frameworks that will let you do that. The people who normally use C++ aren't very bothered by complexity. They're bothered by excessive complexity, but existing graphics libraries aren't excessively complex. You're not going to get a lot of traction with a pitch like this.

I could be wrong, but I suspect the problem you're really trying to solve is "having to learn to use someone else's library". Unfortunately the solution you're proposing is much harder than just learning it.
is that or 'the bug' ... every other coder wants to build a game engine at some point in their career (usually, about on year 1). I know I did, at one point.
For stuff where graphics performance isn't critical, software rendering is often "fast enough".
It takes like ten minutes to get a crude put_pixel function going via GDI. This should be enough to get you started.
Make it work, then make it good.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
#include <windows.h>

class [[nodiscard]] w32_screen_buffer
{ 
  BITMAPINFO info_{};
  LPVOID     data_{};
    
public:
  ~w32_screen_buffer() { clear(); }
  w32_screen_buffer() = default;
  w32_screen_buffer(w32_screen_buffer const&)            = delete;
  w32_screen_buffer& operator=(w32_screen_buffer const&) = delete;
    
  [[nodiscard]] LONG              width_px()  const { return info_.bmiHeader.biWidth;     }
  [[nodiscard]] LONG              height_px() const { return -1*info_.bmiHeader.biHeight; }
  [[nodiscard]] LPVOID            data()            { return data_; }
  [[nodiscard]] LPCVOID           data()      const { return data_; }
  [[nodiscard]] BITMAPINFO const& info()      const { return info_; }

  static LONG constexpr bytes_per_pixel = 4;
    
  [[nodiscard]] bool resize(LONG new_width_px, LONG new_height_px)
  {
    SIZE_T const pixels_allocated = info_.bmiHeader.biWidth * info_.bmiHeader.biHeight;
    SIZE_T const pixels_requested = new_width_px * new_height_px;
    SIZE_T const bytes_requested  = bytes_per_pixel * pixels_requested;
  
    if (pixels_allocated < pixels_requested) clear(); else return true;

    // DOCS: https://docs.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-bitmapinfo
    info_.bmiHeader.biSize        = sizeof info_.bmiHeader;
    info_.bmiHeader.biWidth       = new_width_px;
    info_.bmiHeader.biBitCount    = 8 * bytes_per_pixel;
    info_.bmiHeader.biHeight      = -1 * new_height_px;
    info_.bmiHeader.biPlanes      = 1;
    info_.bmiHeader.biCompression = BI_RGB;
  
    data_ = VirtualAlloc(nullptr, bytes_requested, MEM_COMMIT, PAGE_READWRITE);
    if (! data_) clear();
      
    return data_;
  }

  void clear()
  {
    info_.bmiHeader.biWidth = 0;
    info_.bmiHeader.biHeight = 0;
      
    if (data_) VirtualFree(data_, 0, MEM_RELEASE);
  }
};

struct w32_window_dimension { LONG w, h; };
w32_window_dimension window_client_dimensions(HWND window)
{
  RECT r;
  GetClientRect(window, &r);
  return { r.right - r.left, r.bottom - r.top };
}
  
w32_screen_buffer screen_buffer;
bool running = true;

void present_buffer(w32_screen_buffer const& buf, HDC dc, LONG w_px, LONG h_px)
{
  StretchDIBits(dc, 0, 0, w_px, h_px, 0, 0, buf.width_px(), buf.height_px(),
                buf.data(), &buf.info(), DIB_RGB_COLORS, SRCCOPY);
}

void put_pixel(w32_screen_buffer& buf, LONG x, LONG y, ULONG color)
{
  LPBYTE p = reinterpret_cast<LPBYTE>(buf.data());
  LONG   w = buf.width_px();
    
  p += y * buf.bytes_per_pixel * w;
  p += x * buf.bytes_per_pixel;
    
  p[0] = static_cast<BYTE>((color & 0xff000000) >> 24);
  p[1] = static_cast<BYTE>((color & 0x00ff0000) >> 16);
  p[2] = static_cast<BYTE>((color & 0x0000ff00) >> 8);
  p[3] = static_cast<BYTE>((color & 0x000000ff) >> 0);
}

LRESULT CALLBACK my_wndproc(HWND window, UINT msg, WPARAM wp, LPARAM lp)
{
  switch (msg)
  {
  case WM_SIZE:
    (void)::screen_buffer.resize(LOWORD(lp), HIWORD(lp));
    return 0;
  case WM_DESTROY: [[fallthrough]];
  case WM_CLOSE: ::running = false;
    return 0;
  case WM_PAINT:
  {
    PAINTSTRUCT ps;
    HDC dc = BeginPaint(window, &ps);
    auto [w, h] = window_client_dimensions(window);
    present_buffer(::screen_buffer, dc, w, h);
    EndPaint(window, &ps);
    return 0;
  }
  default: return DefWindowProc(window, msg, wp, lp);
  }
}

int WINAPI wWinMain(HINSTANCE instance, HINSTANCE, PWSTR, int)
{
  LPCWSTR class_name = L"GDI Demo";
  WNDCLASSEXW wc {};
  wc.lpszClassName = class_name;
  wc.style         = CS_VREDRAW | CS_HREDRAW | CS_OWNDC;
  wc.lpfnWndProc   = my_wndproc;
  wc.cbSize        = sizeof wc;
  wc.hInstance     = instance;
  wc.hCursor       = LoadCursor(nullptr, IDC_ARROW);
  if (! RegisterClassExW(&wc)) return 1;

  HWND window =
    CreateWindowExW(0, wc.lpszClassName, wc.lpszClassName, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
                    CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, 0, 0,
                    instance, 0);
  if (! window) return 1;

  HDC dc = GetWindowDC(window);
  MSG message {};
  while (::running)
  {
    while (PeekMessage(&message, NULL, 0, 0, PM_REMOVE))
      if (message.message == WM_QUIT) ::running = false; else DispatchMessage(&message);

    auto [w, h] = window_client_dimensions(window);

    // make the top left quarter of the screen red; basically
    // do all your video rendering here
    for (int x = 0; x < w / 2; ++x) 
      for (int y = 0; y < h / 2; ++y)
        put_pixel(::screen_buffer, x, y, 0xff00);
    
    present_buffer(::screen_buffer, dc, w, h);
  }

  return 0;
} 



I searched all the libraries in GUI section and they all basicly suck in simplicity

Did you want a GUI library or a graphics library?

Here is a crude example of a button control - using SDL instead of GDI - but it's the same idea nevertheless. A similar approach can be used to make any interactive control.
In real cases you'll need to remember some things about the controls. Which control is currently active, for instance.
http://cplusplus.com/forum/beginner/279157/#msg1205876
The button example seems fine, although the person it was directed to never got the point.

i am using embarcadero dev c++ ide

You probably won't be able to compile my code without modification;
Consider updating your compiler.
Last edited on
Hi jonin

OpenGL association never come to mind. Nice point of view. My library will not have GL on name.

Well slow or not a one pixel function is a must for this library. A pixel will be the base for this library.

This library will not depend on directx, sdl, unity, etc. I will try to wrap some features only from win32.

It's not a bug it's an itch trying to build a gui library Big Lol :)

It's not a bad idea making a game engine later.

Version 0.1 of library will have only 2 objects (SCREEN and PIXEL) ... Big Lol. And it will be a chalenge to a newbie in C++ like me.
Hi helios

What's the motivation? Simplicity in doing things is my motivation. And i am try to solve that gap in C++ programming. I like more the ++ than the # ... Big Lol.

Most of frameworks are too complex and generally they suck in simplicity. I know people in C++ like a good chalenge and for me the chalenge is simplicity of thought in building things. Most of frameworks have bad documentation and they even lack examples on commands. Well ... my pitch is open to everybody who likes this simple idea of a library. I have no problem in learning frameworks but i don't want to blow my head off in the process. Big Lol.

Note: i know the solution of something like this is a road full of bumps. I will start slowly with small steps :)
hi mbozzi

Do you want to "kill" this newbie with a piece of code like that ? Big Lol.

Made some investigations already ...

1: i ditch my IDE from free embarcadero dev c++ (Big Lol)
2: Now i am using Visual Studio Code with TDM-GCC-64
(typed command "g++ -v" in terminal and got "gcc version 10.3.0")
3: you program is giving me errors on line 98 and 132 with "auto".
It says i need C++ 17.
4: run program below and got "c++ 14".
Bad luck Lol.
5: Still strugling with compiler params ...

1
2
3
4
5
6
7
8
9
10
//c++ version
#include<iostream>

int main() {
    if (__cplusplus == 201703L) std::cout << "C++17\n";
    else if (__cplusplus == 201402L) std::cout << "C++14\n";
    else if (__cplusplus == 201103L) std::cout << "C++11\n";
    else if (__cplusplus == 199711L) std::cout << "C++98\n";
    else std::cout << "pre-standard C++\n";
}


Note: Thanks for code. I will try to investigate more.
Last edited on
So are we talking about GUI or graphics? They are very different beasts.

Most of frameworks are too complex
Let's get to the point. Which frameworks/libraries have you tried and what were your specific problems with them?

It's rare that a library is unnecessarily complex. The complexity is usually proportional to the complexity of the problem the library is trying to solve. For example, the problem "allow an application to display images on the screen efficiently" is more complex (but that complexity doesn't need to increase the complexity of the API very much) than the problem "allow an application to put pixels on the screen, no matter how efficiently". If the latter is all you want I can knock something out for you in less than an hour, but I guarantee it will not be efficient.

Most of frameworks have bad documentation and they even lack examples on commands.
Again, not my experience. Most documentation is okay. There are examples of both excellent documentation and horrid documentation. Actually it's somewhat common for there to be no documentation, or for it to be out of date. But that's only in small projects.
Last edited on
Hi helios

When you are talking about graphics you mean 2D/3D gaming right? This library is not that right now. Not even a GUI. I just want to start with a screen and a pixel object. That's my chalenge for now. And this small step for me will be difficult to achieve. Maybe easier for others. That's a newbie life and all the help will be apreciated.

Found a win32 code for a window. Next chalenge is to figure how to put this in a class called screen.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
#include <windows.h>

const char g_szClassName[] = "myWindowClass";

// Step 4: the Window Procedure
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    switch(msg)
    {
        case WM_CLOSE:
            DestroyWindow(hwnd);
        break;
        case WM_DESTROY:
            PostQuitMessage(0);
        break;
        default:
            return DefWindowProc(hwnd, msg, wParam, lParam);
    }
    return 0;
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
    LPSTR lpCmdLine, int nCmdShow)
{
    WNDCLASSEX wc;
    HWND hwnd;
    MSG Msg;

    //Step 1: Registering the Window Class
    wc.cbSize        = sizeof(WNDCLASSEX);
    wc.style         = 0;
    wc.lpfnWndProc   = WndProc;
    wc.cbClsExtra    = 0;
    wc.cbWndExtra    = 0;
    wc.hInstance     = hInstance;
    wc.hIcon         = LoadIcon(NULL, IDI_APPLICATION);
    wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
    wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
    wc.lpszMenuName  = NULL;
    wc.lpszClassName = g_szClassName;
    wc.hIconSm       = LoadIcon(NULL, IDI_APPLICATION);

    if(!RegisterClassEx(&wc))
    {
        MessageBox(NULL, "Window Registration Failed!", "Error!",
            MB_ICONEXCLAMATION | MB_OK);
        return 0;
    }

    // Step 2: Creating the Window
    hwnd = CreateWindowEx(
        WS_EX_CLIENTEDGE,
        g_szClassName,
        "The title of my window",
        WS_OVERLAPPEDWINDOW,
        CW_USEDEFAULT, CW_USEDEFAULT, 800, 600,
        NULL, NULL, hInstance, NULL);

    if(hwnd == NULL)
    {
        MessageBox(NULL, "Window Creation Failed!", "Error!",
            MB_ICONEXCLAMATION | MB_OK);
        return 0;
    }

    ShowWindow(hwnd, nCmdShow);
    UpdateWindow(hwnd);

    // Step 3: The Message Loop
    while(GetMessage(&Msg, NULL, 0, 0) > 0)
    {
        TranslateMessage(&Msg);
        DispatchMessage(&Msg);
    }
    return Msg.wParam;
}
Well, no wonder you think libraries are too complex if you're starting at this level just to put pixels on the screen. Here's how you create a 800x600 screen in SFML and put a white pixel on it:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <SFML/Graphics.hpp>
#include <RectangleShape.hpp>

int main(){
    sf::RenderWindow window(sf::VideoMode(800, 600), "some title");
    sf::RectangleShape point(sf::Vector2f(1, 1));
    point.setPosition(240, 500);
    point.setFillColor(sf::Color::White);
    while (window.isOpen()){
        window.clear();
        window.draw(point);
        window.display();
    }
}
Is that still too complex for you?
if you want to do the win32 stuff you need to learn about device contexts (DC). They are fairly easy to draw to.
Hi helios

Good example of simplicity but I don't want to construct my library based in SFML or others alike. It's a level on top of a level. I want the lowest level possible for windows OS. So for me is Win32. Forget assembly Big Lol. This is going to hurt my brain for shure.

Note: thanks for example.
Hi jonnin

Device contexts (DC) ? hum ... i think i saw some of that when mbozzi posted code here. I will look up to it later. Now i am strugling with win32 window wrapper. I already learn how to remove WinMain and to hide console window.

I want users to use.

1
2
3
4
5
6
int main() {

 // library code

 return 0;
}


I am so happy Lol.

Note: Thanks for tip
Last edited on
So for me is Win32.

Well, then you really need to learn the basics of how to construct a Windows app.

1. the entry point of a Windows app is WinMain, not main.

2. writing text in a Windows Desktop app is drawing the text as if it were graphics. There are some exceptions.

3. the Win32 API is now known as the Windows Desktop API.

A couple of books I own that use Win32's GDI to create games:
Sams Teach Yourself Game Programming in 24 Hours
https://www.amazon.com/Sams-Teach-Yourself-Programming-Hours/dp/067232461X

Beginning Game Programming
https://www.amazon.com/gp/product/0672326590/

Different editions, same multi-step "build a game engine from scratch" approach.

Yes, you learn how to create a rudimentary game engine using C++ classes and Win32 to make 2D windowed games using the builtin GDI and multimedia libraries in Windows.

What is GDI? Windows graphics device interface. Used to draw images and text to the screen.
https://docs.microsoft.com/en-us/windows/win32/gdi/windows-gdi

GDI is a bunch of C functions. MS later created a C++ class-based framework, GDI+.
https://docs.microsoft.com/en-us/windows/win32/gdiplus/-gdiplus-gdi-start

Then there's DirectX in its multiple incarnations.
https://docs.microsoft.com/en-us/windows/win32/directx

If you don't want to create cross platform apps, or even apps that can run on any device that runs Windows, then using the Windows Desktop API is a way to go.
Hi Furry Guy

Thanks for links. I am not at a level of game programming. I will not program in directx or opengl. Just need gdi to write a pixel.

I will hide every trace of win32 in this library starting with Winmain. Already have a window that works without it.

Strugling with window background color in:

WNDCLASSEX wc;
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);

I want a window with a black background once it is created. :)
The game engine from either of the game programming books hides all the mucky, nitty-gritty details of WinAPI programming within an increasingly more complex set of C++ classes for graphics and multi-media (sound and music) support. No DX or 3rd party libraries.

The initial 2 versions are quite simple compared to the engine later in the books.
I want a window with a black background once it is created.

Well, setting the background brush to a predefined color like COLOR_WINDOW yields a color that is user specific. A user can change the various colors Windows displays, so you don't need to worry about what the color is.

You need to use a stock object color brush instead:
wc.hbrBackground = (HBRUSH) GetStockObject(BLACK_BRUSH); // client area black background

Learning more of the WinAPI would benefit you in the long run.

If'n you are committed to creating Windows apps you really should consider getting Visual Studio 2019 (or 2022 when officially released). You have much better support when creating WinAPI apps than Visual Studio Code will give you.

The entire minimal WinAPI source, hard-wired for Unicode:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
#include <windows.h>

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

int WINAPI wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance,
                    _In_ PWSTR szCmdLine, _In_ int nWinMode)
{
   const WCHAR szAppName[]  = L"BlackBkgrnd";

   WNDCLASSW wc;

   wc.style         = CS_HREDRAW | CS_VREDRAW;
   wc.lpfnWndProc   = WndProc;
   wc.cbClsExtra    = 0;
   wc.cbWndExtra    = 0;
   wc.hInstance     = hInstance;
   wc.hIcon         = (HICON)   LoadImageW(NULL, IDI_APPLICATION, IMAGE_ICON, 0, 0, LR_DEFAULTCOLOR);
   wc.hCursor       = (HCURSOR) LoadImageW(NULL, IDC_ARROW, IMAGE_CURSOR, 0, 0, LR_SHARED);
// wc.hbrBackground = (HBRUSH)  (COLOR_WINDOW + 1);
   wc.hbrBackground = (HBRUSH)  GetStockObject(BLACK_BRUSH); // client area black background
   wc.lpszMenuName  = NULL;
   wc.lpszClassName = szAppName;

   if (0 == RegisterClassW(&wc))
   {
      MessageBoxW(NULL, L"Can't Register the Window Class!", szAppName, MB_OK | MB_ICONERROR);
      return E_FAIL;
   }

   const WCHAR szAppTitle[] = L"Black Background Client Area";

   HWND hwnd = CreateWindowW(szAppName, szAppTitle,
                             WS_OVERLAPPEDWINDOW,
                             CW_USEDEFAULT, CW_USEDEFAULT,
                             CW_USEDEFAULT, CW_USEDEFAULT,
                             NULL, NULL, hInstance, NULL);

   if (NULL == hwnd)
   {
      MessageBoxW(NULL, L"Unable to Create the Main Window!", szAppName, MB_OK | MB_ICONERROR);
      return E_FAIL;
   }

   // show and update the window
   ShowWindow(hwnd, nWinMode);
   UpdateWindow(hwnd);

   MSG msg;

   while (GetMessageW(&msg, NULL, 0, 0))
   {
      TranslateMessage(&msg);
      DispatchMessageW(&msg);
   }

   return (int) msg.wParam;
}

LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
   switch(message)
   {
   case WM_PAINT:
      HDC         hdc;
      PAINTSTRUCT ps;
      hdc = BeginPaint(hwnd, &ps);

      // drawing routine(s) go here
      RECT rect;
      GetClientRect(hwnd, &rect);
      DrawTextW(hdc, L"Hello, Windows!", -1, &rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER);

      EndPaint(hwnd, &ps);
      return S_OK;

   case WM_DESTROY:
      PostQuitMessage(0);
      return S_OK;
   }

   return DefWindowProcW(hwnd, message, wParam, lParam);
}
Pages: 123