diff --git a/Apps/Explorer/desk_server.vp b/Apps/Explorer/desk_server.vp index a87366e..3b190ae 100644 --- a/Apps/Explorer/desk_server.vp +++ b/Apps/Explorer/desk_server.vp @@ -156,30 +156,12 @@ class DeskServer: return (uint32(255) << 24) | (r << 16) | (g << 8) | b return (uint32(255) << 24) | (b << 16) | (g << 8) | r - # ---- 按 framebuffer 格式把 fg 以 alpha/255 混到 bg 上 ---- + # ---- 按 alpha/255 把 fg 混到 bg 上(RGBA/BGRA 同为 R/B@0,16、G@8,可共用 SWAR)---- def _blend(self, bg: uint32, fg: uint32, a: int) -> uint32: ia: int = 255 - a - if self.fmt == uint32(1): - br: int = int((bg >> 16) & 0xFF) - bg_g: int = int((bg >> 8) & 0xFF) - bg_b: int = int(bg & 0xFF) - fr: int = int((fg >> 16) & 0xFF) - fg_g: int = int((fg >> 8) & 0xFF) - fg_b: int = int(fg & 0xFF) - r: int = (fr * a + br * ia) >> 8 - g: int = (fg_g * a + bg_g * ia) >> 8 - b: int = (fg_b * a + bg_b * ia) >> 8 - return (uint32(255) << 24) | (uint32(r) << 16) | (uint32(g) << 8) | uint32(b) - br = int(bg & 0xFF) - bg_g = int((bg >> 8) & 0xFF) - bg_b = int((bg >> 16) & 0xFF) - fr = int(fg & 0xFF) - fg_g = int((fg >> 8) & 0xFF) - fg_b = int((fg >> 16) & 0xFF) - r = (fr * a + br * ia) >> 8 - g = (fg_g * a + bg_g * ia) >> 8 - b = (fg_b * a + bg_b * ia) >> 8 - return (uint32(255) << 24) | (uint32(b) << 16) | (uint32(g) << 8) | uint32(r) + v: int = ((int(fg & uint32(0x00FF00FF)) * a) + (int(bg & uint32(0x00FF00FF)) * ia)) >> 8 + g: int = ((int((fg >> 8) & uint32(0xFF)) * a) + (int((bg >> 8) & uint32(0xFF)) * ia)) >> 8 + return (uint32(255) << 24) | (uint32(v) & uint32(0x00FF00FF)) | (uint32(g & 0xFF) << 8) def init(self, fb: uint32*, w: int, h: int, pitch: int, fmt: uint32, shm: uint64, kfd: int, mfd: int, fb_fd: int): @@ -375,6 +357,20 @@ class DeskServer: i += 1 # ---------------- 窗口阴影 ---------------- + # 单个阴影像素的 alpha(与原逐像素算法完全相同) + def _shadow_alpha(self, adx: int, ady: int, me_x: int, me_y: int) -> int: + dist: int = adx + if ady > dist: dist = ady + dist = dist + ((adx + ady - dist) * 3) / 8 + me: int = me_x + if adx + ady > 0: + me = (me_x * adx + me_y * ady) / (adx + ady) + if me > 0 and dist > 0 and dist < me: + t_val: int = (256 * dist) / me + t_inv: int = 256 - t_val + return (SHADOW_ALPHA * t_inv * t_inv) / 65536 + return 0 + def _draw_shadow(self, s: desk.WinSlot*, y0: int, y1: int): wx: int = s.ux wy: int = s.uy @@ -384,54 +380,76 @@ class DeskServer: sr: int = SHADOW_RIGHT st: int = SHADOW_TOP sb: int = SHADOW_BOTTOM - sa: int = SHADOW_ALPHA - shadow_col: uint32 = self.rgb(uint32(0), uint32(0), uint32(0)) + # 左右窄带(dy=0)的 alpha 只随 adx 变化,预建表 + lt: [16]int + rt: [16]int + tl: [16]int + tr: [16]int + i: int = 0 + while i <= sl: + lt[i] = self._shadow_alpha(i, 0, sl, st) + i += 1 + i = 0 + while i <= sr: + rt[i] = self._shadow_alpha(i, 0, sr, st) + i += 1 yy: int = y0 if yy < wy - st: yy = wy - st yend: int = y1 if yend > wy + wh + sb: yend = wy + wh + sb while yy < yend: if yy >= 0 and yy < self.fb_h: + side: int = 0 + ady: int = 0 + me_y: int = st + if yy < wy: + ady = wy - yy + elif yy >= wy + wh: + ady = yy - (wy + wh - 1) + me_y = sb + else: + side = 1 + tm: int = 0 + if side == 0: + i = 0 + while i <= sl: + tl[i] = self._shadow_alpha(i, ady, sl, me_y) + i += 1 + i = 0 + while i <= sr: + tr[i] = self._shadow_alpha(i, ady, sr, me_y) + i += 1 + tm = self._shadow_alpha(0, ady, sl, me_y) px: int = wx - sl if px < 0: px = 0 xend: int = wx + ww + sr if xend > self.fb_w: xend = self.fb_w + base: int = yy * self.fb_w while px < xend: - if px < wx or px >= wx + ww or yy < wy or yy >= wy + wh: - cpx: int = px - if cpx < wx: cpx = wx - elif cpx > wx + ww - 1: cpx = wx + ww - 1 - cpy: int = yy - if cpy < wy: cpy = wy - elif cpy > wy + wh - 1: cpy = wy + wh - 1 - dx: int = px - cpx - dy: int = yy - cpy - adx: int = dx - if adx < 0: adx = 0 - adx - ady: int = dy - if ady < 0: ady = 0 - ady - dist: int = adx - if ady > dist: dist = ady - dist = dist + ((adx + ady - dist) * 3) / 8 - me_x: int = sl - if dx > 0: me_x = sr - me_y: int = st - if dy > 0: me_y = sb - me: int = me_x - if adx + ady > 0: - me = (me_x * adx + me_y * ady) / (adx + ady) - if me > 0 and dist > 0 and dist < me: - t_val: int = (256 * dist) / me - t_inv: int = 256 - t_val - a: int = (sa * t_inv * t_inv) / 65536 - if a > 0: - idx: int = yy * self.fb_w + px - self.back[idx] = self._blend(self.back[idx], shadow_col, a) + a: int = 0 + adx: int = 0 + if px < wx: + adx = wx - px + if side != 0: a = lt[adx] + else: a = tl[adx] + elif px >= wx + ww: + adx = px - (wx + ww - 1) + if side != 0: a = rt[adx] + else: a = tr[adx] + elif side == 0: + a = tm + if a > 0: + idx: int = base + px + bg: uint32 = self.back[idx] + ia: int = 255 - a + rb: int = (int(bg & uint32(0x00FF00FF)) * ia) >> 8 + g: int = (int((bg >> 8) & uint32(0xFF)) * ia) >> 8 + self.back[idx] = (uint32(255) << 24) | (uint32(rb) & uint32(0x00FF00FF)) | (uint32(g & 0xFF) << 8) px += 1 yy += 1 # ---------------- 窗口逐行绘制(按样式)---------------- - # 把 col 以 alpha 混到后备缓冲已有像素上(WIN7 半透明标题栏用) + # 把 col 以 alpha 混到后备缓冲已有像素上(WIN7 半透明标题栏用);逐像素内联 SWAR def _blend_row(self, x0: int, y: int, w: int, col: uint32, a: int): if y < 0 or y >= self.fb_h or w <= 0 or a <= 0: return x: int = x0 @@ -442,11 +460,17 @@ class DeskServer: if x + dw > self.fb_w: dw = self.fb_w - x if dw <= 0: return + ia: int = 255 - a + frb: int = int(col & uint32(0x00FF00FF)) * a + fg: int = int((col >> 8) & uint32(0xFF)) * a base: int = y * self.fb_w i: int = 0 while i < dw: idx: int = base + x + i - self.back[idx] = self._blend(self.back[idx], col, a) + bg: uint32 = self.back[idx] + v: int = (frb + int(bg & uint32(0x00FF00FF)) * ia) >> 8 + g: int = (fg + int((bg >> 8) & uint32(0xFF)) * ia) >> 8 + self.back[idx] = (uint32(255) << 24) | (uint32(v) & uint32(0x00FF00FF)) | (uint32(g & 0xFF) << 8) i += 1 # 标题栏每行颜色:WIN7/WINXP 竖直渐变 + 首两行高光 + 末行暗边,其余样式纯色 @@ -494,7 +518,7 @@ class DeskServer: col = self._blend(col, self.rgb(uint32(100), uint32(160), uint32(230)), 40) return col - # 直边行:整行底色 + 内容 blit + 左右/上下 1px 边框 + # 直边行:整行底色/内容 blit + 左右/上下 1px 边框(内容行不再先铺整行底色) def _draw_flat_row(self, s: desk.WinSlot*, yy: int, rel: int, row_col: uint32, row_is_title: int, border_col: uint32, title_alpha: int, buf: uint32*, fw: int, fh: int, content_y0: int): @@ -504,17 +528,17 @@ class DeskServer: content_row: int = yy - content_y0 if row_is_title != 0 and title_alpha < 255: self._blend_row(wx + 1, yy, ww - 2, row_col, title_alpha) + elif rel >= TITLE_H + TITLE_GAP and rel < wh - 1 and content_row >= 0 and content_row < fh: + self.row_blit(wx + 1, yy, buf, content_row * fw + 1, ww - 2) else: self.row_fill(wx, yy, ww, row_col) - if rel >= TITLE_H + TITLE_GAP and rel < wh - 1 and content_row >= 0 and content_row < fh: - self.row_blit(wx + 1, yy, buf, content_row * fw + 1, ww - 2) if rel == 0 or rel == wh - 1: self.row_fill(wx, yy, ww, border_col) else: self.row_fill(wx, yy, 1, border_col) self.row_fill(wx + ww - 1, yy, 1, border_col) - # 圆角带的行:逐像素按圆角形状裁剪,画边框/标题渐变/内容 + # 圆角带的行:只有左右各 r 列需要逐像素,中段按直行整段处理 def _draw_round_row(self, s: desk.WinSlot*, yy: int, rel: int, row_col: uint32, row_is_title: int, outline_col: uint32, r: int, title_alpha: int, buf: uint32*, fw: int, fh: int, content_y0: int): @@ -525,84 +549,110 @@ class DeskServer: do_blit: int = 0 if rel >= TITLE_H + TITLE_GAP and rel < wh - 1 and content_row >= 0 and content_row < fh: do_blit = 1 + cyc: int = r + if rel >= r: cyc = wh - r - 1 + if ww > r + r: + seg: int = 0 + while seg < 2: + xs: int = wx + xe: int = wx + r + cxc: int = r + if seg == 1: + xs = wx + ww - r + xe = wx + ww + cxc = ww - r - 1 + px: int = xs + while px < xe: + if px >= 0 and px < self.fb_w: + rx: int = px - wx + if _is_in_corner(rx, rel, cxc, cyc, r) != 0: + on_border: int = _is_on_border(rx, rel, ww, wh, r) + idx: int = yy * self.fb_w + px + if on_border == 0 and do_blit != 0: + self.back[idx] = buf[content_row * fw + rx] + px += 1 + continue + col: uint32 = row_col + if on_border != 0: + col = outline_col + ca: int = _corner_alpha(rx, rel, cxc, cyc, r) + if on_border != 0 and ca > 0 and ca < 255: + ca = 255 + if row_is_title != 0 and title_alpha < 255 and rel >= 1 and rx >= 1 and rx < ww - 1 and ca == 255 and on_border == 0: + ca = title_alpha + if ca > 0: + if ca < 255: + self.back[idx] = self._blend(self.back[idx], col, ca) + else: + self.back[idx] = col + px += 1 + seg += 1 + mid0: int = wx + r + mid1: int = wx + ww - r + midw: int = mid1 - mid0 + if midw > 0: + if rel == 0 or rel == wh - 1: + self.row_fill(mid0, yy, midw, outline_col) + elif do_blit != 0: + self.row_blit(mid0, yy, buf, content_row * fw + r, midw) + elif row_is_title != 0 and title_alpha < 255: + self._blend_row(mid0, yy, midw, row_col, title_alpha) + else: + self.row_fill(mid0, yy, midw, row_col) + return + # 窄窗回退:整行逐像素 px: int = wx xend: int = wx + ww while px < xend: if px >= 0 and px < self.fb_w: rx: int = px - wx - in_corner: int = 1 - on_border: int = 0 - if rel < r: - if rx < r: - in_corner = _is_in_corner(rx, rel, r, r, r) - elif rx >= ww - r: - in_corner = _is_in_corner(rx, rel, ww - r - 1, r, r) - elif rel >= wh - r: - if rx < r: - in_corner = _is_in_corner(rx, rel, r, wh - r - 1, r) - elif rx >= ww - r: - in_corner = _is_in_corner(rx, rel, ww - r - 1, wh - r - 1, r) - if in_corner == 0: - on_border = _is_on_border(rx, rel, ww, wh, r) - if on_border == 0: + cxr: int = r + if rx >= ww - r: cxr = ww - r - 1 + if _is_in_corner(rx, rel, cxr, cyc, r) != 0: + on_border: int = _is_on_border(rx, rel, ww, wh, r) + idx: int = yy * self.fb_w + px + if on_border == 0 and do_blit != 0: + self.back[idx] = buf[content_row * fw + rx] px += 1 continue - is_border_pixel: int = 0 - if on_border != 0 or _is_on_border(rx, rel, ww, wh, r) != 0: - is_border_pixel = 1 - idx: int = yy * self.fb_w + px - if is_border_pixel == 0 and do_blit != 0: - self.back[idx] = buf[content_row * fw + rx] - px += 1 - continue - col: uint32 = row_col - if is_border_pixel != 0: - col = outline_col - ca: int = 255 - if rel < r: - if rx < r: - ca = _corner_alpha(rx, rel, r, r, r) - elif rx >= ww - r: - ca = _corner_alpha(rx, rel, ww - r - 1, r, r) - elif rel >= wh - r: - if rx < r: - ca = _corner_alpha(rx, rel, r, wh - r - 1, r) - elif rx >= ww - r: - ca = _corner_alpha(rx, rel, ww - r - 1, wh - r - 1, r) - if is_border_pixel != 0 and ca > 0 and ca < 255: - ca = 255 - if row_is_title != 0 and title_alpha < 255 and rel >= 1 and rx >= 1 and rx < ww - 1 and ca == 255 and is_border_pixel == 0: - ca = title_alpha - if ca <= 0: - px += 1 - continue - if ca < 255: - self.back[idx] = self._blend(self.back[idx], col, ca) - else: - self.back[idx] = col + col: uint32 = row_col + if on_border != 0: + col = outline_col + ca: int = _corner_alpha(rx, rel, cxr, cyc, r) + if on_border != 0 and ca > 0 and ca < 255: + ca = 255 + if row_is_title != 0 and title_alpha < 255 and rel >= 1 and rx >= 1 and rx < ww - 1 and ca == 255 and on_border == 0: + ca = title_alpha + if ca > 0: + if ca < 255: + self.back[idx] = self._blend(self.back[idx], col, ca) + else: + self.back[idx] = col px += 1 # ---------------- 窗口按钮(按样式逐行绘制)---------------- - # 关闭键底色圆角(WIN7/WINXP 的红色圆角块) + # 圆角块的一行是否保留该列 + def _round_keep(self, lx: int, lry: int, bw: int, bh: int, r: int) -> int: + if lry < r: + if lx < r: return _is_in_corner(lx, lry, r, r, r) + if lx >= bw - r: return _is_in_corner(lx, lry, bw - r - 1, r, r) + elif lry >= bh - r: + if lx < r: return _is_in_corner(lx, lry, r, bh - r - 1, r) + if lx >= bw - r: return _is_in_corner(lx, lry, bw - r - 1, bh - r - 1, r) + return 1 + + # 关闭键底色圆角(WIN7/WINXP 的红色圆角块):整行只做一次 row_fill def _round_fill_row(self, bx: int, by: int, bw: int, bh: int, yy: int, col: uint32, r: int): lry: int = yy - by if lry < 0 or lry >= bh: return - lx: int = 0 - while lx < bw: - keep: int = 1 - if lry < r: - if lx < r: - keep = _is_in_corner(lx, lry, r, r, r) - elif lx >= bw - r: - keep = _is_in_corner(lx, lry, bw - r - 1, r, r) - elif lry >= bh - r: - if lx < r: - keep = _is_in_corner(lx, lry, r, bh - r - 1, r) - elif lx >= bw - r: - keep = _is_in_corner(lx, lry, bw - r - 1, bh - r - 1, r) - if keep != 0: - self.row_fill(bx + lx, yy, 1, col) - lx += 1 + lo: int = 0 + while lo < bw and self._round_keep(lo, lry, bw, bh, r) == 0: + lo += 1 + hi: int = bw + while hi > lo and self._round_keep(hi - 1, lry, bw, bh, r) == 0: + hi -= 1 + if hi > lo: + self.row_fill(bx + lo, yy, hi - lo, col) def _draw_close_row(self, bx: int, by: int, bw: int, bh: int, yy: int, style: int): lry: int = yy - by @@ -767,13 +817,30 @@ class DeskServer: # ---------------- 渲染 ---------------- def render_range(self, y0: int, y1: int): - # 窗口按 Z 序升序(选择排序,窗口数 ≤ 8)—— 背景裁剪与窗口绘制都要用 + # 窗口按 Z 序升序(选择排序,窗口数 ≤ 8);顺带缓存几何/样式,避免逐行查槽 order: [desk.DESK_MAX_WIN]int + sx: [desk.DESK_MAX_WIN]int + sy: [desk.DESK_MAX_WIN]int + sw: [desk.DESK_MAX_WIN]int + sh: [desk.DESK_MAX_WIN]int + smode: [desk.DESK_MAX_WIN]int cnt: int = 0 + top_z: int = -1 for i in range(desk.DESK_MAX_WIN): s: desk.WinSlot* = self.slot(i) if s.used != 0 and s.active != 0 and s.minimized == 0: order[cnt] = i + sx[i] = s.ux + sy[i] = s.uy + sw[i] = s.w + sh[i] = s.h + if s.style == STYLE_WIN7: + smode[i] = 2 + elif s.style == STYLE_WIN11 or s.style == STYLE_WINXP: + smode[i] = 1 + else: + smode[i] = 0 + if s.z_order > top_z: top_z = s.z_order cnt += 1 for a in range(cnt - 1): for b in range(a + 1, cnt): @@ -783,18 +850,26 @@ class DeskServer: t: int = order[a] order[a] = order[b] order[b] = t - # 1) 背景:只铺"没有被窗口覆盖"的 x 区间。整行铺背景对窗口完全覆盖的那几百列是纯浪费 - # (Scene3D 每帧刷全窗,等于每帧多拷一整屏背景)。 + # 1) 背景:只铺"没有被窗口覆盖"的 x 区间;混合样式的可见行再单独铺一次底 yy: int = y0 while yy < y1: xx: int = 0 for i in range(cnt): - s: desk.WinSlot* = self.slot(order[i]) - if yy < s.uy or yy >= s.uy + s.h: continue - if s.ux > xx: - self.row_blit(xx, yy, self.bg_row, xx, s.ux - xx) - ex: int = s.ux + s.w + w: int = order[i] + if yy < sy[w] or yy >= sy[w] + sh[w]: continue + if sx[w] > xx: + self.row_blit(xx, yy, self.bg_row, xx, sx[w] - xx) + ex: int = sx[w] + sw[w] if ex > xx: xx = ex + if smode[w] != 0: + rel: int = yy - sy[w] + need: int = 0 + if smode[w] == 2: + if rel < TITLE_H or rel >= sh[w] - WIN_RADIUS: need = 1 + elif rel < WIN_RADIUS or rel >= sh[w] - WIN_RADIUS: + need = 1 + if need != 0: + self.row_blit(sx[w], yy, self.bg_row, sx[w], sw[w]) if xx < self.fb_w: self.row_blit(xx, yy, self.bg_row, xx, self.fb_w - xx) yy += 1 @@ -802,11 +877,11 @@ class DeskServer: self._draw_taskbar_rows(y0, y1) # 3) 窗口 for i in range(cnt): - self.render_window_rows(order[i], y0, y1) + self.render_window_rows(order[i], y0, y1, top_z) # 4) 光标 self.render_cursor_rows(y0, y1) - def render_window_rows(self, win: int, y0: int, y1: int): + def render_window_rows(self, win: int, y0: int, y1: int, top_z: int): s: desk.WinSlot* = self.slot(win) wx: int = s.ux wy: int = s.uy @@ -814,7 +889,7 @@ class DeskServer: th: int = TITLE_H style: int = s.style active: int = 0 - if s.z_order == self._top_z(): active = 1 + if s.z_order == top_z: active = 1 # 每样式调色板(对齐内核桌面 desktop.vp 的 _draw_app_window) title_col: uint32 = self.rgb(uint32(50), uint32(50), uint32(90)) border_col: uint32 = self.rgb(uint32(100), uint32(100), uint32(180))