Тёмный
No video :(

Draw Pixels to a Win32 Window in C with GDI 

Nick Walton
Подписаться 6 тыс.
Просмотров 10 тыс.
50% 1

Опубликовано:

 

26 авг 2024

Поделиться:

Ссылка:

Скачать:

Готовим ссылку...

Добавить в:

Мой плейлист
Посмотреть позже
Комментарии : 50   
@UltimaN3rd
@UltimaN3rd Год назад
The code from this video runs on my PC (CPU i7 3770k) at around 2100 FPS. The footage of the program running at the end of the video is slightly modified - I believe I just made a simple loop to draw 20 pixels per frame instead of 1. I should have gone back and edited the code shown in the video accordingly, to avoid causing confusion when you run the code and see the animation run much slower. With 640x480 = 307k pixels, at 2000 FPS you should expect it to take about 2.5 minutes to fill the window with pixels, so don't be surprised when it doesn't appear to go as fast as in the video. You can speed up the animation by putting a simple for loop around the 2 lines that draw pixels to the screen. Sorry for the confusion; I'll do my best to avoid such mistakes in my future videos.
@blekienomoregames9312
@blekienomoregames9312 Год назад
Great video dude ... It was short, straight to the point, highlighted.
@UltimaN3rd
@UltimaN3rd Год назад
Cheers mate 😊
@pqsk
@pqsk 2 года назад
Nice explanation and I love the random painting.
@UltimaN3rd
@UltimaN3rd 2 года назад
Cheers mate!
@semihartan
@semihartan 3 месяца назад
Hey, just a small correction for Win32 geeks, the HDC doesn't point to the HBITMAP object actually. The SelectObject sets the HBITMAP object you give to it as the default bitmap object that will be affected by the drawing functions on that HDC. That means, you select that bitmap into the HDC. And, every HDC has a default bitmap selected into it, otherwise you cannot draw on that HDC.
@Bits32
@Bits32 6 месяцев назад
Thank you. This was informative.
@UltimaN3rd
@UltimaN3rd 6 месяцев назад
You're welcome mate 😁
@SystemsDevel
@SystemsDevel 2 года назад
Hello! Thanks for the amazing tutorial, I actually ported it successfully to MASM64 assembly! One thing though, Im drawing rectangles and when I move them around the pixels don't redraw so the rects end up leaving a persistent trail, this is because the drawing pixels array is persistent from frame to frame. Is there a way to zero it out at the end of every frame or do I have to do it manually?
@SystemsDevel
@SystemsDevel 2 года назад
okay I added a fillBackground function and now everything works fine =)
@Der_Arathok
@Der_Arathok Год назад
This helped me a lot pursuing my personal Dream of making a game. One Question though... Why is there no NOD if there is a GDI? :P
@UltimaN3rd
@UltimaN3rd Год назад
Maybe that's what Apple uses? 🤔
@starc0w
@starc0w Год назад
Really a very good tutorial! Thank you very much! I really like your style of programming! Besides explicitly casting to (void**)&frame.pixels in line 84, you should look at line 48 again: static unsigned int p = 0; frame.pixels[(p++)%(frame.width*frame.height)] = border32(); The idea would be elegant, however you are willfully letting p overflow with it. Are you sure that the overflow of an unsigned int is not a UB? For signed int the overflow would be UB for sure.
@UltimaN3rd
@UltimaN3rd Год назад
Cheers mate. In C, unsigned types wrap around to 0. UINT_MAX + 1 = 0.
@starc0w
@starc0w Год назад
@@UltimaN3rd Ok, good to know! Thanks! Cheers
@po1sonseede9001
@po1sonseede9001 2 года назад
Do you ever plan on making a community chat room, like IRC or Discord?
@UltimaN3rd
@UltimaN3rd 2 года назад
I don't think there are enough people who want that for it to work out yet, but thanks for the suggestion 😊
@1kvolt1978
@1kvolt1978 Год назад
Doesn't work until frame_bitmap is initialized by CreateDIBSection BEFORE entering message loop. Access violation error.
@UltimaN3rd
@UltimaN3rd Год назад
Did you get that error running the code exactly as provided? I am not able to reproduce it. During CreateWindow, the WindowProcessMessage function is called with several messages. Since the WS_VISIBLE flag is passed, this includes the WM_WINDOWPOSCHANGED message, which then through DefWindowProc sends a WM_SIZE message. Therefore, a WM_SIZE message is handled before the CreateWindow function returns and the main loop is entered. So frame_bitmap gets initialized with CreateDIBSection before the first main loop ever calls PeekMessage().
@1kvolt1978
@1kvolt1978 Год назад
@@UltimaN3rd Kinda. :) I've changed variables names to my style, and organized global vars into one structure, and moved buffer-filling code into separate function for future experiments. Everything else is the same. I ran it through debagger step-by-step and there was jump straight to buffer-filling function without getting WM_SIZE message and thus skipping that branch. It caused Access violation (obviously, we didn't allocate buffer memory at that moment yet). So I initialized buffer with the code from WM-SIZE message branch right after window creation. And everything worked. Actually, now I think, overall it's a safer way to allocate memory without any conditions before trying to write something into it. Because if somehow (like in my case) condition will not be met, there may be an error. I use Windows 7 (may be this is the cause of not getting WM_SIZE message without resizing window?) and Pelles C as IDE/compiler.
@UltimaN3rd
@UltimaN3rd Год назад
@@1kvolt1978 Ah I see, most likely it's a difference in the Windows 7 Win32 API. When I started these tutorials I had intended to write my code such that it would work as far back as possible - probably Windows XP. However I quickly found an important feature of the Win32 API related to high resolution timing that was improved in Windows 10 2004, and eventually decided to just target Windows 10 at a minimum. Perhaps I should have made that clear though in my Windows programming tutorials.
@111marx
@111marx 2 года назад
Hi, I used your code to run on my computer, but not as fast as yours. Did you speed up the video?
@UltimaN3rd
@UltimaN3rd 2 года назад
Yes I sped it up to show the full effect. If you want to test how fast it's actually going you can use the code from my recent tutorial on high precision timing. In my upcoming series of tutorials on making a complete game I'll be showing how to put the rendering code on a separate thread to keep it running at a high refresh rate.
@111marx
@111marx 2 года назад
@@UltimaN3rd oh, ok. I'm trying to write a Win32 based renderer. I found your video when I was looking for pixel processing, very nice tutorial.
@poutineausyropderable7108
@poutineausyropderable7108 Год назад
There's an error on line 91 when you pass frame.pixels to CreateDIBSection. What you have to do is: (void*)&frame.pixels Because the function takes a void pointer.
@UltimaN3rd
@UltimaN3rd Год назад
Yes, you're right. When I wrote this code I was compiling with Microsoft's C compiler which didn't throw an error or warning, but with GCC you do need to cast frame.pixels to a void pointer.
@starc0w
@starc0w Год назад
Yes. But its ja (void**) type not a (void*). So: (void**)&frame.pixels msdn CreateDIBSection: HBITMAP CreateDIBSection( [in] HDC hdc, [in] const BITMAPINFO *pbmi, [in] UINT usage, [out] VOID **ppvBits, [in] HANDLE hSection, [in] DWORD offset ); VOID **ppvBits is type (void**)
@shankar4510
@shankar4510 Год назад
thanks for this . Lifesaver . You are so good . what is a void pointer by the way ?
@starc0w
@starc0w Год назад
​@@shankar4510 A void pointer is a pointer to an "unknown type". The address to which the pointer points could be anything. For this reason, the following things are not allowed with a void pointer and lead to undefined behavior: - Dereferencing a void pointer - Pointer arithmetic on void pointers. However, void pointers may be compared with each other and they may also be checked for NULL. Note: ppvBits is not a void pointer, but a pointer to a void pointer, i.e. void**.
@rhinoturk910
@rhinoturk910 Год назад
@Nick Walton Hey great tutorials! I'm having a little trouble regarding the CreateDIBSection() function within the WindowProcessMessage() function. In the CreateDIBSection() the fourth argument takes a "void**" pointer to a pointer type, but then we are passing in a "uint32_t**" type. When I try to use this, visual studio gives an error stating " 'uint32_t **' is incompatible with parameter of type 'void **' " I do not know what to do beyond this point. I'm trying to do this tutorial in c++ so maybe that's the issue. (I mainly wanted to make my own game engine with GDI but there aren't really any good tutorials in c++ or even GDI in general, and then yours showed up, so thanks btw).
@UltimaN3rd
@UltimaN3rd Год назад
You should be able to cast the type: (void**)&pixels Cheers mate 😊
@rhinoturk910
@rhinoturk910 Год назад
@@UltimaN3rd Thanks!
@billkillernic
@billkillernic 2 года назад
Could you make a code sample for cheking if a particular pixel on the screen changed color and initiate a mouse click on the same coordinate in case of that event?
@UltimaN3rd
@UltimaN3rd 2 года назад
Do you mean a pixel within your own window or anywhere on screen in any program?
@billkillernic
@billkillernic 2 года назад
@@UltimaN3rd Anywhere on the screen e.g if a pixel changes color inside a browser window or on the desktop (E.g because I hit the meta key and the windows start menu popped up causing the pixels near that area to change color )
@UltimaN3rd
@UltimaN3rd 2 года назад
@@billkillernic I don't have the time right now to write that code, but I believe you could put it together from these two links: docs.microsoft.com/en-us/windows/win32/gdi/capturing-an-image docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-sendinput You could continually capture screenshots and compare them to detect updated pixels, then send the mouse clicks you want. Very inefficient but should get the job done.
@alexmuller452
@alexmuller452 Год назад
hey man, great explanation, but i tried the code, got a couple problems that i resolved, only one i am not sure if i resolved right. Using visula studio 2019 it is complaining the entry point is not main. I changed it to WinMain to main and deleted WINAPI next to it. Now it runs, i get a console but nothing else. should i have solved it differently ?
@UltimaN3rd
@UltimaN3rd Год назад
In the text version of this tutorial, you can download the code and build script directly: croakingkero.com/tutorials/drawing_pixels_win32_gdi/ Try following the instructions there (everthing before the "Code Walkthrough") and see if it compiles with the original code and build script downloaded from my site. Cheers.
@alexmuller452
@alexmuller452 Год назад
@@UltimaN3rd Hey man, thanks for the answer, i actually decided to take a step back as it seemed a bit too complicated. I am familiarizing myself with the topic first using Wxwidgets, then it should become easier to take a deeper dive into Windowsapi. Thanks again!
@davidrossington9756
@davidrossington9756 2 года назад
I've got two problems with this tutorial... The first is that GCC is warning me that casting from uint32_t * to void ** in CreateDIBSection is a bad idea.. But that's just a warning. The part that is confusing me is that even though I've linked both gdi32.lib and user32.lib in the command line, it still gives me undefined reference errors for CreateCompatibleDC, BitBlt, DeleteObject, CreateDIBSection, and SelectObject. What's extra weird is that I know wingdi is being included since at the same time CreateDIBSection is being declared as an undefined reference, it's also warning me about incompatible pointer types. Any ideas?
@UltimaN3rd
@UltimaN3rd 2 года назад
What is the exact command you use to build the code with GCC? I was able to compile with this: "gcc main.c -lgdi32" Perhaps your version of GCC/MinGW is no good in some way. If the build command I pasted above doesn't work, what is the output of "gcc -v"?
@davidrossington9756
@davidrossington9756 2 года назад
​@@UltimaN3rd Oh.. that's why. I used capital L instead of lowercase l Now it works Man I feel dumb. Thanks for the response though :)
@UltimaN3rd
@UltimaN3rd 2 года назад
@@davidrossington9756 No problem mate, we can't know every tiny detail in advance, and we often learn by getting it wrong on the first try 👌
@vbachris
@vbachris 2 года назад
can you do some allegro in pure c?
@UltimaN3rd
@UltimaN3rd 2 года назад
I don't plan on using many libraries for these tutorials; I'd rather code as low level as possible for now (except for audio). However I've never used Allegro before so I'll take a good look at it.
@nihonam
@nihonam Год назад
seems not compatible with MinGW: pixelsbuf.c: In function `LRESULT WindowProcessMessage(HWND__*, UINT, WPARAM, LPARAM)': pixelsbuf.c:84: error: invalid conversion from `uint32_t**' to `void**' pixelsbuf.c:84: error: initializing argument 4 of `HBITMAP__* CreateDIBSection(HDC__*, const BITMAPINFO*, UINT, void**, void*, DWORD)'
@UltimaN3rd
@UltimaN3rd Год назад
Cast the pixels pointer to void**, like so: (void**)&pixels
@nihonam
@nihonam Год назад
@@UltimaN3rd Yeeaah, works. Thanx! But freakin slow. And why pixels that are not currently set do change, mutate their color?
@nihonam
@nihonam Год назад
ok, I need to dig into code before any further explaination
@nihonam
@nihonam Год назад
@@UltimaN3rd digged a bit, found place where pixel color generates. replaced it with for(i=0; i
Далее
Win32 Input in C (Keyboard/Mouse)
3:49
Просмотров 3,5 тыс.
Arenas, strings and Scuffed Templates in C
12:28
Просмотров 83 тыс.
skibidi toilet multiverse 041
06:01
Просмотров 5 млн
HOW Win32 Apps Are Made in C
23:54
Просмотров 23 тыс.
Win32 - Drawing Pixels (C)
20:39
Просмотров 27 тыс.
Switching to C - One Year Later
4:43
Просмотров 58 тыс.
Introduction to shaders: Learn the basics!
34:50
Просмотров 322 тыс.
Drawing Graphics with C and Windows API is Easy
5:17
The World's Tallest Pythagoras Cup-Does It Still Drain?
10:05
Master Pointers in C:  10X Your C Coding!
14:12
Просмотров 300 тыс.
Reading/Writing structs to files (aka Serialization)
14:41