From dd5f691cab26c45a149c762357e0da77c0a08eeb Mon Sep 17 00:00:00 2001 From: helios Date: Sun, 9 Aug 2026 18:40:45 +0200 Subject: [PATCH] Batch animation frames and buffer status text --- README.md | 7 +++++-- src/main.cpp | 14 +++++++++----- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 3d4d886..856fdf8 100644 --- a/README.md +++ b/README.md @@ -9,8 +9,11 @@ Controls: **Pause/Resume**, **Redo**, **Next**, **Run All 8**, and **Algorithm Menu**. **No Visual** reruns the selected algorithm without any animation, touch polling, or intentional delay during the timed section and reports its duration with microsecond-derived precision. The bar animation is -rendered through a PSRAM-backed canvas for tear-free updates. Build with -`pio run`, upload with `pio run -t upload`. +rendered through a PSRAM-backed canvas for tear-free updates. Animation work is +batched (32 sort operations per candidate frame), the display is capped near +60 FPS, and the independently buffered counter strip updates at 4 Hz so its +rapidly changing digits remain readable without flicker. Build with `pio run`, +upload with `pio run -t upload`. **All Visual** runs the eight faster animations and then opens a comparison report. **All Fast** benchmarks all eight without intermediate drawing and diff --git a/src/main.cpp b/src/main.cpp index fbaec5b..92c201d 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -3,6 +3,8 @@ namespace { constexpr int N=48, CX=34, CY=142, CW=1212, CH=410; +constexpr int STATUS_Y=562, STATUS_H=46, OPS_PER_FRAME=32; +constexpr uint32_t FRAME_MS=16, STATUS_MS=250; constexpr uint16_t BG=0x0841,PANEL=0x18E3,PANEL2=0x2125,MUTED=0xBDF7,CYAN=0x2E9F,YELLOW=0xFDC0,GREEN=0x4EE9; struct Rect{int x,y,w,h;bool has(int px,int py)const{return px>=x&&px=y&&py0);return true;} +bool frame(int x=-1,int y=-1,int ms=0){(void)ms;if(benchmark)return true;hotA=x;hotB=y;if(++animationOps%OPS_PER_FRAME!=0)return true;chart();touch();while(paused&&!abortRun){touch();status();delay(12);}return !abortRun;} void swapv(int x,int y){if(x==y)return;int v=a[x];a[x]=a[y];a[y]=v;moves+=3;}void writev(int i,int v){a[i]=v;moves++;} bool bubble(){for(int end=N-1;end>0;end--){bool changed=false;for(int i=0;ia[i+1]){swapv(i,i+1);changed=true;}if(!frame(i,i+1))return false;}if(!changed)break;}return true;} @@ -42,7 +46,7 @@ bool heapify(int size,int root){while(true){int big=root,l=root*2+1,r=l+1;if(l=0;i--)if(!heapify(N,i))return false;for(int e=N-1;e>0;e--){swapv(0,e);if(!frame(0,e))return false;if(!heapify(e,0))return false;}return true;} bool radix(){for(int exp=1;N/exp>0;exp*=10){int count[10]={0};for(int i=0;i=0;i--){tmp[--count[(a[i]/exp)%10]]=a[i];moves++;}for(int i=0;i0;i--){int j=random(i+1);int v=base[i];base[i]=base[j];base[j]=v;}} void menu(){M5.Display.fillScreen(BG);M5.Display.fillRect(0,0,1280,102,PANEL);label("SORTING LAB",34,42,middle_left,&fonts::FreeSansBold24pt7b,TFT_WHITE,PANEL);label("Choose one, or compare all eight",1244,42,middle_right,&fonts::FreeSans12pt7b,MUTED,PANEL);for(int i=0;i<8;i++){int col=i%2,row=i/2;Rect r{34+col*614,126+row*112,596,94};uint16_t fill=i==which?0x2B8E:PANEL2;M5.Display.fillRoundRect(r.x,r.y,r.w,r.h,16,fill);M5.Display.drawRoundRect(r.x,r.y,r.w,r.h,16,0x31A6);label(alg[i].name,r.x+24,r.y+31,middle_left,&fonts::FreeSansBold12pt7b,TFT_WHITE,fill);label(alg[i].lesson,r.x+24,r.y+67,middle_left,&fonts::FreeSans9pt7b,MUTED,fill);label(alg[i].cost,r.x+r.w-18,r.y+31,middle_right,&fonts::FreeSansBold12pt7b,YELLOW,fill);}Rect sh{34,598,238,78},oneFast{288,598,278,78},all{582,598,316,78},allFast{914,598,332,78};button(sh,"NEW SHUFFLE",0x620B);button(oneFast,"SELECTED FAST",YELLOW);button(all,"ALL VISUAL",0x4A2E);button(allFast,"ALL FAST",0x6A2E);while(true){M5.update();auto t=M5.Touch.getDetail();if(t.wasReleased()){if(sh.has(t.x,t.y)){shuffle();menu();return;}if(oneFast.has(t.x,t.y)){benchmark=true;runAll=false;return;}if(all.has(t.x,t.y)){which=0;runAll=true;benchmark=false;for(auto&r:results)r=Result{};return;}if(allFast.has(t.x,t.y)){which=0;runAll=true;benchmark=true;for(auto&r:results)r=Result{};return;}for(int i=0;i<8;i++){Rect r{34+(i%2)*614,126+(i/2)*112,596,94};if(r.has(t.x,t.y)){which=i;runAll=false;benchmark=false;return;}}}delay(12);}} } -void setup(){Serial.begin(115200);auto cfg=M5.config();M5.begin(cfg);M5.Display.setRotation(1);M5.Display.setColorDepth(16);M5.Display.setBrightness(180);barCanvas.setColorDepth(16);barCanvas.setPsram(true);barCanvas.createSprite(CW,CH);randomSeed(esp_random());shuffle();Serial.println("Tab5 Sorting Lab ready");} +void setup(){Serial.begin(115200);auto cfg=M5.config();M5.begin(cfg);M5.Display.setRotation(1);M5.Display.setColorDepth(16);M5.Display.setBrightness(180);barCanvas.setColorDepth(16);barCanvas.setPsram(true);barCanvas.createSprite(CW,CH);statusCanvas.setColorDepth(16);statusCanvas.setPsram(true);statusCanvas.createSprite(CW,STATUS_H);randomSeed(esp_random());shuffle();Serial.println("Tab5 Sorting Lab ready");} void loop(){menu();do{reset();runScreen();startMs=millis();startUs=micros();bool done=sortNow();if(done){uint32_t elapsedUs=benchmark?(micros()-startUs):(millis()-startMs-pauseTotal)*1000UL;results[which]={cmp,moves,elapsedUs,true};Serial.printf("%s: %lu comparisons, %lu moves, %.3f ms%s\n",alg[which].name,(unsigned long)cmp,(unsigned long)moves,elapsedUs/1000.0f,benchmark?" (no visual)":"");if(runAll&&benchmark){if(which<7){which++;continue;}summary();runAll=false;break;}result();if(runAll){if(waitFor(700)&&which<7){which++;continue;}if(which==7){summary();runAll=false;}break;}waitFor(10000);break;}bool again=redo;abortRun=false;if(again)continue;break;}while(true);}