fix line endings

This commit is contained in:
bicarus-dev
2026-08-16 21:23:41 -07:00
parent adf4cccd4a
commit f857926ec3
77 changed files with 25537 additions and 25495 deletions
+213 -213
View File
@@ -1,213 +1,213 @@
#include "gdi_overlay.h"
#include <cstddef>
#include "util/logging.h"
namespace {
// the back buffer matches the window DC; the software buffer has a fixed 32-bit layout
enum class BufferType {
TargetCompatible,
Bgra32,
};
struct GdiBuffer {
HDC dc = nullptr;
HBITMAP bitmap = nullptr;
// bitmap originally selected into the memory DC, restored before cleanup
HGDIOBJ old_bitmap = nullptr;
int width = 0;
int height = 0;
};
// back buffer holds the complete frame; overlay buffer holds ImGui software pixels
GdiBuffer BACK_BUFFER;
GdiBuffer OVERLAY_BUFFER;
void release_buffer(GdiBuffer &buffer) {
// destroy the DC before the bitmap so cleanup is safe even if restoration fails
if (buffer.dc != nullptr) {
if (buffer.old_bitmap != nullptr && buffer.old_bitmap != HGDI_ERROR) {
SelectObject(buffer.dc, buffer.old_bitmap);
}
DeleteDC(buffer.dc);
}
if (buffer.bitmap != nullptr) {
DeleteObject(buffer.bitmap);
}
buffer = {};
}
// ensures the buffer has a memory DC with a bitmap of the requested size and type
// selected into it. a matching allocation is reused; otherwise the old resources are
// released and recreated. returns false if the dimensions or any GDI operation fail.
bool ensure_buffer(
GdiBuffer &buffer,
HDC target_dc,
int width,
int height,
BufferType type,
const char *name) {
if (width <= 0 || height <= 0) {
return false;
}
if (buffer.dc != nullptr && buffer.bitmap != nullptr &&
buffer.width == width && buffer.height == height) {
return true;
}
// keep allocations across frames and recreate only after a size change
release_buffer(buffer);
buffer.dc = CreateCompatibleDC(target_dc);
if (buffer.dc == nullptr) {
log_warning("touch", "failed to create {} DC: {}", name, GetLastError());
return false;
}
// compatible bitmaps are fast presentation targets; BGRA bitmaps accept raw pixels
if (type == BufferType::TargetCompatible) {
buffer.bitmap = CreateCompatibleBitmap(target_dc, width, height);
} else {
buffer.bitmap = CreateBitmap(width, height, 1, sizeof(uint32_t) * 8, nullptr);
}
if (buffer.bitmap == nullptr) {
log_warning("touch", "failed to create {} bitmap: {}", name, GetLastError());
release_buffer(buffer);
return false;
}
buffer.old_bitmap = SelectObject(buffer.dc, buffer.bitmap);
if (buffer.old_bitmap == nullptr || buffer.old_bitmap == HGDI_ERROR) {
log_warning("touch", "failed to select {} bitmap: {}", name, GetLastError());
release_buffer(buffer);
return false;
}
buffer.width = width;
buffer.height = height;
return true;
}
bool update_overlay_buffer(
HDC target_dc,
const uint32_t *pixels,
bool pixels_dirty,
int width,
int height) {
if (pixels == nullptr) {
return false;
}
bool needs_update = pixels_dirty || OVERLAY_BUFFER.bitmap == nullptr ||
OVERLAY_BUFFER.width != width || OVERLAY_BUFFER.height != height;
if (!ensure_buffer(
OVERLAY_BUFFER,
target_dc,
width,
height,
BufferType::Bgra32,
"software overlay")) {
return false;
}
if (!needs_update) {
return true;
}
// SetDIBits requires the destination bitmap not to be selected into a DC
HGDIOBJ overlay_bitmap =
SelectObject(OVERLAY_BUFFER.dc, OVERLAY_BUFFER.old_bitmap);
if (overlay_bitmap == nullptr || overlay_bitmap == HGDI_ERROR) {
log_warning("touch", "failed to deselect software overlay bitmap: {}", GetLastError());
release_buffer(OVERLAY_BUFFER);
return false;
}
BITMAPINFO bitmap_info {};
bitmap_info.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bitmap_info.bmiHeader.biWidth = width;
bitmap_info.bmiHeader.biHeight = -height;
bitmap_info.bmiHeader.biPlanes = 1;
bitmap_info.bmiHeader.biBitCount = sizeof(uint32_t) * 8;
bitmap_info.bmiHeader.biCompression = BI_RGB;
int copied_lines = SetDIBits(
target_dc,
OVERLAY_BUFFER.bitmap,
0,
height,
pixels,
&bitmap_info,
DIB_RGB_COLORS);
HGDIOBJ old_bitmap = SelectObject(OVERLAY_BUFFER.dc, OVERLAY_BUFFER.bitmap);
if (old_bitmap == nullptr || old_bitmap == HGDI_ERROR) {
log_warning("touch", "failed to reselect software overlay bitmap: {}", GetLastError());
release_buffer(OVERLAY_BUFFER);
return false;
}
OVERLAY_BUFFER.old_bitmap = old_bitmap;
if (copied_lines != height) {
log_warning("touch", "failed to update software overlay bitmap: {} of {} lines copied",
copied_lines, height);
release_buffer(OVERLAY_BUFFER);
return false;
}
return true;
}
}
HDC touch_gdi_overlay_begin_frame(
HDC target_dc,
HBRUSH background_brush,
int width,
int height,
const uint32_t *overlay_pixels,
bool overlay_pixels_dirty,
int overlay_width,
int overlay_height) {
if (!ensure_buffer(
BACK_BUFFER,
target_dc,
width,
height,
BufferType::TargetCompatible,
"overlay back buffer")) {
return nullptr;
}
HDC draw_dc = BACK_BUFFER.dc;
SetBkMode(draw_dc, TRANSPARENT);
// start each frame from the transparent color-key background
RECT buffer_rect {0, 0, width, height};
FillRect(draw_dc, &buffer_rect, background_brush);
if (update_overlay_buffer(
target_dc,
overlay_pixels,
overlay_pixels_dirty,
overlay_width,
overlay_height) &&
!BitBlt(draw_dc, 0, 0, overlay_width, overlay_height,
OVERLAY_BUFFER.dc, 0, 0, SRCCOPY)) {
log_warning("touch", "failed to draw software overlay bitmap: {}", GetLastError());
}
return draw_dc;
}
void touch_gdi_overlay_present(HDC target_dc) {
// one full-window blit exposes the completed frame without an intermediate erase
if (!BitBlt(target_dc, 0, 0, BACK_BUFFER.width, BACK_BUFFER.height,
BACK_BUFFER.dc, 0, 0, SRCCOPY)) {
log_warning("touch", "failed to present overlay back buffer: {}", GetLastError());
}
}
void touch_gdi_overlay_release() {
release_buffer(BACK_BUFFER);
release_buffer(OVERLAY_BUFFER);
}
#include "gdi_overlay.h"
#include <cstddef>
#include "util/logging.h"
namespace {
// the back buffer matches the window DC; the software buffer has a fixed 32-bit layout
enum class BufferType {
TargetCompatible,
Bgra32,
};
struct GdiBuffer {
HDC dc = nullptr;
HBITMAP bitmap = nullptr;
// bitmap originally selected into the memory DC, restored before cleanup
HGDIOBJ old_bitmap = nullptr;
int width = 0;
int height = 0;
};
// back buffer holds the complete frame; overlay buffer holds ImGui software pixels
GdiBuffer BACK_BUFFER;
GdiBuffer OVERLAY_BUFFER;
void release_buffer(GdiBuffer &buffer) {
// destroy the DC before the bitmap so cleanup is safe even if restoration fails
if (buffer.dc != nullptr) {
if (buffer.old_bitmap != nullptr && buffer.old_bitmap != HGDI_ERROR) {
SelectObject(buffer.dc, buffer.old_bitmap);
}
DeleteDC(buffer.dc);
}
if (buffer.bitmap != nullptr) {
DeleteObject(buffer.bitmap);
}
buffer = {};
}
// ensures the buffer has a memory DC with a bitmap of the requested size and type
// selected into it. a matching allocation is reused; otherwise the old resources are
// released and recreated. returns false if the dimensions or any GDI operation fail.
bool ensure_buffer(
GdiBuffer &buffer,
HDC target_dc,
int width,
int height,
BufferType type,
const char *name) {
if (width <= 0 || height <= 0) {
return false;
}
if (buffer.dc != nullptr && buffer.bitmap != nullptr &&
buffer.width == width && buffer.height == height) {
return true;
}
// keep allocations across frames and recreate only after a size change
release_buffer(buffer);
buffer.dc = CreateCompatibleDC(target_dc);
if (buffer.dc == nullptr) {
log_warning("touch", "failed to create {} DC: {}", name, GetLastError());
return false;
}
// compatible bitmaps are fast presentation targets; BGRA bitmaps accept raw pixels
if (type == BufferType::TargetCompatible) {
buffer.bitmap = CreateCompatibleBitmap(target_dc, width, height);
} else {
buffer.bitmap = CreateBitmap(width, height, 1, sizeof(uint32_t) * 8, nullptr);
}
if (buffer.bitmap == nullptr) {
log_warning("touch", "failed to create {} bitmap: {}", name, GetLastError());
release_buffer(buffer);
return false;
}
buffer.old_bitmap = SelectObject(buffer.dc, buffer.bitmap);
if (buffer.old_bitmap == nullptr || buffer.old_bitmap == HGDI_ERROR) {
log_warning("touch", "failed to select {} bitmap: {}", name, GetLastError());
release_buffer(buffer);
return false;
}
buffer.width = width;
buffer.height = height;
return true;
}
bool update_overlay_buffer(
HDC target_dc,
const uint32_t *pixels,
bool pixels_dirty,
int width,
int height) {
if (pixels == nullptr) {
return false;
}
bool needs_update = pixels_dirty || OVERLAY_BUFFER.bitmap == nullptr ||
OVERLAY_BUFFER.width != width || OVERLAY_BUFFER.height != height;
if (!ensure_buffer(
OVERLAY_BUFFER,
target_dc,
width,
height,
BufferType::Bgra32,
"software overlay")) {
return false;
}
if (!needs_update) {
return true;
}
// SetDIBits requires the destination bitmap not to be selected into a DC
HGDIOBJ overlay_bitmap =
SelectObject(OVERLAY_BUFFER.dc, OVERLAY_BUFFER.old_bitmap);
if (overlay_bitmap == nullptr || overlay_bitmap == HGDI_ERROR) {
log_warning("touch", "failed to deselect software overlay bitmap: {}", GetLastError());
release_buffer(OVERLAY_BUFFER);
return false;
}
BITMAPINFO bitmap_info {};
bitmap_info.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bitmap_info.bmiHeader.biWidth = width;
bitmap_info.bmiHeader.biHeight = -height;
bitmap_info.bmiHeader.biPlanes = 1;
bitmap_info.bmiHeader.biBitCount = sizeof(uint32_t) * 8;
bitmap_info.bmiHeader.biCompression = BI_RGB;
int copied_lines = SetDIBits(
target_dc,
OVERLAY_BUFFER.bitmap,
0,
height,
pixels,
&bitmap_info,
DIB_RGB_COLORS);
HGDIOBJ old_bitmap = SelectObject(OVERLAY_BUFFER.dc, OVERLAY_BUFFER.bitmap);
if (old_bitmap == nullptr || old_bitmap == HGDI_ERROR) {
log_warning("touch", "failed to reselect software overlay bitmap: {}", GetLastError());
release_buffer(OVERLAY_BUFFER);
return false;
}
OVERLAY_BUFFER.old_bitmap = old_bitmap;
if (copied_lines != height) {
log_warning("touch", "failed to update software overlay bitmap: {} of {} lines copied",
copied_lines, height);
release_buffer(OVERLAY_BUFFER);
return false;
}
return true;
}
}
HDC touch_gdi_overlay_begin_frame(
HDC target_dc,
HBRUSH background_brush,
int width,
int height,
const uint32_t *overlay_pixels,
bool overlay_pixels_dirty,
int overlay_width,
int overlay_height) {
if (!ensure_buffer(
BACK_BUFFER,
target_dc,
width,
height,
BufferType::TargetCompatible,
"overlay back buffer")) {
return nullptr;
}
HDC draw_dc = BACK_BUFFER.dc;
SetBkMode(draw_dc, TRANSPARENT);
// start each frame from the transparent color-key background
RECT buffer_rect {0, 0, width, height};
FillRect(draw_dc, &buffer_rect, background_brush);
if (update_overlay_buffer(
target_dc,
overlay_pixels,
overlay_pixels_dirty,
overlay_width,
overlay_height) &&
!BitBlt(draw_dc, 0, 0, overlay_width, overlay_height,
OVERLAY_BUFFER.dc, 0, 0, SRCCOPY)) {
log_warning("touch", "failed to draw software overlay bitmap: {}", GetLastError());
}
return draw_dc;
}
void touch_gdi_overlay_present(HDC target_dc) {
// one full-window blit exposes the completed frame without an intermediate erase
if (!BitBlt(target_dc, 0, 0, BACK_BUFFER.width, BACK_BUFFER.height,
BACK_BUFFER.dc, 0, 0, SRCCOPY)) {
log_warning("touch", "failed to present overlay back buffer: {}", GetLastError());
}
}
void touch_gdi_overlay_release() {
release_buffer(BACK_BUFFER);
release_buffer(OVERLAY_BUFFER);
}