Skip to content

Commit b28a311

Browse files
authored
tileclk: Optimize digit extraction, simplify RGB565 color interpolation, and streamline border drawing with direct boolean flags
1 parent 1e9c001 commit b28a311

File tree

1 file changed

+49
-48
lines changed

1 file changed

+49
-48
lines changed

apps/tileclk/app.js

Lines changed: 49 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -182,36 +182,35 @@
182182
];
183183

184184
// ===== EFFICIENT COLOR SYSTEM =====
185-
// Pre-calculated color tables for animations using typed arrays
185+
// Pre-calculated color tables for animations
186186
let colorOn = null, colorOff = null;
187187

188188
const initColorTables = () => {
189-
// Use Uint32Array for maximum performance
190-
colorOn = new Uint32Array(FRAC_STEPS + 1);
191-
colorOff = new Uint32Array(FRAC_STEPS + 1);
189+
// Use Uint16Array since Bangle uses RGB565 (16-bit) colors
190+
colorOn = new Uint16Array(FRAC_STEPS + 1);
191+
colorOff = new Uint16Array(FRAC_STEPS + 1);
192192

193193
const bgColor = g.theme.bg;
194194
const fgColor = g.theme.fg;
195195

196-
// Calculate all color transitions
196+
// Simple linear interpolation between color values
197197
for (let i = 0; i <= FRAC_STEPS; i++) {
198198
const frac = i / FRAC_STEPS;
199-
const invFrac = 1 - frac;
200199

201-
// Direct calculation for better performance
202-
const rOn = (((bgColor >> 16) & 0xFF) * invFrac + ((fgColor >> 16) & 0xFF) * frac) | 0;
203-
const gOn = (((bgColor >> 8) & 0xFF) * invFrac + ((fgColor >> 8) & 0xFF) * frac) | 0;
204-
const bOn = ((bgColor & 0xFF) * invFrac + (fgColor & 0xFF) * frac) | 0;
205-
const rOff = (((fgColor >> 16) & 0xFF) * invFrac + ((bgColor >> 16) & 0xFF) * frac) | 0;
206-
const gOff = (((fgColor >> 8) & 0xFF) * invFrac + ((bgColor >> 8) & 0xFF) * frac) | 0;
207-
const bOff = ((fgColor & 0xFF) * invFrac + (bgColor & 0xFF) * frac) | 0;
208-
colorOn[i] = (rOn << 16) | (gOn << 8) | bOn;
209-
colorOff[i] = (rOff << 16) | (gOff << 8) | bOff;
200+
// Direct interpolation of RGB565 values
201+
colorOn[i] = (bgColor + (fgColor - bgColor) * frac + 0.5) | 0;
202+
colorOff[i] = (fgColor + (bgColor - fgColor) * frac + 0.5) | 0;
210203
}
211204
}
212-
// ===== BORDER DRAWING =====
213-
const drawBorder = (x, y, s, thickness) => {
214-
if (!showBorders || thickness <= 0) return;
205+
206+
// ===== CONSOLIDATED BORDER DRAWING =====
207+
const drawBorder = (x, y, s, isMainDigit) => {
208+
if (!showBorders) return;
209+
210+
// Direct variable lookup is faster than object property access
211+
const thickness = isMainDigit ? MAIN_BORDER_THICKNESS : SEC_BORDER_THICKNESS;
212+
if (thickness <= 0) return;
213+
215214
g.setColor(borderColor);
216215
for (let i = 0; i < thickness; i++) {
217216
g.drawRect(x + i, y + i, x + s - 1 - i, y + s - 1 - i);
@@ -226,7 +225,7 @@
226225
function transition() {
227226
if (!isDrawing || (pendingSwitch && isSeconds)) return;
228227

229-
// Use pre-calculated color instead of interpColor()
228+
// Use pre-calculated color
230229
g.setColor(colors[step]);
231230
g.fillRect(x, y, x + s - 1, y + s - 1);
232231

@@ -248,15 +247,14 @@
248247
}
249248

250249
function animateTileOn(x, y, s, callback, isMainDigit) {
251-
const thickness = isMainDigit ? MAIN_BORDER_THICKNESS : SEC_BORDER_THICKNESS;
252-
const borderFunc = (showBorders && thickness > 0) ?
253-
() => drawBorder(x, y, s, thickness) : null;
250+
const borderFunc = showBorders ? () => drawBorder(x, y, s, isMainDigit) : null;
254251
animateTransition(x, y, s, g.theme.bg, g.theme.fg, borderFunc, callback);
255252
}
256253

257254
function animateTileOff(x, y, s, callback) {
258255
animateTransition(x, y, s, g.theme.fg, g.theme.bg, null, callback);
259256
}
257+
260258
// ===== TILE CALCULATION =====
261259
const calculateTilesToUpdate = (x, y, s, currentDigit, prevDigit) => {
262260
const currentPacked = digitBitmaps[getDigitIndex(currentDigit)];
@@ -281,15 +279,14 @@
281279

282280
return tiles;
283281
}
282+
284283
// ===== TILE UPDATE =====
285284
function updateTile(tile, s, skipAnimation, isMainDigit, isClearing) {
286-
const thickness = isMainDigit ? MAIN_BORDER_THICKNESS : SEC_BORDER_THICKNESS;
287-
288285
if (tile.state) {
289286
if (skipAnimation) {
290287
g.setColor(g.theme.fg);
291288
g.fillRect(tile.x, tile.y, tile.x + s - 1, tile.y + s - 1);
292-
drawBorder(tile.x, tile.y, s, thickness);
289+
drawBorder(tile.x, tile.y, s, isMainDigit);
293290
} else {
294291
animateTileOn(tile.x, tile.y, s, null, isMainDigit);
295292
}
@@ -315,6 +312,7 @@
315312
animationTimeouts[animationTimeoutCount++] = timeout;
316313
}
317314
}
315+
318316
// ===== DIGIT DRAWING =====
319317
function drawDigit(x, y, s, num, prevNum, callback, skipAnimation, isMainDigit) {
320318
if (num === prevNum) {
@@ -344,6 +342,7 @@
344342
}, true);
345343
}, true);
346344
}
345+
347346
// ===== TIME UPDATE SCHEDULING =====
348347
function scheduleNextUpdate() {
349348
if (drawTimeout) clearTimeout(drawTimeout);
@@ -352,6 +351,7 @@
352351

353352
drawTimeout = setTimeout(updateAndAnimTime, msUntilNextMinute);
354353
}
354+
355355
// ===== CLEARING FUNCTIONS (Direct callback approach for performance) =====
356356
function clearColon(callback) {
357357
if (!isColonDrawn) {
@@ -417,7 +417,7 @@
417417
});
418418
}
419419

