@bitefoundry/retrieviewer 0.0.19 → 0.0.20
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/NATIVE-RUNTIME.md +13 -13
- package/PUPPY-MEMORY.md +14 -0
- package/README.ko.md +7 -1
- package/README.md +8 -1
- package/RELEASING.md +18 -1
- package/SPARSE-PAINT.md +53 -0
- package/integrations/native-windows/bin/win32-x64/retrieviewer-native.exe +0 -0
- package/integrations/native-windows/host.cpp +1 -0
- package/integrations/native-windows/manifest.json +2 -2
- package/integrations/native-windows/native-paint.hpp +35 -5
- package/integrations/native-windows/paint-regions.hpp +4 -31
- package/package.json +1 -1
package/NATIVE-RUNTIME.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Lightweight desktop runtime · 0.0.
|
|
1
|
+
# Lightweight desktop runtime · 0.0.20
|
|
2
2
|
|
|
3
3
|
Windows x64 basic desktop mode runs the existing JavaScript pet behavior in
|
|
4
4
|
QuickJS-NG, inside the same native process that paints the transparent window.
|
|
@@ -41,15 +41,14 @@ play/treat/attention or tower/wheel actions. No forced GC or working-set trimmin
|
|
|
41
41
|
|
|
42
42
|
| Pet | Median RSS | Sampled maximum | OS lifetime peak |
|
|
43
43
|
|---|---:|---:|---:|
|
|
44
|
-
| Retriever |22.
|
|
45
|
-
| Ginger cat with tower/wheel |
|
|
44
|
+
| Retriever |22.9MiB|37.9MiB|38.7MiB|
|
|
45
|
+
| Ginger cat with tower/wheel |44.4MiB|64.6MiB|65.5MiB|
|
|
46
46
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
Raw local evidence: dist/sparse-paint-memory/{dog,cat,report}.json.
|
|
47
|
+
Version 0.0.20 uses one cropped layered window for the complete scene. This
|
|
48
|
+
fixes flicker from the 0.0.19 multi-window painter; its lower memory figures are
|
|
49
|
+
superseded. Buffer shrinking and hidden-state cleanup remain. See the
|
|
50
|
+
[presentation fix](SPARSE-PAINT.md). These finite measurements do not establish
|
|
51
|
+
a universal 50 MiB memory cap. Raw evidence: dist/coherent-paint-memory/.
|
|
53
52
|
|
|
54
53
|
## Scope
|
|
55
54
|
|
|
@@ -88,8 +87,9 @@ The executable embeds the Windows UTF-8 process code-page manifest (Windows10
|
|
|
88
87
|
1903+ /11) so QuickJS stdio also reads Korean/non-ASCII installation paths.
|
|
89
88
|
A regression test launches both species from Korean bundle, art and state paths.
|
|
90
89
|
|
|
91
|
-
##
|
|
90
|
+
## Coherent scene presentation
|
|
92
91
|
|
|
93
|
-
[
|
|
94
|
-
|
|
95
|
-
|
|
92
|
+
[One complete-scene upload](SPARSE-PAINT.md) keeps the final pet, props and
|
|
93
|
+
furniture in the same HWND. That window stays click-through and non-activating.
|
|
94
|
+
The 128-frame presentation regression checks window identity, full-frame pixel
|
|
95
|
+
parity and hidden-resource release separately from pet-core pixel parity.
|
package/PUPPY-MEMORY.md
CHANGED
|
@@ -1,3 +1,17 @@
|
|
|
1
|
+
# 0.0.20 coherent scene painter
|
|
2
|
+
|
|
3
|
+
The complete scene now updates through one native layered window to fix the
|
|
4
|
+
0.0.19 flicker regression. Buffer shrinking, hidden-state release, stamp atlas
|
|
5
|
+
and indexed art loading remain; no art or pet behavior changed. Distant cat
|
|
6
|
+
furniture can enlarge the one bounding surface. The 0.0.19 figures below are
|
|
7
|
+
historical and must not describe the current version. See
|
|
8
|
+
[presentation evidence](SPARSE-PAINT.md) and [current measurements](NATIVE-RUNTIME.md).
|
|
9
|
+
|
|
10
|
+
Real 4K 150s measurements: dog median22.9MiB / OS peak38.7MiB; cat with
|
|
11
|
+
tower/wheel44.4 /65.5MiB. Watch/brain off, no forced GC/trim; not a hard cap.
|
|
12
|
+
|
|
13
|
+
## Superseded 0.0.19 result (presentation regression)
|
|
14
|
+
|
|
1
15
|
# 0.0.19 sparse painter result
|
|
2
16
|
|
|
3
17
|
Windows x64 basic mode retains one native process and splits sparse content
|
package/README.ko.md
CHANGED
|
@@ -148,7 +148,13 @@ JS 플러그인과 JSONL 브리지를 제공해요. 화면·입력·시간 제
|
|
|
148
148
|
AI로 생성한 그림에 자세 정렬·접지·프레임 처리를 적용한 애니메이션입니다.
|
|
149
149
|
실제 모션 캡처나 자의식이 있는 강아지라고 주장하지 않아요.
|
|
150
150
|
|
|
151
|
-
## 0.0.
|
|
151
|
+
## 0.0.20
|
|
152
|
+
|
|
153
|
+
Windows에서 화면 일부가 깜빡이던 문제를 고쳤어요. 장면 전체를 창 하나로
|
|
154
|
+
갱신하고, 버퍼 축소와 숨김 상태 정리는 유지합니다. 그림과 동작은 그대로예요.
|
|
155
|
+
[수정과 측정 기록](SPARSE-PAINT.md)을 참고하세요.
|
|
156
|
+
|
|
157
|
+
## 0.0.19 (이전 버전 · 깜빡임 수정으로 대체)
|
|
152
158
|
|
|
153
159
|
Windows 기본 실행에서 표시 영역을 나누고 불필요하게 커진 버퍼를 회수해요.
|
|
154
160
|
그림과 동작은 그대로예요. 실제4K150초 측정에서 강아지는 중앙값22.6MiB·최고36.5MiB,
|
package/README.md
CHANGED
|
@@ -189,7 +189,14 @@ The puppy artwork was developed with AI-generated imagery and programmatic pose,
|
|
|
189
189
|
grounding and frame processing. It is authored animation, not motion capture or
|
|
190
190
|
a claim of sentience.
|
|
191
191
|
|
|
192
|
-
## 0.0.
|
|
192
|
+
## 0.0.20
|
|
193
|
+
|
|
194
|
+
Fixes Windows flicker introduced by the split-window painter. The whole scene
|
|
195
|
+
updates through one stable transparent window again; buffer shrinking and
|
|
196
|
+
hidden-state cleanup remain. Artwork and behavior are unchanged.
|
|
197
|
+
See [presentation fix and measurements](SPARSE-PAINT.md).
|
|
198
|
+
|
|
199
|
+
## 0.0.19 (historical; superseded by flicker fix)
|
|
193
200
|
|
|
194
201
|
Windows basic mode now splits distant content into small paint regions and
|
|
195
202
|
reclaims oversized/hidden surfaces. Same pets, artwork and behavior. In real4K
|
package/RELEASING.md
CHANGED
|
@@ -1,4 +1,21 @@
|
|
|
1
|
-
# Retrieviewer 0.0.
|
|
1
|
+
# Retrieviewer 0.0.20 release process
|
|
2
|
+
|
|
3
|
+
Current target: `@bitefoundry/retrieviewer@0.0.20`, public `latest`.
|
|
4
|
+
Hotfix for the reported flicker in the previously authorized npm/site release.
|
|
5
|
+
Replace the dynamically repartitioned HWNDs with one complete-scene layered
|
|
6
|
+
window and one pixel/position/size upload. Keep stamp caching, indexed art,
|
|
7
|
+
buffer shrinking and hidden-state release. Artwork and pet behavior are unchanged.
|
|
8
|
+
|
|
9
|
+
Verify moving/disjoint masks keep one stable window, exact native paint pixels,
|
|
10
|
+
resize/hide/restore/switch/teardown, full suite and fresh installed artifact.
|
|
11
|
+
Publish that same tested tarball after CI, verify registry integrity and a fresh
|
|
12
|
+
consumer, then confirm the matching bilingual website. Memory figures must
|
|
13
|
+
come from this version, not the regressed sparse painter. Existing code/art
|
|
14
|
+
licenses, optional integrations, user pet and privacy setup are preserved.
|
|
15
|
+
|
|
16
|
+
## Previous 0.0.19 scope (historical; presentation regression)
|
|
17
|
+
|
|
18
|
+
### Retrieviewer 0.0.19 release process
|
|
2
19
|
|
|
3
20
|
Current target: `@bitefoundry/retrieviewer@0.0.19`, public `latest`.
|
|
4
21
|
The owner explicitly authorized npm and website deployment on2026-10-25.
|
package/SPARSE-PAINT.md
CHANGED
|
@@ -1,3 +1,56 @@
|
|
|
1
|
+
# Coherent native painting · 0.0.20
|
|
2
|
+
|
|
3
|
+
The 0.0.19 sparse-window optimization is superseded. Per-frame pixel comparison
|
|
4
|
+
passed, but a moving scene could change its partition and destroy/reposition
|
|
5
|
+
multiple HWNDs at different compositor moments. The owner reported visible
|
|
6
|
+
flicker. Preparing all DIBs first did not make those window updates atomic.
|
|
7
|
+
|
|
8
|
+
Version 0.0.20 paints the complete final mask into one cropped layered window.
|
|
9
|
+
`UpdateLayeredWindow` uploads all pixels, position and size together. The same
|
|
10
|
+
HWND survives movement and crop changes. Visibility is changed only when first
|
|
11
|
+
shown; there is no extra per-frame `SetWindowPos` after upload. No animal assets,
|
|
12
|
+
anatomy, motion, Braille masks or optional integrations changed.
|
|
13
|
+
|
|
14
|
+
The 256-mask stamp atlas and one-process QuickJS host remain. Capacity still
|
|
15
|
+
shrinks when it exceeds twice the rounded target area; hidden/minimized scenes
|
|
16
|
+
release their surface and window. The tradeoff is one bounding bitmap spanning
|
|
17
|
+
distant furniture: memory can exceed the regressed split-painter measurements.
|
|
18
|
+
Those old numbers below must not be presented as current measurements.
|
|
19
|
+
|
|
20
|
+
## Verification
|
|
21
|
+
|
|
22
|
+
- Real Win32 presentation regression: 128 changing/disjoint scenes retain one
|
|
23
|
+
visible HWND, with exact full-scene BGRA pixels; hidden resources release.
|
|
24
|
+
- Native mask/capacity tests: 56 grids across seven cell sizes.
|
|
25
|
+
- Real moving dog/cream, cat/gold and cat/dark: 301 exact paint comparisons.
|
|
26
|
+
- Owned 4K -> small -> 4K, minimize/restore and same-process species switching.
|
|
27
|
+
DIB capacity shrank from 12.22 to 1.50 MiB and reached zero when minimized.
|
|
28
|
+
|
|
29
|
+
Reproduce with `node --test native-desktop.test.mjs`,
|
|
30
|
+
`node tools/check-native-paint.mjs` and `node tools/check-native-resources.mjs`.
|
|
31
|
+
This checks actual window lifetime and upload coherence as well as image bytes;
|
|
32
|
+
finite pixel/lifetime checks are not a claim that every display was observed.
|
|
33
|
+
|
|
34
|
+
## Current memory measurement
|
|
35
|
+
|
|
36
|
+
Same Windows x64 host, owned off-screen 3840x2160 target, real native painter,
|
|
37
|
+
seed731 and 150s action schedule, 300 roughly half-second samples per pet
|
|
38
|
+
(157.5/156.9s wall time). Watch/brain off; no forced GC or working-set trim.
|
|
39
|
+
Harness and external DWM/GPU allocations are excluded.
|
|
40
|
+
|
|
41
|
+
| Pet | Median RSS | Sampled maximum | OS lifetime peak |
|
|
42
|
+
|---|---:|---:|---:|
|
|
43
|
+
| Retriever |22.9MiB|37.9MiB|38.7MiB|
|
|
44
|
+
| Cat with tower/wheel |44.4MiB|64.6MiB|65.5MiB|
|
|
45
|
+
|
|
46
|
+
Cat furniture spans a large bounding bitmap again. This restores coherent
|
|
47
|
+
presentation at a higher RAM cost than 0.0.19; it is not a universal 50MiB cap.
|
|
48
|
+
Both owned processes stopped and removed their sessions. Raw local evidence:
|
|
49
|
+
`dist/coherent-paint-memory/{dog,cat,report}.json`. Full suite:244 passed,
|
|
50
|
+
two macOS-only tests skipped on Windows. No artwork or motion change.
|
|
51
|
+
|
|
52
|
+
## Superseded 0.0.19 experiment (historical)
|
|
53
|
+
|
|
1
54
|
# Sparse Windows paint surfaces · 0.0.19
|
|
2
55
|
|
|
3
56
|
Version0.0.19 builds on0.0.18. JavaScript behavior, Q5 art, world/contact math, colors and
|
|
Binary file
|
|
@@ -75,6 +75,7 @@ static JSValue blit(JSContext* c,JSValueConst,int argc,JSValueConst* a){try{
|
|
|
75
75
|
int wmain(int argc,wchar_t** wideArgs){
|
|
76
76
|
std::vector<std::string> argText;for(int i=0;i<argc;i++){int n=WideCharToMultiByte(CP_UTF8,0,wideArgs[i],-1,nullptr,0,nullptr,nullptr);std::string value(n,0);WideCharToMultiByte(CP_UTF8,0,wideArgs[i],-1,value.data(),n,nullptr,nullptr);value.pop_back();argText.push_back(value);}std::vector<char*> args;for(auto& text:argText)args.push_back(text.data());char** argv=args.data();
|
|
77
77
|
if(argc==2&&std::string(argv[1])=="--self-test-regions")try{return NativePet::selfTestPaintRegions();}catch(const std::exception& e){fprintf(stderr,"%s\n",e.what());return 1;}
|
|
78
|
+
if(argc==2&&std::string(argv[1])=="--self-test-presentation")try{return NativePet::selfTestPaintPresentation();}catch(const std::exception& e){fprintf(stderr,"%s\n",e.what());return 1;}
|
|
78
79
|
bool production=false;for(int i=1;i<argc;i++)if(std::string(argv[i])=="--production")production=true;std::string configuration;
|
|
79
80
|
if(production){char ch;while(std::cin.get(ch)&&ch!='\n'){if(configuration.size()>=8192)return 2;configuration+=ch;}if(configuration.empty())return 2;}
|
|
80
81
|
if(argc<2)return 2;JSRuntime* rt=JS_NewRuntime();js_std_init_handlers(rt);JSContext* ctx=JS_NewContext(rt);JS_SetModuleLoaderFunc2(rt,nullptr,js_module_loader,js_module_check_attributes,nullptr);js_init_module_std(ctx,"qjs:std");js_init_module_os(ctx,"qjs:os");js_std_add_helpers(ctx,argc-1,argv+1);
|
|
@@ -7,8 +7,8 @@
|
|
|
7
7
|
"sha256": "e9da942dbe57ac778c44ea8f300e2e868face5e73b00ffcd4399aeb7e94ee09c"
|
|
8
8
|
},
|
|
9
9
|
"bin/win32-x64/retrieviewer-native.exe": {
|
|
10
|
-
"bytes":
|
|
11
|
-
"sha256": "
|
|
10
|
+
"bytes": 1562624,
|
|
11
|
+
"sha256": "0844d0e5303938e11d3e57acb457d7f6df2f138ee84246ecdf006395055f0fba"
|
|
12
12
|
}
|
|
13
13
|
}
|
|
14
14
|
}
|
|
@@ -46,7 +46,7 @@ static void verifyPaint(const std::vector<uint8_t>& masks,int columns,const PetP
|
|
|
46
46
|
static const int dx[]={0,0,0,1,1,1,0,1},dy[]={0,1,2,0,1,2,3,3};float step=cell/2.f,diameter=std::max(1.1f,step*.48f);
|
|
47
47
|
for(int y=all.top;y<all.bottom;y++)for(int x=all.left;x<all.right;x++){int mask=masks[(size_t)y*columns+x];for(int bit=0;bit<8;bit++)if(mask&(1<<bit)){float px=(x-all.left)*cell+(dx[bit]+.5f)*step,py=(y-all.top)*cell*2+(dy[bit]+.5f)*step;g.FillEllipse(&brush,px-diameter/2,py-diameter/2,diameter,diameter);}}g.Flush(Gdiplus::FlushIntentionSync);
|
|
48
48
|
}
|
|
49
|
-
if(reference!=assemble(all,cell))throw std::runtime_error("
|
|
49
|
+
if(reference!=assemble(all,cell))throw std::runtime_error("Native dots changed pixels");verifiedPaints++;
|
|
50
50
|
if(!atlasVerified){printf("{\"stage\":\"dot-atlas-verified\",\"pixelExact\":true,\"regions\":%zu}\n",paintCount());fflush(stdout);}atlasVerified=true;
|
|
51
51
|
}
|
|
52
52
|
static void paint(const std::string& text,int columns,int rows,int cell,POINT canvas){
|
|
@@ -66,10 +66,11 @@ static void paint(const std::string& text,int columns,int rows,int cell,POINT ca
|
|
|
66
66
|
for(size_t i=regions.size();i<panels.size();i++)panels[i].release();
|
|
67
67
|
if(verifyAtlas&&(!atlasVerified||verifyEveryPaint))verifyPaint(masks,columns,all,cell);
|
|
68
68
|
if(saveProof&&!proofSaved){const int w=all.width()*cell,h=all.height()*cell*2;auto image=assemble(all,cell);Gdiplus::Bitmap source(w,h,w*4,PixelFormat32bppPARGB,image.data()),proof(w,h,PixelFormat32bppARGB);Gdiplus::Graphics pg(&proof);pg.Clear(Gdiplus::Color(255,0,0,0));pg.DrawImage(&source,Gdiplus::Rect(0,0,w,h),0,0,w,h,Gdiplus::UnitPixel);pg.Flush(Gdiplus::FlushIntentionSync);CLSID png={0x557cf406,0x1a04,0x11d3,{0x9a,0x73,0x00,0x00,0xf8,0x1e,0xf3,0x2e}};if(proof.Save(wide(proofPath).c_str(),&png,nullptr)!=Gdiplus::Ok)throw std::runtime_error("PNG proof failed");proofSaved=true;}
|
|
69
|
-
//
|
|
70
|
-
//
|
|
69
|
+
// The complete scene (pet, ball and furniture) has exactly one HWND.
|
|
70
|
+
// UpdateLayeredWindow changes its pixels, size and position in one call.
|
|
71
|
+
// Do not add another per-frame SetWindowPos/show: it exposes separate state.
|
|
71
72
|
HDC screen=GetDC(nullptr);BLENDFUNCTION blend={AC_SRC_OVER,0,255,AC_SRC_ALPHA};POINT origin={0,0};
|
|
72
|
-
for(size_t i=0;i<regions.size();i++){auto& p=panels[i];POINT destination={canvas.x+p.crop.left*cell,canvas.y+p.crop.top*cell*2};SIZE size={p.crop.width()*cell,p.crop.height()*cell*2};BOOL ok=UpdateLayeredWindow(p.window,screen,&destination,&size,p.surface.dc,&origin,0,&blend,ULW_ALPHA);if(!ok){ReleaseDC(nullptr,screen);throw std::runtime_error("Native layered update");}
|
|
73
|
+
for(size_t i=0;i<regions.size();i++){auto& p=panels[i];POINT destination={canvas.x+p.crop.left*cell,canvas.y+p.crop.top*cell*2};SIZE size={p.crop.width()*cell,p.crop.height()*cell*2};BOOL ok=UpdateLayeredWindow(p.window,screen,&destination,&size,p.surface.dc,&origin,0,&blend,ULW_ALPHA);if(!ok){ReleaseDC(nullptr,screen);throw std::runtime_error("Native layered update");}if(!IsWindowVisible(p.window))ShowWindow(p.window,SW_SHOWNOACTIVATE);}
|
|
73
74
|
ReleaseDC(nullptr,screen);painted++;
|
|
74
75
|
}
|
|
75
76
|
static int selfTestPaintRegions(){
|
|
@@ -77,10 +78,39 @@ static int selfTestPaintRegions(){
|
|
|
77
78
|
for(int cell:{6,8,10,12,16,24,32})for(int type=0;type<8;type++){
|
|
78
79
|
const int cols=type==7?1000:240,rows=type==7?125:90;std::vector<uint8_t> masks((size_t)cols*rows);
|
|
79
80
|
for(int y=0;y<rows;y++)for(int x=0;x<cols;x++){bool on=type==1||type==2&&x%61==0||type==3&&y%31==0||type==4&&(x<20||x>cols-30)&&y>10||type==5&&(next()%100<4)||type==6&&((x-cols/2)*(x-cols/2)+(y-rows/2)*(y-rows/2)<900)||type==7&&x%97<3&&y%17<2;if(on)masks[(size_t)y*cols+x]=(uint8_t)(1+next()%255);}
|
|
80
|
-
const auto regions=PetPaint::partition(masks,cols,rows,cell);if(regions.size()>PetPaint::MaxRegions)throw std::runtime_error("
|
|
81
|
+
const auto regions=PetPaint::partition(masks,cols,rows,cell);if(regions.size()>PetPaint::MaxRegions)throw std::runtime_error("Non-atomic scene partition");std::vector<uint8_t> seen(masks.size(),0);PetPaint::Rect all;uint64_t bytes=0;
|
|
81
82
|
for(const auto& r:regions){if(r.empty()||r.left<0||r.top<0||r.right>cols||r.bottom>rows)throw std::runtime_error("Region outside grid");all.include(r);bytes+=PetPaint::bytes(r,cell);for(int y=r.top;y<r.bottom;y++)for(int x=r.left;x<r.right;x++)if(++seen[(size_t)y*cols+x]!=1)throw std::runtime_error("Overlapping paint regions");}
|
|
82
83
|
for(size_t i=0;i<masks.size();i++)if(masks[i]&&seen[i]!=1)throw std::runtime_error("Missing mask cell");if(bytes>PetPaint::bytes(all,cell))throw std::runtime_error("Partition grew allocation");checks++;
|
|
83
84
|
}
|
|
84
85
|
Surface s;s.ensure(2048,1024);const auto big=s.bytes();s.ensure(1800,900);if(s.bytes()!=big)throw std::runtime_error("Surface churn on small size change");s.ensure(96,64);if(s.bytes()>(uint64_t)128*64*4*2)throw std::runtime_error("Surface did not shrink");s.release();if(s.bytes()!=0)throw std::runtime_error("Surface did not release");
|
|
85
86
|
printf("{\"passed\":true,\"partitionCases\":%zu,\"coverageAndDisjointness\":true,\"surfaceShrink\":true}\n",checks);return 0;
|
|
86
87
|
}
|
|
88
|
+
|
|
89
|
+
// Real Win32 regression: moving/disjoint masks must retain one display window.
|
|
90
|
+
// Byte equality alone did not catch the multi-HWND presentation regression.
|
|
91
|
+
static int selfTestPaintPresentation(){
|
|
92
|
+
Gdiplus::GdiplusStartupInput input;ULONG_PTR token=0;
|
|
93
|
+
if(Gdiplus::GdiplusStartup(&token,&input,nullptr)!=Gdiplus::Ok)throw std::runtime_error("Presentation GDI+ startup");
|
|
94
|
+
WNDCLASS wc{};wc.lpfnWndProc=DefWindowProc;wc.hInstance=GetModuleHandle(nullptr);wc.lpszClassName=L"RetrieviewerNativeDots";RegisterClass(&wc);
|
|
95
|
+
const int columns=240,rows=90,cell=8;HWND first=nullptr;size_t checked=0;
|
|
96
|
+
verifyAtlas=verifyEveryPaint=atlasVerified=true;
|
|
97
|
+
try{
|
|
98
|
+
for(int frame=0;frame<128;frame++){
|
|
99
|
+
std::string text;
|
|
100
|
+
for(int y=0;y<rows;y++){if(y)text+='\n';for(int x=0;x<columns;x++){
|
|
101
|
+
bool pet=x>=20+frame%81&&x<55+frame%81&&y>=20&&y<65;
|
|
102
|
+
bool object=frame%3!=0&&x>=200-frame%13&&x<210-frame%13&&y>=5&&y<30;
|
|
103
|
+
unsigned ch=0x2800+(pet||object?1+(x+y+frame)%255:0);
|
|
104
|
+
text+=(char)(0xe0|(ch>>12));text+=(char)(0x80|((ch>>6)&63));text+=(char)(0x80|(ch&63));
|
|
105
|
+
}}
|
|
106
|
+
paint(text,columns,rows,cell,POINT{-12000,-12000});
|
|
107
|
+
if(paintCount()!=1||!IsWindowVisible(panels[0].window))throw std::runtime_error("Scene lost coherent visible window");
|
|
108
|
+
if(!first)first=panels[0].window;
|
|
109
|
+
if(panels[0].window!=first)throw std::runtime_error("Moving scene recreated its display window");
|
|
110
|
+
checked++;
|
|
111
|
+
}
|
|
112
|
+
hidePanels();if(paintCount()!=0||paintBytes()!=0)throw std::runtime_error("Hidden scene retained paint resources");
|
|
113
|
+
}catch(...){releasePanels();atlas.pixels.clear();Gdiplus::GdiplusShutdown(token);throw;}
|
|
114
|
+
atlas.pixels.clear();Gdiplus::GdiplusShutdown(token);
|
|
115
|
+
printf("{\"passed\":true,\"frames\":%zu,\"singleWindow\":true,\"stableWindow\":true,\"pixelExact\":true,\"hiddenResourcesReleased\":true}\n",checked);return 0;
|
|
116
|
+
}
|
|
@@ -5,9 +5,10 @@
|
|
|
5
5
|
#include <stdexcept>
|
|
6
6
|
#include <vector>
|
|
7
7
|
|
|
8
|
-
//
|
|
8
|
+
// One final-mask crop and one layered-window upload per scene. Separate HWNDs
|
|
9
|
+
// cannot present a repartitioned frame atomically, even with identical pixels.
|
|
9
10
|
namespace PetPaint {
|
|
10
|
-
constexpr size_t MaxRegions=
|
|
11
|
+
constexpr size_t MaxRegions=1;
|
|
11
12
|
struct Rect {
|
|
12
13
|
int left=std::numeric_limits<int>::max(),top=std::numeric_limits<int>::max();
|
|
13
14
|
int right=0,bottom=0;
|
|
@@ -19,37 +20,9 @@ struct Rect {
|
|
|
19
20
|
};
|
|
20
21
|
inline int rounded(int n){return (n+63)/64*64;}
|
|
21
22
|
inline uint64_t bytes(const Rect& r,int cell){return r.empty()?0:(uint64_t)rounded(r.width()*cell)*rounded(r.height()*cell*2)*4;}
|
|
22
|
-
struct Split {Rect box,a,b;uint64_t saved=0;};
|
|
23
|
-
inline Split bestSplit(const std::vector<uint8_t>& masks,int columns,const Rect& box,int cell){
|
|
24
|
-
Split result;result.box=box;const auto parent=bytes(box,cell);
|
|
25
|
-
for(bool horizontal:{false,true}){
|
|
26
|
-
const int n=horizontal?box.height():box.width();std::vector<Rect> bins(n),suffix(n+1);
|
|
27
|
-
for(int y=box.top;y<box.bottom;y++)for(int x=box.left;x<box.right;x++)
|
|
28
|
-
if(masks[(size_t)y*columns+x])bins[horizontal?y-box.top:x-box.left].include(x,y);
|
|
29
|
-
for(int i=n-1;i>=0;i--){suffix[i]=suffix[i+1];suffix[i].include(bins[i]);}
|
|
30
|
-
Rect prefix;
|
|
31
|
-
for(int i=0;i+1<n;i++){
|
|
32
|
-
prefix.include(bins[i]);const Rect& other=suffix[i+1];if(prefix.empty()||other.empty())continue;
|
|
33
|
-
const auto cost=bytes(prefix,cell)+bytes(other,cell);
|
|
34
|
-
if(cost<parent&&parent-cost>result.saved){result.saved=parent-cost;result.a=prefix;result.b=other;}
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
return result;
|
|
38
|
-
}
|
|
39
23
|
inline std::vector<Rect> partition(const std::vector<uint8_t>& masks,int columns,int rows,int cell){
|
|
40
24
|
if(columns<1||rows<1||(uint64_t)columns*rows>125000||masks.size()!=(size_t)columns*rows||cell<6||cell>32)throw std::runtime_error("Invalid paint mask grid");
|
|
41
25
|
Rect all;for(int y=0;y<rows;y++)for(int x=0;x<columns;x++)if(masks[(size_t)y*columns+x])all.include(x,y);
|
|
42
|
-
|
|
43
|
-
std::vector<Split> nodes{bestSplit(masks,columns,all,cell)};
|
|
44
|
-
// A new HWND must save meaningful surface space, not split every fur fleck.
|
|
45
|
-
constexpr uint64_t MinimumSaving=256*1024;
|
|
46
|
-
while(nodes.size()<MaxRegions){
|
|
47
|
-
size_t best=0;for(size_t i=1;i<nodes.size();i++)if(nodes[i].saved>nodes[best].saved)best=i;
|
|
48
|
-
if(nodes[best].saved<MinimumSaving)break;
|
|
49
|
-
const auto selected=nodes[best];nodes[best]=bestSplit(masks,columns,selected.a,cell);
|
|
50
|
-
nodes.push_back(bestSplit(masks,columns,selected.b,cell));
|
|
51
|
-
}
|
|
52
|
-
std::vector<Rect> result;for(const auto& node:nodes)result.push_back(node.box);
|
|
53
|
-
return result;
|
|
26
|
+
return all.empty()?std::vector<Rect>{}:std::vector<Rect>{all};
|
|
54
27
|
}
|
|
55
28
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bitefoundry/retrieviewer",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.20",
|
|
4
4
|
"description": "A fluffy Braille desktop pet for Windows and Linux X11, with experimental macOS support and an embeddable TUI engine.",
|
|
5
5
|
"license": "SEE LICENSE IN LICENSE",
|
|
6
6
|
"homepage": "https://bitefoundry.github.io/retrieviewer/",
|