@geastack/native-webgl-angle 0.1.9 → 0.1.10

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/NOTICE ADDED
@@ -0,0 +1,4 @@
1
+ GeaStack native-webgl-angle
2
+ Copyright 2026 GeaStack
3
+
4
+ Licensed under the Apache License, Version 2.0; see LICENSE.
@@ -168,6 +168,23 @@ extern "C" bool gea_three_key_pressed(double code) {
168
168
  return gGeaKeyState[c];
169
169
  }
170
170
 
171
+ #if defined(_WIN32)
172
+ // The Win32 window procedure owns input on Windows; it reports into the same
173
+ // tables the AppKit host view fills on macOS (keys as macOS virtual key codes).
174
+ extern "C" void gea_three_set_key_state(int code, bool down) {
175
+ if (code >= 0 && code < 256) gGeaKeyState[code] = down;
176
+ }
177
+
178
+ extern "C" void gea_three_set_pointer_state(double x, double y, double width, double height, bool down) {
179
+ gGeaPointerX = x;
180
+ gGeaPointerY = y;
181
+ gGeaPointerW = width;
182
+ gGeaPointerH = height;
183
+ gGeaPointerDown = down;
184
+ gGeaPointerSeq += 1.0;
185
+ }
186
+ #endif
187
+
171
188
  #if !defined(_WIN32)
172
189
  @interface GeaAngleWebGLHostView : NSView
173
190
  @end
@@ -1064,8 +1081,22 @@ extern "C" bool gea_three_webgl_attach(
1064
1081
  if (gWebGL.ready) return true;
1065
1082
 
1066
1083
  #if defined(_WIN32)
1067
- gWebGL.egl = LoadPackagedLibrary(L"libEGL.dll", 0);
1068
- gWebGL.gles = LoadPackagedLibrary(L"libGLESv2.dll", 0);
1084
+ // An override (e.g. threejs-rendozer's GeaRendozerGLES.dll) first, then the
1085
+ // packaged ANGLE of a UWP app, then a plain desktop load next to the exe.
1086
+ auto openWin32 = [](const wchar_t *overrideEnv, const wchar_t *name) -> HMODULE {
1087
+ wchar_t overridePath[MAX_PATH];
1088
+ const DWORD n = GetEnvironmentVariableW(overrideEnv, overridePath, MAX_PATH);
1089
+ if (n > 0 && n < MAX_PATH) {
1090
+ if (HMODULE m = LoadLibraryW(overridePath)) return m;
1091
+ }
1092
+ #if defined(WINAPI_FAMILY) && WINAPI_FAMILY == WINAPI_FAMILY_APP
1093
+ return LoadPackagedLibrary(name, 0);
1094
+ #else
1095
+ return LoadLibraryW(name);
1096
+ #endif
1097
+ };
1098
+ gWebGL.egl = openWin32(L"GEA_ANGLE_EGL_DYLIB", L"libEGL.dll");
1099
+ gWebGL.gles = openWin32(L"GEA_ANGLE_GLES_DYLIB", L"libGLESv2.dll");
1069
1100
  #else
1070
1101
  static const char *const eglPaths[] = {
1071
1102
  "/Applications/Visual Studio Code.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Libraries/libEGL.dylib",
@@ -1400,6 +1431,61 @@ extern "C" void gea_three_webgl_swap() {
1400
1431
  }
1401
1432
  }
1402
1433
  }
1434
+ // Debug recording: GEA_WEBGL_RECORD=<path>[:<seconds>] appends the
1435
+ // framebuffer as raw top-down RGB24 at a constant 30 fps of wall-clock time
1436
+ // (frames repeat or drop to hold the rate), then closes the file. The size
1437
+ // goes to the smoke log; encode with ffmpeg -f rawvideo -pix_fmt rgb24.
1438
+ if (const char *recordSpec = std::getenv("GEA_WEBGL_RECORD"); recordSpec && gWebGL.glReadPixels) {
1439
+ static FILE *recordFile = nullptr;
1440
+ static bool recordDone = false;
1441
+ static double recordSeconds = 30.0;
1442
+ static long long recordWritten = 0;
1443
+ static int recordW = 0, recordH = 0;
1444
+ static std::chrono::steady_clock::time_point recordStart;
1445
+ if (!recordDone && !recordFile) {
1446
+ std::string spec(recordSpec);
1447
+ // A trailing ":<seconds>" sets the length; drive-letter colons stay in the path.
1448
+ if (const size_t colon = spec.rfind(':'); colon != std::string::npos && colon > 1) {
1449
+ recordSeconds = std::atof(spec.c_str() + colon + 1);
1450
+ spec.resize(colon);
1451
+ }
1452
+ recordW = gWebGL.widthPx;
1453
+ recordH = gWebGL.heightPx;
1454
+ recordFile = std::fopen(spec.c_str(), "wb");
1455
+ recordStart = std::chrono::steady_clock::now();
1456
+ if (recordFile) {
1457
+ smokeLog("[record] %dx%d rgb24 30fps %.1fs -> %s", recordW, recordH, recordSeconds, spec.c_str());
1458
+ } else {
1459
+ recordDone = true;
1460
+ }
1461
+ }
1462
+ if (recordFile) {
1463
+ const double elapsed = std::chrono::duration<double>(std::chrono::steady_clock::now() - recordStart).count();
1464
+ const long long due = std::min(static_cast<long long>(elapsed * 30.0) + 1,
1465
+ static_cast<long long>(recordSeconds * 30.0));
1466
+ if (due > recordWritten && gWebGL.widthPx == recordW && gWebGL.heightPx == recordH) {
1467
+ std::vector<unsigned char> rgba(static_cast<size_t>(recordW) * recordH * 4);
1468
+ std::vector<unsigned char> rgb(static_cast<size_t>(recordW) * recordH * 3);
1469
+ gWebGL.glReadPixels(0, 0, recordW, recordH, GL_RGBA_VALUE, GL_UNSIGNED_BYTE, rgba.data());
1470
+ for (int y = 0; y < recordH; ++y) {
1471
+ const unsigned char *src = rgba.data() + static_cast<size_t>(recordH - 1 - y) * recordW * 4;
1472
+ unsigned char *dst = rgb.data() + static_cast<size_t>(y) * recordW * 3;
1473
+ for (int x = 0; x < recordW; ++x) {
1474
+ dst[x * 3 + 0] = src[x * 4 + 0];
1475
+ dst[x * 3 + 1] = src[x * 4 + 1];
1476
+ dst[x * 3 + 2] = src[x * 4 + 2];
1477
+ }
1478
+ }
1479
+ for (; recordWritten < due; ++recordWritten) std::fwrite(rgb.data(), 1, rgb.size(), recordFile);
1480
+ }
1481
+ if (recordWritten >= static_cast<long long>(recordSeconds * 30.0)) {
1482
+ std::fclose(recordFile);
1483
+ recordFile = nullptr;
1484
+ recordDone = true;
1485
+ smokeLog("[record] done: %lld frames", recordWritten);
1486
+ }
1487
+ }
1488
+ }
1403
1489
  // Measure presentation separately from the display-link callback. The
1404
1490
  // latter includes this wait and cannot by itself distinguish frame work
1405
1491
  // from drawable/GPU backpressure. No clock reads run when profiling is off.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@geastack/native-webgl-angle",
3
- "version": "0.1.9",
3
+ "version": "0.1.10",
4
4
  "description": "Typed native WebGL compatibility layer backed by ANGLE/Metal",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {