Some optimizations.
This commit is contained in:
parent
7a1777ebfc
commit
73f7e37ba6
5 changed files with 152 additions and 108 deletions
|
|
@ -155,7 +155,7 @@ static void compositeAndFlush(AppContextT *ctx) {
|
|||
drawCursorAt(ctx, ctx->mouseX, ctx->mouseY);
|
||||
|
||||
// 5. Flush this dirty rect to LFB
|
||||
flushRect(d, ops, dr);
|
||||
flushRect(d, dr);
|
||||
}
|
||||
|
||||
resetClipRect(d);
|
||||
|
|
|
|||
|
|
@ -4,6 +4,8 @@
|
|||
|
||||
#include <string.h>
|
||||
|
||||
#define DIRTY_MERGE_GAP 4
|
||||
|
||||
// ============================================================
|
||||
// Prototypes
|
||||
// ============================================================
|
||||
|
|
@ -82,7 +84,7 @@ void dirtyListMerge(DirtyListT *dl) {
|
|||
|
||||
for (int32_t i = 0; i < dl->count; i++) {
|
||||
for (int32_t j = i + 1; j < dl->count; j++) {
|
||||
if (rectsOverlapOrAdjacent(&dl->rects[i], &dl->rects[j], 4)) {
|
||||
if (rectsOverlapOrAdjacent(&dl->rects[i], &dl->rects[j], DIRTY_MERGE_GAP)) {
|
||||
rectUnion(&dl->rects[i], &dl->rects[j], &dl->rects[i]);
|
||||
dl->rects[j] = dl->rects[dl->count - 1];
|
||||
dl->count--;
|
||||
|
|
@ -99,9 +101,7 @@ void dirtyListMerge(DirtyListT *dl) {
|
|||
// flushRect
|
||||
// ============================================================
|
||||
|
||||
void flushRect(DisplayT *d, const BlitOpsT *ops, const RectT *r) {
|
||||
(void)ops;
|
||||
|
||||
void flushRect(DisplayT *d, const RectT *r) {
|
||||
int32_t bpp = d->format.bytesPerPixel;
|
||||
|
||||
int32_t x = r->x;
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ void dirtyListMerge(DirtyListT *dl);
|
|||
void dirtyListClear(DirtyListT *dl);
|
||||
|
||||
// Flush a single rectangle from backbuffer to LFB
|
||||
void flushRect(DisplayT *d, const BlitOpsT *ops, const RectT *r);
|
||||
void flushRect(DisplayT *d, const RectT *r);
|
||||
|
||||
// Intersect two rectangles, returns true if intersection is non-empty
|
||||
bool rectIntersect(const RectT *a, const RectT *b, RectT *result);
|
||||
|
|
|
|||
|
|
@ -368,6 +368,7 @@ int32_t videoInit(DisplayT *d, int32_t requestedW, int32_t requestedH, int32_t p
|
|||
|
||||
if (!d->backBuf) {
|
||||
fprintf(stderr, "VBE: Failed to allocate %lu byte backbuffer\n", (unsigned long)fbSize);
|
||||
__djgpp_nearptr_disable();
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
|
@ -381,6 +382,7 @@ int32_t videoInit(DisplayT *d, int32_t requestedW, int32_t requestedH, int32_t p
|
|||
fprintf(stderr, "VBE: Failed to allocate palette\n");
|
||||
free(d->backBuf);
|
||||
d->backBuf = NULL;
|
||||
__djgpp_nearptr_disable();
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
|
|
|||
238
dvx/dvxWm.c
238
dvx/dvxWm.c
|
|
@ -10,11 +10,37 @@
|
|||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
// ============================================================
|
||||
// Constants
|
||||
// ============================================================
|
||||
|
||||
#define GADGET_PAD 2
|
||||
#define GADGET_INSET 2 // inset from title bar edges
|
||||
|
||||
// ============================================================
|
||||
// Title bar gadget geometry
|
||||
// ============================================================
|
||||
|
||||
typedef struct {
|
||||
int32_t titleX;
|
||||
int32_t titleY;
|
||||
int32_t titleW;
|
||||
int32_t titleH;
|
||||
int32_t gadgetS; // gadget square size
|
||||
int32_t gadgetY; // gadget Y position
|
||||
int32_t closeX; // close gadget X
|
||||
int32_t minX; // minimize gadget X
|
||||
int32_t maxX; // maximize gadget X (-1 if not resizable)
|
||||
int32_t textLeftEdge; // left edge of title text area
|
||||
int32_t textRightEdge; // right edge of title text area
|
||||
} TitleGeomT;
|
||||
|
||||
// ============================================================
|
||||
// Prototypes
|
||||
// ============================================================
|
||||
|
||||
static void computeMenuBarPositions(WindowT *win, const BitmapFontT *font);
|
||||
static void computeTitleGeom(const WindowT *win, TitleGeomT *g);
|
||||
static void drawBorderFrame(DisplayT *d, const BlitOpsT *ops, const ColorSchemeT *colors, int32_t x, int32_t y, int32_t w, int32_t h);
|
||||
static void drawMenuBar(DisplayT *d, const BlitOpsT *ops, const BitmapFontT *font, const ColorSchemeT *colors, WindowT *win);
|
||||
static void drawResizeBreaks(DisplayT *d, const BlitOpsT *ops, const ColorSchemeT *colors, WindowT *win);
|
||||
|
|
@ -50,6 +76,42 @@ static void computeMenuBarPositions(WindowT *win, const BitmapFontT *font) {
|
|||
}
|
||||
|
||||
|
||||
// ============================================================
|
||||
// computeTitleGeom
|
||||
// ============================================================
|
||||
//
|
||||
// Compute title bar gadget positions. Used by both drawTitleBar()
|
||||
// and wmHitTest() to keep geometry in sync.
|
||||
|
||||
static void computeTitleGeom(const WindowT *win, TitleGeomT *g) {
|
||||
g->titleX = win->x + CHROME_BORDER_WIDTH;
|
||||
g->titleY = win->y + CHROME_BORDER_WIDTH;
|
||||
g->titleW = win->w - CHROME_BORDER_WIDTH * 2;
|
||||
g->titleH = CHROME_TITLE_HEIGHT;
|
||||
g->gadgetS = g->titleH - GADGET_INSET * 2;
|
||||
g->gadgetY = g->titleY + GADGET_INSET;
|
||||
|
||||
// Close gadget on the left
|
||||
g->closeX = g->titleX + GADGET_PAD;
|
||||
|
||||
// Rightmost gadget position (decremented as gadgets are placed)
|
||||
int32_t rightX = g->titleX + g->titleW - GADGET_PAD - g->gadgetS;
|
||||
|
||||
if (win->resizable) {
|
||||
g->maxX = rightX;
|
||||
rightX -= g->gadgetS + GADGET_PAD;
|
||||
} else {
|
||||
g->maxX = -1;
|
||||
}
|
||||
|
||||
g->minX = rightX;
|
||||
|
||||
// Text area between close gadget and minimize gadget
|
||||
g->textLeftEdge = g->closeX + g->gadgetS + GADGET_PAD;
|
||||
g->textRightEdge = g->minX - GADGET_PAD;
|
||||
}
|
||||
|
||||
|
||||
// ============================================================
|
||||
// drawBorderFrame
|
||||
// ============================================================
|
||||
|
|
@ -201,34 +263,46 @@ static void drawResizeBreaks(DisplayT *d, const BlitOpsT *ops, const ColorScheme
|
|||
// ============================================================
|
||||
|
||||
static void drawScaledRect(DisplayT *d, int32_t dstX, int32_t dstY, int32_t dstW, int32_t dstH, const uint8_t *src, int32_t srcW, int32_t srcH, int32_t srcPitch, int32_t bpp) {
|
||||
for (int32_t dy = 0; dy < dstH; dy++) {
|
||||
int32_t sy = (dy * srcH) / dstH;
|
||||
int32_t screenY = dstY + dy;
|
||||
// Pre-compute visible row/col range (clip against display clip rect)
|
||||
int32_t rowStart = 0;
|
||||
int32_t rowEnd = dstH;
|
||||
int32_t colStart = 0;
|
||||
int32_t colEnd = dstW;
|
||||
|
||||
if (screenY < d->clipY || screenY >= d->clipY + d->clipH) {
|
||||
continue;
|
||||
if (dstY < d->clipY) { rowStart = d->clipY - dstY; }
|
||||
if (dstY + dstH > d->clipY + d->clipH) { rowEnd = d->clipY + d->clipH - dstY; }
|
||||
if (dstX < d->clipX) { colStart = d->clipX - dstX; }
|
||||
if (dstX + dstW > d->clipX + d->clipW) { colEnd = d->clipX + d->clipW - dstX; }
|
||||
|
||||
if (rowStart >= rowEnd || colStart >= colEnd) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t *dstRow = d->backBuf + screenY * d->pitch;
|
||||
// Pre-compute source X lookup table (one division per column instead of per pixel)
|
||||
int32_t srcXTab[ICON_SIZE];
|
||||
int32_t visibleCols = colEnd - colStart;
|
||||
|
||||
for (int32_t dx = 0; dx < visibleCols; dx++) {
|
||||
srcXTab[dx] = ((colStart + dx) * srcW) / dstW * bpp;
|
||||
}
|
||||
|
||||
// Blit with pre-computed lookups — no per-pixel divisions or clip checks
|
||||
for (int32_t dy = rowStart; dy < rowEnd; dy++) {
|
||||
int32_t sy = (dy * srcH) / dstH;
|
||||
uint8_t *dstRow = d->backBuf + (dstY + dy) * d->pitch + (dstX + colStart) * bpp;
|
||||
const uint8_t *srcRow = src + sy * srcPitch;
|
||||
|
||||
for (int32_t dx = 0; dx < dstW; dx++) {
|
||||
int32_t sx = (dx * srcW) / dstW;
|
||||
int32_t screenX = dstX + dx;
|
||||
|
||||
if (screenX < d->clipX || screenX >= d->clipX + d->clipW) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const uint8_t *srcPx = srcRow + sx * bpp;
|
||||
uint8_t *dstPx = dstRow + screenX * bpp;
|
||||
|
||||
if (bpp == 1) {
|
||||
*dstPx = *srcPx;
|
||||
for (int32_t dx = 0; dx < visibleCols; dx++) {
|
||||
dstRow[dx] = srcRow[srcXTab[dx]];
|
||||
}
|
||||
} else if (bpp == 2) {
|
||||
*(uint16_t *)dstPx = *(const uint16_t *)srcPx;
|
||||
for (int32_t dx = 0; dx < visibleCols; dx++) {
|
||||
*(uint16_t *)(dstRow + dx * 2) = *(const uint16_t *)(srcRow + srcXTab[dx]);
|
||||
}
|
||||
} else {
|
||||
*(uint32_t *)dstPx = *(const uint32_t *)srcPx;
|
||||
for (int32_t dx = 0; dx < visibleCols; dx++) {
|
||||
*(uint32_t *)(dstRow + dx * 4) = *(const uint32_t *)(srcRow + srcXTab[dx]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -345,45 +419,30 @@ static void drawScrollbarArrow(DisplayT *d, const BlitOpsT *ops, const ColorSche
|
|||
// ============================================================
|
||||
|
||||
static void drawTitleBar(DisplayT *d, const BlitOpsT *ops, const BitmapFontT *font, const ColorSchemeT *colors, WindowT *win) {
|
||||
int32_t titleX = win->x + CHROME_BORDER_WIDTH;
|
||||
int32_t titleY = win->y + CHROME_BORDER_WIDTH;
|
||||
int32_t titleW = win->w - CHROME_BORDER_WIDTH * 2;
|
||||
int32_t titleH = CHROME_TITLE_HEIGHT;
|
||||
TitleGeomT g;
|
||||
computeTitleGeom(win, &g);
|
||||
|
||||
uint32_t bg = win->focused ? colors->activeTitleBg : colors->inactiveTitleBg;
|
||||
uint32_t fg = win->focused ? colors->activeTitleFg : colors->inactiveTitleFg;
|
||||
|
||||
// Fill title bar background
|
||||
rectFill(d, ops, titleX, titleY, titleW, titleH, bg);
|
||||
|
||||
// GEOS Motif gadget sizing
|
||||
int32_t gadgetS = titleH - 4; // gadget size, fits within title bar
|
||||
int32_t gadgetY = titleY + 2;
|
||||
int32_t gadgetPad = 2;
|
||||
rectFill(d, ops, g.titleX, g.titleY, g.titleW, g.titleH, bg);
|
||||
|
||||
// Close gadget on the LEFT (system menu / close)
|
||||
int32_t closeX = titleX + gadgetPad;
|
||||
drawTitleGadget(d, ops, colors, closeX, gadgetY, gadgetS);
|
||||
drawTitleGadget(d, ops, colors, g.closeX, g.gadgetY, g.gadgetS);
|
||||
// Horizontal bar icon inside close gadget
|
||||
drawHLine(d, ops, closeX + 3, gadgetY + gadgetS / 2,
|
||||
gadgetS - 6, colors->contentFg);
|
||||
drawHLine(d, ops, g.closeX + 3, g.gadgetY + g.gadgetS / 2,
|
||||
g.gadgetS - 6, colors->contentFg);
|
||||
|
||||
// Right edge of title text area
|
||||
int32_t textRightEdge = titleX + titleW - gadgetPad;
|
||||
|
||||
// Rightmost gadget position
|
||||
int32_t rightGadgetX = titleX + titleW - gadgetPad - gadgetS;
|
||||
|
||||
if (win->resizable) {
|
||||
if (g.maxX >= 0) {
|
||||
// Maximize/restore gadget on the far RIGHT
|
||||
int32_t maxX = rightGadgetX;
|
||||
drawTitleGadget(d, ops, colors, maxX, gadgetY, gadgetS);
|
||||
drawTitleGadget(d, ops, colors, g.maxX, g.gadgetY, g.gadgetS);
|
||||
|
||||
if (win->maximized) {
|
||||
// Restore icon: larger box outline filling more of the gadget
|
||||
int32_t bx = maxX + 2;
|
||||
int32_t by = gadgetY + 2;
|
||||
int32_t bs = gadgetS - 4;
|
||||
int32_t bx = g.maxX + 2;
|
||||
int32_t by = g.gadgetY + 2;
|
||||
int32_t bs = g.gadgetS - 4;
|
||||
rectFill(d, ops, bx, by, bs, bs, colors->buttonFace);
|
||||
drawHLine(d, ops, bx, by, bs, colors->contentFg);
|
||||
drawHLine(d, ops, bx, by + 1, bs, colors->contentFg);
|
||||
|
|
@ -392,30 +451,24 @@ static void drawTitleBar(DisplayT *d, const BlitOpsT *ops, const BitmapFontT *fo
|
|||
drawVLine(d, ops, bx + bs - 1, by, bs, colors->contentFg);
|
||||
} else {
|
||||
// Maximize icon: small box outline
|
||||
rectFill(d, ops, maxX + 3, gadgetY + 3,
|
||||
gadgetS - 6, gadgetS - 6, colors->buttonFace);
|
||||
drawHLine(d, ops, maxX + 3, gadgetY + 3, gadgetS - 6, colors->contentFg);
|
||||
drawHLine(d, ops, maxX + 3, gadgetY + gadgetS - 4, gadgetS - 6, colors->contentFg);
|
||||
drawVLine(d, ops, maxX + 3, gadgetY + 3, gadgetS - 6, colors->contentFg);
|
||||
drawVLine(d, ops, maxX + gadgetS - 4, gadgetY + 3, gadgetS - 6, colors->contentFg);
|
||||
rectFill(d, ops, g.maxX + 3, g.gadgetY + 3,
|
||||
g.gadgetS - 6, g.gadgetS - 6, colors->buttonFace);
|
||||
drawHLine(d, ops, g.maxX + 3, g.gadgetY + 3, g.gadgetS - 6, colors->contentFg);
|
||||
drawHLine(d, ops, g.maxX + 3, g.gadgetY + g.gadgetS - 4, g.gadgetS - 6, colors->contentFg);
|
||||
drawVLine(d, ops, g.maxX + 3, g.gadgetY + 3, g.gadgetS - 6, colors->contentFg);
|
||||
drawVLine(d, ops, g.maxX + g.gadgetS - 4, g.gadgetY + 3, g.gadgetS - 6, colors->contentFg);
|
||||
}
|
||||
}
|
||||
|
||||
rightGadgetX -= gadgetS + gadgetPad;
|
||||
}
|
||||
|
||||
// Minimize gadget (always present, to the left of maximize or on the far right)
|
||||
int32_t minX = rightGadgetX;
|
||||
drawTitleGadget(d, ops, colors, minX, gadgetY, gadgetS);
|
||||
// Minimize gadget (always present)
|
||||
drawTitleGadget(d, ops, colors, g.minX, g.gadgetY, g.gadgetS);
|
||||
// Small square centered in minimize gadget
|
||||
int32_t miniSize = 4;
|
||||
rectFill(d, ops, minX + (gadgetS - miniSize) / 2, gadgetY + (gadgetS - miniSize) / 2,
|
||||
rectFill(d, ops, g.minX + (g.gadgetS - miniSize) / 2, g.gadgetY + (g.gadgetS - miniSize) / 2,
|
||||
miniSize, miniSize, colors->contentFg);
|
||||
|
||||
textRightEdge = minX - gadgetPad;
|
||||
|
||||
// Title text — centered between close gadget and right edge, truncated to fit
|
||||
int32_t textLeftEdge = closeX + gadgetS + gadgetPad;
|
||||
int32_t availW = textRightEdge - textLeftEdge;
|
||||
// Title text — centered between close gadget and minimize, truncated to fit
|
||||
int32_t availW = g.textRightEdge - g.textLeftEdge;
|
||||
|
||||
if (availW > 0) {
|
||||
int32_t maxChars = availW / font->charWidth;
|
||||
|
|
@ -426,15 +479,16 @@ static void drawTitleBar(DisplayT *d, const BlitOpsT *ops, const BitmapFontT *fo
|
|||
}
|
||||
|
||||
if (len > 0) {
|
||||
int32_t textW = len * font->charWidth;
|
||||
int32_t textX = textLeftEdge + (availW - textW) / 2;
|
||||
int32_t textY = titleY + (titleH - font->charHeight) / 2;
|
||||
// Build truncated title for drawText
|
||||
char truncTitle[MAX_TITLE_LEN];
|
||||
memcpy(truncTitle, win->title, len);
|
||||
truncTitle[len] = '\0';
|
||||
|
||||
// Draw truncated title character by character
|
||||
for (int32_t i = 0; i < len; i++) {
|
||||
drawChar(d, ops, font, textX + i * font->charWidth, textY,
|
||||
win->title[i], fg, bg, true);
|
||||
}
|
||||
int32_t textW = len * font->charWidth;
|
||||
int32_t textX = g.textLeftEdge + (availW - textW) / 2;
|
||||
int32_t textY = g.titleY + (g.titleH - font->charHeight) / 2;
|
||||
|
||||
drawText(d, ops, font, textX, textY, truncTitle, fg, bg, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -464,13 +518,13 @@ static int32_t scrollbarThumbInfo(const ScrollbarT *sb, int32_t *thumbPos, int32
|
|||
return trackLen;
|
||||
}
|
||||
|
||||
*thumbSize = (sb->pageSize * trackLen) / (range + sb->pageSize);
|
||||
*thumbSize = (int32_t)(((int64_t)sb->pageSize * trackLen) / (range + sb->pageSize));
|
||||
|
||||
if (*thumbSize < SCROLLBAR_WIDTH) {
|
||||
*thumbSize = SCROLLBAR_WIDTH;
|
||||
}
|
||||
|
||||
*thumbPos = ((sb->value - sb->min) * (trackLen - *thumbSize)) / range;
|
||||
*thumbPos = (int32_t)(((int64_t)(sb->value - sb->min) * (trackLen - *thumbSize)) / range);
|
||||
|
||||
return trackLen;
|
||||
}
|
||||
|
|
@ -944,46 +998,34 @@ int32_t wmHitTest(const WindowStackT *stack, int32_t mx, int32_t my, int32_t *hi
|
|||
continue;
|
||||
}
|
||||
|
||||
// Title bar gadget geometry (must match drawTitleBar)
|
||||
int32_t titleX = win->x + CHROME_BORDER_WIDTH;
|
||||
int32_t titleY = win->y + CHROME_BORDER_WIDTH;
|
||||
int32_t titleW = win->w - CHROME_BORDER_WIDTH * 2;
|
||||
int32_t gadgetS = CHROME_TITLE_HEIGHT - 4;
|
||||
int32_t gadgetY = titleY + 2;
|
||||
int32_t gadgetP = 2;
|
||||
TitleGeomT g;
|
||||
computeTitleGeom(win, &g);
|
||||
|
||||
// Close gadget (top-left)
|
||||
int32_t closeX = titleX + gadgetP;
|
||||
if (mx >= closeX && mx < closeX + gadgetS &&
|
||||
my >= gadgetY && my < gadgetY + gadgetS) {
|
||||
if (mx >= g.closeX && mx < g.closeX + g.gadgetS &&
|
||||
my >= g.gadgetY && my < g.gadgetY + g.gadgetS) {
|
||||
*hitPart = 2;
|
||||
return i;
|
||||
}
|
||||
|
||||
// Rightmost gadget position
|
||||
int32_t rightGadgetX = titleX + titleW - gadgetP - gadgetS;
|
||||
|
||||
// Maximize gadget only on resizable windows
|
||||
if (win->resizable) {
|
||||
if (mx >= rightGadgetX && mx < rightGadgetX + gadgetS &&
|
||||
my >= gadgetY && my < gadgetY + gadgetS) {
|
||||
// Maximize gadget (resizable windows only)
|
||||
if (g.maxX >= 0 &&
|
||||
mx >= g.maxX && mx < g.maxX + g.gadgetS &&
|
||||
my >= g.gadgetY && my < g.gadgetY + g.gadgetS) {
|
||||
*hitPart = 8;
|
||||
return i;
|
||||
}
|
||||
|
||||
rightGadgetX -= gadgetS + gadgetP;
|
||||
}
|
||||
|
||||
// Minimize gadget (always present)
|
||||
if (mx >= rightGadgetX && mx < rightGadgetX + gadgetS &&
|
||||
my >= gadgetY && my < gadgetY + gadgetS) {
|
||||
if (mx >= g.minX && mx < g.minX + g.gadgetS &&
|
||||
my >= g.gadgetY && my < g.gadgetY + g.gadgetS) {
|
||||
*hitPart = 7;
|
||||
return i;
|
||||
}
|
||||
|
||||
// Title bar (drag area — between gadgets)
|
||||
if (my >= titleY && my < titleY + CHROME_TITLE_HEIGHT &&
|
||||
mx >= titleX && mx < titleX + titleW) {
|
||||
if (my >= g.titleY && my < g.titleY + CHROME_TITLE_HEIGHT &&
|
||||
mx >= g.titleX && mx < g.titleX + g.titleW) {
|
||||
*hitPart = 1;
|
||||
return i;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue