How exactly do I draw to a BDirectWindow?

I’m trying to develop a game for Haiku using its native API, and I’ve looked at the BeBook page on BDirectWindow, but I’m not exactly sure how we’re drawing to the screen. I understand there’s something to do with clip_rects, but I’m not exactly sure what it is they do. Are they regions of the window not overlapped by other windows? If so, how may I know where exactly my pixel is. If I can just figure out how to plot a color to a specific {X,Y} coordinate, I think I’ll be able to roll all the rest of the necessary functions I’d need for this.

UPDATE: Found this https://github.com/HaikuArchives/BeSampleCode/tree/haiku/game_kit

Hopefully the code’ll help. Wish me luck!

1 Like

DO NOT USE BDirectWindow ever. It is obsolete and can’t work properly at all on some hardware (for example on VMWare with guest additions or on real hardware that need manual handling of cache coherence). In near future it may stop working at all for most hardware because of implementing screen hardware double buffering and flipping.

5 Likes

Thanks! That’s good to know. What do you recommend? Just regular old BWindow?

Also I just followed you on Github today, coincidentally, as I heard you were helping out with hardware acceleration support – how’s that coming along?

Yes. You can use BWindow, BView and BBitmap for rendering game graphics. It will work fast enough for any hardware suitable for Haiku. You can also use BWindowScreen for easy full screen mode support.

1 Like

Fantastic, thank you! Supposing I want to draw to different buffers as different layers and then composite them together to do something like a HUD overlay or pause menu/in-game GUI, which of those would you recommend, or will any of them work fine?

It depends on game graphics complexity. If using Haiku API, you can use BView::DrawBitmap with alpha channel to draw sprites or layers. It also support setting a matrix for affine transformations. If complex fast graphics are needed, you may want to look at OpenGL/Vulkan.

1 Like

Thanks again so much for taking your time to help me, I figured I’d have to wait until morning to get any response.

Well, I’m thinking of making something like DooM/Wolf3D in terms of complexity, for what that’s worth.

If your game wants to do its own rendering to a bitmap, it may be better to set that up on screen using BView::SetViewBitmap rather than BView::DrawBitmap. In that case, you set the bitmap once, and then you just need to Invalidate() the view when you want it to show the data.

On the other hand, DrawBitmap may allow for better synchronization if you have problems with tearing or other glitches.

I think the API can be made to work regardless, even if it won’t be as “direct” as the name says. So, I think it’s fine to use it, but you will have a lot more complex job than what’s really needed.

No, SetViewBitmap should be not used for dynamically changing contents because there are currently no mechanisms of synchronization. It will cause rendering artifacts such as flickering and showing immediate stages of drawing. SetViewBitmap is currently useful only for static bitmaps. For many people including me such artifacts are unacceptable. Flickering images may cause seizures for people with epilepsy.

Current API will stop working when hardware framebuffer flipping will be implemented (it is required to avoid tearing on modern hardware). So framebuffer address may suddenly change during drawing using BDirectWindow, causing terrible artifacts.

Supporting BDirectWindow for framebuffer flipping will require incompatible API changes or framebuffer emulation by using fake framebuffer and drawing it on real framebuffer by timer. It of course will be less efficient than using BView::DrawBitmap.

1 Like

I’m not sure you need a timer, you can just wait until the direct window is unlocked by the drawing thread, and either do a fake framebuffer to framebuffer copy after that, or just lock the framebuffer flip until the direct window is unlocked (which should happen at every frame anyways). Then you send a new DirectConnected at every buffer flip, to update the pointer to the new framebuffer.

It will still not be the best and most efficient API for sure, but it will still work.

It depends how you use it. Indeed if you draw directly to that bitmap, it will be a problem. But you can draw to another bitmap and then manually copy the updated areas, for example.

Or, in my case, I use SetViewBitmap in an emulator. The emulator emulates the CRT display refresh of the original machine and so it always writes “finished” pixels to the bitmap, from top to bottom and left to right. There are no intermediate states in this case.

Also, if you use Invalidate() correctly, there will be glitches only if the window is being refreshed for other reasons (typically, you are dragging another window on top). You have to try very hard if you want to make a really bad flickering mess.

I made a simple test that demonstrates problem. It draw overlapping rectangles and call Invalidate() after finishing drawing. As you can see there are white stripe artifacts present.

It is fundamentally impossible to properly show animations with SetViewBitmap if drawing contains overlapping figures.

1 Like

In this case it will not cause flickering artifacts, but still cause tearing artifacts even after proper framebuffer flipping and synchronization will be implemented in app_server.

As a rule of thumb, NEVER use SetViewBitmap for animations until proper synchronization API will be added. It do not worth it, DrawBitmap is fast enough, even on VisionFive 2.

1 Like

There will always be artifacts unless I can set the display refresh rate to an exact multiple of the 50.02Hz or so that the emulated hardware is displaying at. Either tearing, or frame repeats, which don’t look great either.

It is on my TODO list to get to that, but I need to fix a few things in the Intel graphics driver first…

While it is currently not possible to synchronize single BBitmap when using SetViewBitmap, it is possible to free BBitmap after SetViewBitmap call and allocate new BBitmap when rendering new frame. As long you will not modify BBitmap after sending it to SetViewBitmap, you will be fine.

1 Like

Oh, hell yeah, I want one of those. How is the RISC-V port of Haiku at the moment?

Also, what would you recommend for networking? I’m thinking of using the Network Kit, but the API seems a bit sparse. My goal is to make as much of this project use the Be/Haiku API as possible.