Make a window and draw pixels to it without a library.

How would one do this? I've seen solutions with SDL but I want to create one without any libraries.
you would have to interface to the graphics card driver directly.
SDL is cross-platform. If you want to do what it does yourself, you lose on portability.

That means the answer depends on what platform you are working on.
If you are on Windows, you should look at Win32 API.
If you are on GNU/Linux, you should look at Xlib or XCB.

I don't know about Windows but if you're using Xlib you might do something like this:
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
//Ihatov: WTFPL 2017
#include <stdio.h>
#include <stdlib.h>
#include <X11/Xlib.h>
void drawpixel(Display* di, Window wi, GC gc, int x, int y, int color)
{
	XSetForeground(di, gc, color);
	XDrawPoint(di, wi, gc, x, y);
}
int main() 
{
	//Open Display
	Display *di = XOpenDisplay(getenv("DISPLAY"));
	if (di == NULL) {
		printf("Couldn't open display.\n");
		return -1;
	}

	//Create Window
	int const x = 0, y = 0, width = 640, height = 480, border_width = 1;
	int sc    = DefaultScreen(di);
	Window ro = DefaultRootWindow(di);
	Window wi = XCreateSimpleWindow(di, ro, x, y, width, height, border_width, 
                                BlackPixel(di, sc), WhitePixel(di, sc));
	XMapWindow(di, wi); //Make window visible
	XStoreName(di, wi, "Window sample"); // Set window title
	
	//Prepare the window for drawing
	GC gc = XCreateGC(di, ro, 0, NULL);

	//Select what events the window will listen to
	XSelectInput(di, wi, KeyPressMask | ExposureMask);
	XEvent ev;
	int quit = 0;
	while (!quit) {
		int a = XNextEvent(di, &ev);
		if (ev.type == KeyPress)
			quit = 1; // quit if someone presses a key
		if (ev.type == Expose) {
			drawpixel(di, wi, gc, 10, 10, 0x00ff00); //green
		}
	}
	XFreeGC(di, gc);
	XDestroyWindow(di, wi);
	XCloseDisplay(di);
	return 0;
}

Of course, it looks pretty complicated just to make a window and raw a single pixel.
That's because it's very low level. I know for a fact though that creating a window is even more complicated in Win32.

This is why nobody does this directly, and instead everybody uses a library like SDL, SFML (or toolkits like GTK, Qt) that abstracts away lower level details.

However, maybe you're not satisfied and wonder if this is possible to do in pure C++ without any libraries other than the standard libraries? Sadly no, because you have to interface with the OS somehow in order for it to let you create a window (and C++ is OS independent)
Last edited on
> I know for a fact though that creating a window is even more complicated in Win32.

What? Not it isn’t.

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
#include <stdio.h>
#include <windows.h>

void PaintWindow( HWND hwnd )
{
  PAINTSTRUCT ps;
  HDC hdc = BeginPaint( hwnd, &ps );
  SetPixel( hdc, 10, 10, RGB( 0, 0xFF, 0 ) );  // green
  EndPaint( hwnd, &ps );
}

LRESULT CALLBACK WndProc( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam )
{
  switch (msg)
  {
    case WM_KEYDOWN: // same as pressing the X button:
    case WM_CLOSE:   DestroyWindow( hwnd ); return 0;
    case WM_DESTROY: PostQuitMessage( 0 );  return 0;
    case WM_PAINT:   PaintWindow( hwnd );   return 0;
  }
  return DefWindowProc( hwnd, msg, wParam, lParam );
}

int main()
{
  // Register window class
  WNDCLASSA wc =
  {
    0, WndProc, 0, 0, 0, 
    LoadIcon( NULL, IDI_APPLICATION ),
    LoadCursor( NULL, IDC_ARROW ),
    GetStockObject( BLACK_BRUSH ), // background color == black
    NULL, // no menu
    "ExampleWindowClass"
  };
  
  ATOM wClass = RegisterClassA( &wc );
  if (!wClass)
  {
    fprintf( stderr, "%s\n", "Couldn’t create Window Class" );
    return 1;
  }
  
  // Create the window
  HWND hwnd = CreateWindowA(
    MAKEINTATOM( wClass ),
    "Window sample",     // window title
    WS_OVERLAPPEDWINDOW, // title bar, thick borders, etc.
    CW_USEDEFAULT, CW_USEDEFAULT, 640, 480,
    NULL, // no parent window
    NULL, // no menu
    GetModuleHandle( NULL ),  // EXE's HINSTANCE
    NULL  // no magic user data
  );
  if (!hwnd)
  {
    fprintf( stderr, "%ld\n", GetLastError() );
    fprintf( stderr, "%s\n", "Failed to create Window" );
    return 1;
  }
  
  // Make window visible
  ShowWindow( hwnd, SW_SHOWNORMAL );
  
  // Event loop
  MSG msg;
  while (GetMessage( &msg, NULL, 0, 0 ) > 0)
  {
    TranslateMessage( &msg );
    DispatchMessage( &msg );
  }
  
  return msg.wParam;
}

I tried to follow your example program closely — the two should work very similarly.

You take a few shortcuts with your code that I wouldn’t. I’ve done similarly in this Win32 example. Notably, I would have checked that XCreateSimpleWindow() succeeded. I added code to check this in the Win32 version.

BTW, never return negative numbers from main(). If you have an error, return 1.

Your point remains valid, though: get a library to do pixel pushing.

[edit] Oh yeah, don’t forget to link with libgdi32 when compiling.
Last edited on
Win API: We can create a console application and then draw things directly on the console. For instance:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <iostream>
#include <cstdlib>
#include <windows.h>

int main()
{
    const auto console = ::GetConsoleWindow() ;
    const auto context = ::GetDC(console) ;
    constexpr auto red = RGB( 255, 0, 0 ) ;
    constexpr auto yellow = RGB( 255, 255, 0 ) ;

    for( int i = 100 ; i < 200 ; ++i ) for( int j = 100 ; j < 200 ; ++j )
        ::SetPixel( context, i, j, std::abs(i-j) > 25 ? red : yellow );
}
1
2
3
4
5
6
7
#if _WIN32_WINNT < 0x0500
  #undef _WIN32_WINNT
#endif

#ifndef _WIN32_WINNT
  #define _WIN32_WINNT 0x0500
#endif 
 
  const HWND hConsole = GetConsoleWindow();
Topic archived. No new replies allowed.