420-
// ===== MAIN TIME UPDATE =====
420+
// ===== MAIN TIME UPDATE (OPTIMIZED) =====
421421
function updateAndAnimTime() {
422422
if (!isDrawing) return;
423423

@@ -426,32 +426,33 @@
426426
const minutesNum = now.getMinutes();
427427
const currentTime = hoursNum * 100 + minutesNum;
428428

429-
// Extract digits only for layout decision
430-
const isCurrentThreeDigit = is12Hour && hoursNum < 10;
431-
const wasLastThreeDigit = is12Hour && lastTime !== null && lastTime < 1000;
432-
433-
function drawTime() {
434-
// Extract current digits using cached lookups for maximum performance
435-
let h1, h2, m1, m2;
436-
429+
// Extract current digits ONCE
430+
const currentDigits = (() => {
437431
if (timeCache && timeCache.minuteDigits) {
438432
const hourCache = is12Hour ? timeCache.hourDigits12 : timeCache.hourDigits24;
439433
const minuteCache = timeCache.minuteDigits;
440434

441-
h1 = hourCache[hoursNum * 2];
442-
h2 = hourCache[hoursNum * 2 + 1];
443-
m1 = minuteCache[minutesNum * 2];
444-
m2 = minuteCache[minutesNum * 2 + 1];
435+
return {
436+
h1: hourCache[hoursNum * 2],
437+
h2: hourCache[hoursNum * 2 + 1],
438+
m1: minuteCache[minutesNum * 2],
439+
m2: minuteCache[minutesNum * 2 + 1]
440+
};
445441
} else {
446-
// Fallback to direct calculation
447-
h1 = (hoursNum / 10) | 0;
448-
h2 = hoursNum % 10;
449-
m1 = (minutesNum / 10) | 0;
450-
m2 = minutesNum % 10;
442+
return {
443+
h1: (hoursNum / 10) | 0,
444+
h2: hoursNum % 10,
445+
m1: (minutesNum / 10) | 0,
446+
m2: minutesNum % 10
447+
};
451448
}
452-
453-
const digitMap = { h1: h1, h2: h2, m1: m1, m2: m2 };
454-
449+
})();
450+
451+
// Determine layout based on extracted digits
452+
const isCurrentThreeDigit = is12Hour && currentDigits.h1 === 0;
453+
const wasLastThreeDigit = is12Hour && lastTime !== null && lastTime < 1000;
454+
455+
function drawTime() {
455456
// Extract previous digits (or null for blank)
456457
const previousDigits = (isCurrentThreeDigit !== wasLastThreeDigit && lastTime !== null) ?
457458
{ h1: null, h2: null, m1: null, m2: null } :
@@ -470,7 +471,7 @@
470471
const next = () => drawLayout(items, onComplete);
471472

472473
if (item.type === 'digit') {
473-
drawDigit(item.x, item.y, item.scale, digitMap[item.value], previousDigits[item.value], next, false, true);
474+
drawDigit(item.x, item.y, item.scale, currentDigits[item.value], previousDigits[item.value], next, false, true);
474475
} else if (item.type === 'colon') {
475476
drawColon(item.x, item.y, next);
476477
}
@@ -996,4 +997,4 @@
996997

997998
// ===== START CLOCK =====
998999
drawClock();
999-
})();
1000+
})();

0 commit comments

Comments
 (0)