From 77505f1a2d9aa2c57e170596f660342fa14c0fd9 Mon Sep 17 00:00:00 2001 From: John Bowman Date: Tue, 30 Apr 2024 17:03:37 -0700 Subject: [PATCH 01/51] Fix warning message. --- vkrender.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vkrender.h b/vkrender.h index 355b1ca47..4c064dbd8 100644 --- a/vkrender.h +++ b/vkrender.h @@ -1058,7 +1058,7 @@ class AsyVkRender void travelHome(bool webgl=false); void cycleMode(); - friend class SwapChainDetails; + friend struct SwapChainDetails; }; extern AsyVkRender* vk; From 6e49ae40ed005d720cf3b54d1857a448c22a7475 Mon Sep 17 00:00:00 2001 From: John Bowman Date: Thu, 13 Jun 2024 09:29:35 -0700 Subject: [PATCH 02/51] Exit glfw gracefully. --- vkrender.cc | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/vkrender.cc b/vkrender.cc index 8a2192245..0713dbf9b 100644 --- a/vkrender.cc +++ b/vkrender.cc @@ -533,6 +533,8 @@ void checkpow2(unsigned int n, string s) { } } +void closeWindowHandler(GLFWwindow *); + void AsyVkRender::vkrender(const string& prefix, const picture* pic, const string& format, double Width, double Height, double angle, double zoom, const triple& mins, const triple& maxs, const pair& shift, @@ -730,8 +732,9 @@ void AsyVkRender::vkrender(const string& prefix, const picture* pic, const strin if(window) glfwShowWindow(window); - mainLoop(); + glfwSetWindowCloseCallback(window,closeWindowHandler); + mainLoop(); #endif } @@ -4741,6 +4744,12 @@ void AsyVkRender::quit() #ifdef HAVE_VULKAN +void closeWindowHandler(GLFWwindow *window) +{ + cout << endl; + exitHandler(0); +} + void AsyVkRender::idleFunc(std::function f) { spinTimer.reset(); From 4c0da5a2915ee94ab1d48b6234bee971d97df808 Mon Sep 17 00:00:00 2001 From: John Bowman Date: Fri, 14 Jun 2024 10:51:41 -0700 Subject: [PATCH 03/51] Qualify callback setting. --- vkrender.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/vkrender.cc b/vkrender.cc index 0713dbf9b..3ffbea676 100644 --- a/vkrender.cc +++ b/vkrender.cc @@ -732,7 +732,8 @@ void AsyVkRender::vkrender(const string& prefix, const picture* pic, const strin if(window) glfwShowWindow(window); - glfwSetWindowCloseCallback(window,closeWindowHandler); + if(View) + glfwSetWindowCloseCallback(window,closeWindowHandler); mainLoop(); #endif From 03b28e0addfce2ba0124bd094c69bd8eb3c1325d Mon Sep 17 00:00:00 2001 From: John Bowman Date: Fri, 14 Jun 2024 10:52:30 -0700 Subject: [PATCH 04/51] Don't require deviceFeatures.shaderStorageImageReadWithoutFormat. --- vkrender.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vkrender.cc b/vkrender.cc index 3ffbea676..f8be1618c 100644 --- a/vkrender.cc +++ b/vkrender.cc @@ -1263,7 +1263,7 @@ void AsyVkRender::createLogicalDevice() vk::PhysicalDeviceFeatures deviceFeatures; deviceFeatures.fillModeNonSolid = true; deviceFeatures.shaderStorageImageWriteWithoutFormat=true; - deviceFeatures.shaderStorageImageReadWithoutFormat=true; +// deviceFeatures.shaderStorageImageReadWithoutFormat=true; physicalDevice.getProperties2(&props); From 68990146af784cf663b3a097e42552dcceaccd3d Mon Sep 17 00:00:00 2001 From: John Bowman Date: Thu, 13 Jun 2024 17:44:57 -0700 Subject: [PATCH 05/51] Reset terminal on exit. --- main.cc | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/main.cc b/main.cc index 425c7c130..d5c792745 100644 --- a/main.cc +++ b/main.cc @@ -54,6 +54,12 @@ #include "stack.h" +#ifdef HAVE_LIBCURSES +#ifdef HAVE_LIBREADLINE +#include +#endif +#endif + using namespace settings; using interact::interactive; @@ -240,6 +246,9 @@ void *asymain(void *A) void exitHandler(int) { +#if defined(HAVE_READLINE) && defined(HAVE_LIBCURSES) + rl_cleanup_after_signal(); +#endif exit(returnCode()); } From 2d006ca94e783d8722e6bbde0ade9106bfce9ac1 Mon Sep 17 00:00:00 2001 From: John Bowman Date: Fri, 14 Jun 2024 23:29:33 -0700 Subject: [PATCH 06/51] VK: Remove unnecessary feature requirements. --- vkrender.cc | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/vkrender.cc b/vkrender.cc index f8be1618c..451f63015 100644 --- a/vkrender.cc +++ b/vkrender.cc @@ -542,9 +542,6 @@ void AsyVkRender::vkrender(const string& prefix, const picture* pic, const strin double* background, size_t nlightsin, triple* lights, double* diffuse, double* specular, bool view, int oldpid/*=0*/) { - // By default use discrete GPU. - setenv("DRI_PRIME","1",0); - glfwInit(); offscreen=settings::getSetting("offscreen"); @@ -1262,7 +1259,7 @@ void AsyVkRender::createLogicalDevice() vk::PhysicalDeviceFeatures deviceFeatures; deviceFeatures.fillModeNonSolid = true; - deviceFeatures.shaderStorageImageWriteWithoutFormat=true; +// deviceFeatures.shaderStorageImageWriteWithoutFormat=true; // deviceFeatures.shaderStorageImageReadWithoutFormat=true; physicalDevice.getProperties2(&props); From 63e9c2dd645761f368bfe12f356120e798fc4b26 Mon Sep 17 00:00:00 2001 From: John Bowman Date: Sat, 15 Jun 2024 16:25:41 -0700 Subject: [PATCH 07/51] Use software renderer for remote rendering over X11. --- vkrender.cc | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/vkrender.cc b/vkrender.cc index 451f63015..f41507d8d 100644 --- a/vkrender.cc +++ b/vkrender.cc @@ -1026,8 +1026,11 @@ void AsyVkRender::createAllocator() void AsyVkRender::pickPhysicalDevice() { + string display(getenv("DISPLAY")); + bool remote=display.find(":") != 0; + auto const getDeviceScore = - [this](vk::PhysicalDevice& device) -> std::size_t + [this,remote](vk::PhysicalDevice& device) -> std::size_t { std::size_t score = 0u; @@ -1059,14 +1062,17 @@ void AsyVkRender::pickPhysicalDevice() auto const props = device.getProperties(); + bool software=offscreen || remote; + if(vk::PhysicalDeviceType::eDiscreteGpu == props.deviceType) { + if(software) return 0; score += 10; - } - else if(vk::PhysicalDeviceType::eIntegratedGpu == props.deviceType) { + } else if(vk::PhysicalDeviceType::eIntegratedGpu == props.deviceType) { + if(software) return 0; score += 5; - } - else if (vk::PhysicalDeviceType::eCpu == props.deviceType && offscreen) { - // Force using cpu for offscreen + } else if(vk::PhysicalDeviceType::eCpu == props.deviceType && + software) { + // Force using software renderer for remote or offscreen rendering score += 100; } From 5aadc4b713fe0ba40ff0b3500e45c6ab781bde65 Mon Sep 17 00:00:00 2001 From: John Bowman Date: Sun, 16 Jun 2024 11:38:19 -0700 Subject: [PATCH 08/51] Fix point topology and fill mode. --- vkrender.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/vkrender.cc b/vkrender.cc index f41507d8d..4f200c20a 100644 --- a/vkrender.cc +++ b/vkrender.cc @@ -3320,7 +3320,7 @@ void AsyVkRender::createGraphicsPipelines() for (auto u = 0u; u < PIPELINE_MAX; u++) createGraphicsPipeline (PipelineType(u), linePipelines[u], vk::PrimitiveTopology::eLineList, - vk::PolygonMode::eFill, + vk::PolygonMode::eLine, materialShaderOptions, "vertex", "fragment", @@ -3328,8 +3328,8 @@ void AsyVkRender::createGraphicsPipelines() for (auto u = 0u; u < PIPELINE_MAX; u++) createGraphicsPipeline - (PipelineType(u), pointPipelines[u], vk::PrimitiveTopology::eTriangleList, - drawMode, + (PipelineType(u), pointPipelines[u], vk::PrimitiveTopology::ePointList, + vk::PolygonMode::ePoint, pointShaderOptions, "vertex", "fragment", From 227cd2bdc323e28f1a90ec9635dee3699bfb996f Mon Sep 17 00:00:00 2001 From: John Bowman Date: Sun, 16 Jun 2024 13:17:29 -0700 Subject: [PATCH 09/51] VK: Reset renderCount for lines and points. --- beziercurve.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/beziercurve.h b/beziercurve.h index 7f22fb1d0..af48d0525 100644 --- a/beziercurve.h +++ b/beziercurve.h @@ -43,8 +43,13 @@ struct BezierCurve vk->lineData.extendMaterial(data); } + void notRendered() { + vk->lineData.renderCount=0; + } + void queue(const triple *g, bool straight, double ratio) { data.clear(); + notRendered(); Onscreen=true; init(pixelResolution*ratio); render(g,straight); @@ -59,8 +64,13 @@ struct Pixel vk->pointData.extendPoint(data); } + void notRendered() { + vk->pointData.renderCount=0; + } + void queue(const triple& p, double width) { data.clear(); + notRendered(); MaterialIndex=vk->materialIndex; data.indices.push_back(data.addVertex(PointVertex{p,(float)width,MaterialIndex})); append(); From 9467be4123d055ff1d0e3b2ac5328457eedfe27e Mon Sep 17 00:00:00 2001 From: John Bowman Date: Sun, 16 Jun 2024 14:48:04 -0700 Subject: [PATCH 10/51] VK: Fix material map. --- vkrender.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/vkrender.h b/vkrender.h index 4c064dbd8..e03c25ca2 100644 --- a/vkrender.h +++ b/vkrender.h @@ -74,7 +74,8 @@ class picture; #define RAW_VIEW(x) static_cast(sizeof(x)), x #define ST_VIEW(s) static_cast(sizeof(s)), &s -typedef std::unordered_map MaterialMap; +//typedef mem::unordered_map MaterialMap; +typedef mem::map MaterialMap; template inline T ceilquotient(T a, T b) From 8963f8517d39e4cc739839dd77f0bb74523b6705 Mon Sep 17 00:00:00 2001 From: John Bowman Date: Sun, 16 Jun 2024 17:03:17 -0700 Subject: [PATCH 11/51] VK: fix MacOS dependencies. --- configure.ac | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 88eed0b81..a2db593fd 100644 --- a/configure.ac +++ b/configure.ac @@ -473,7 +473,15 @@ case "$OSTYPE" in AC_CHECK_LIB([vulkan], [vkCreateInstance], [ LIBS_SAVE=$LIBS - LIBS=$LIBS"-lglfw -lvulkan -lMachineIndependent -lOSDependent -lGenericCodeGen -lSPIRV -lglslang " + case "$OSTYPE" in + darwin*) + VULKAN_LIBS="" + ;; + *) + VULKAN_LIBS="-lMachineIndependent -lOSDependent -lGenericCodeGen " + ;; + esac + LIBS=$LIBS"-lglfw -lvulkan "$VULKAN_LIBS"-lSPIRV -lglslang " AC_CHECK_LIB([glslang],[glslang_initialize_process], [ AC_DEFINE(HAVE_LIBVULKAN,1, From e6b1417a59ea61767336f45f49050e91153826ac Mon Sep 17 00:00:00 2001 From: John Bowman Date: Sun, 16 Jun 2024 19:44:19 -0700 Subject: [PATCH 12/51] Remove obsolete code. --- configure.ac | 14 +++----------- memory.h | 10 ---------- vkrender.h | 1 - 3 files changed, 3 insertions(+), 22 deletions(-) diff --git a/configure.ac b/configure.ac index a2db593fd..02c9c7968 100644 --- a/configure.ac +++ b/configure.ac @@ -144,17 +144,9 @@ AC_DEFUN([DEFINE_LIB],[ Define to 1 if you have the `$1' library (-l$1). ]) -AC_CHECK_HEADER(tr1/unordered_map) -AC_COMPILE_IFELSE([AC_LANG_PROGRAM( - [#include ] - [std::tr1::unordered_map map;] - )], - AC_DEFINE(HAVE_TR1_UNORDERED_MAP,1, - DEFINE([])), - [ - AC_CHECK_HEADER(unordered_map,AC_DEFINE(HAVE_UNORDERED_MAP,1, - DEFINE([])), - [AC_CHECK_HEADER(ext/hash_map,,OPTIONS=$OPTIONS"-DNOHASH ")])]) +AC_CHECK_HEADER(unordered_map,AC_DEFINE(HAVE_UNORDERED_MAP,1, + DEFINE([])), +[AC_CHECK_HEADER(ext/hash_map,,OPTIONS=$OPTIONS"-DNOHASH ")]) ASYGLVERSION=1.02 diff --git a/memory.h b/memory.h index 3ddc2aaea..d706fd154 100644 --- a/memory.h +++ b/memory.h @@ -17,14 +17,6 @@ #ifndef NOHASH -#ifdef HAVE_TR1_UNORDERED_MAP - -#include -#include -#define EXT std::tr1 - -#else - #ifdef HAVE_UNORDERED_MAP #include #define EXT std @@ -37,8 +29,6 @@ #endif -#endif - #ifdef __DECCXX_LIBCXX_RH70 #define CONST #else diff --git a/vkrender.h b/vkrender.h index e03c25ca2..a1ad9baf9 100644 --- a/vkrender.h +++ b/vkrender.h @@ -74,7 +74,6 @@ class picture; #define RAW_VIEW(x) static_cast(sizeof(x)), x #define ST_VIEW(s) static_cast(sizeof(s)), &s -//typedef mem::unordered_map MaterialMap; typedef mem::map MaterialMap; template From ae9a960a4723074a382ce122cc3a8046910178f8 Mon Sep 17 00:00:00 2001 From: John Bowman Date: Sun, 16 Jun 2024 22:49:03 -0700 Subject: [PATCH 13/51] Don't initialize GLFW for WebGL or V3D output. --- vkrender.cc | 32 +++++++++++++++++++------------- vkrender.h | 2 +- 2 files changed, 20 insertions(+), 14 deletions(-) diff --git a/vkrender.cc b/vkrender.cc index 4f200c20a..4ee44d87e 100644 --- a/vkrender.cc +++ b/vkrender.cc @@ -542,11 +542,19 @@ void AsyVkRender::vkrender(const string& prefix, const picture* pic, const strin double* background, size_t nlightsin, triple* lights, double* diffuse, double* specular, bool view, int oldpid/*=0*/) { - glfwInit(); + int k=0; + bool v3d=format == "v3d"; + bool webgl=format == "html"; + bool format3d=webgl || v3d; offscreen=settings::getSetting("offscreen"); - GLFWmonitor* monitor=glfwGetPrimaryMonitor(); - if(!monitor) offscreen=true; + + GLFWmonitor* monitor=NULL; + if(!format3d) { + glfwInit(); + monitor=glfwGetPrimaryMonitor(); + if(!monitor) offscreen=true; + } this->pic = pic; this->Prefix=prefix; @@ -583,10 +591,6 @@ void AsyVkRender::vkrender(const string& prefix, const picture* pic, const strin H = orthographic ? 0.0 : -tan(0.5 * this->Angle) * Zmax; Xfactor = Yfactor = 1.0; - bool v3d=format == "v3d"; - bool webgl=format == "html"; - bool format3d=webgl || v3d; - #ifdef HAVE_PTHREAD static bool initializedView=false; if(vkinitialize) @@ -612,12 +616,14 @@ void AsyVkRender::vkrender(const string& prefix, const picture* pic, const strin fullWidth=(int) ceil(expand*Width); fullHeight=(int) ceil(expand*Height); - if(offscreen) { - screenWidth=fullWidth; - screenHeight=fullHeight; - } else { - int mx, my; - glfwGetMonitorWorkarea(monitor, &mx, &my, &screenWidth, &screenHeight); + if(!format3d) { + if(offscreen) { + screenWidth=fullWidth; + screenHeight=fullHeight; + } else { + int mx, my; + glfwGetMonitorWorkarea(monitor, &mx, &my, &screenWidth, &screenHeight); + } } oWidth=Width; diff --git a/vkrender.h b/vkrender.h index a1ad9baf9..4c2f8973d 100644 --- a/vkrender.h +++ b/vkrender.h @@ -64,7 +64,7 @@ namespace camp class picture; // Comment out when not debugging: -#define VALIDATION +//#define VALIDATION #define EMPTY_VIEW 0, nullptr #define SINGLETON_VIEW(x) 1, &(x) From 7a9bf282acdc6f05d711bfd1688140802e817e91 Mon Sep 17 00:00:00 2001 From: John Bowman Date: Sun, 16 Jun 2024 23:14:14 -0700 Subject: [PATCH 14/51] Don't initialize GLFW when rendering offscreen. --- vkrender.cc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/vkrender.cc b/vkrender.cc index 4ee44d87e..1705f3184 100644 --- a/vkrender.cc +++ b/vkrender.cc @@ -542,7 +542,6 @@ void AsyVkRender::vkrender(const string& prefix, const picture* pic, const strin double* background, size_t nlightsin, triple* lights, double* diffuse, double* specular, bool view, int oldpid/*=0*/) { - int k=0; bool v3d=format == "v3d"; bool webgl=format == "html"; bool format3d=webgl || v3d; @@ -550,7 +549,7 @@ void AsyVkRender::vkrender(const string& prefix, const picture* pic, const strin offscreen=settings::getSetting("offscreen"); GLFWmonitor* monitor=NULL; - if(!format3d) { + if(!(offscreen || format3d)) { glfwInit(); monitor=glfwGetPrimaryMonitor(); if(!monitor) offscreen=true; From dce0e4f0bc9799d2f77a19c722b9fcbf6b6bbcba Mon Sep 17 00:00:00 2001 From: John Bowman Date: Mon, 17 Jun 2024 20:54:50 -0700 Subject: [PATCH 15/51] Fix prerendering bounds. --- vkrender.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vkrender.cc b/vkrender.cc index 1705f3184..e4bcc5262 100644 --- a/vkrender.cc +++ b/vkrender.cc @@ -249,7 +249,7 @@ double AsyVkRender::getRenderResolution(triple Min) const double perspective = orthographic ? 0.0 : 1.0 / Zmax; double s = perspective ? Min.getz() * perspective : 1.0; triple b(Xmin, Ymin, Zmin); - triple B(Xmax, Ymin, Zmax); + triple B(Xmax, Ymax, Zmax); pair size3(s * (B.getx() - b.getx()), s * (B.gety() - b.gety())); pair size2(width, height); return prerender * size3.length() / size2.length(); From 253ef39e117199afa83a211c0e36d12c59dbf22b Mon Sep 17 00:00:00 2001 From: John Bowman Date: Mon, 17 Jun 2024 20:55:04 -0700 Subject: [PATCH 16/51] Remove unused code. --- bezierpatch.cc | 45 +++------------------------------------------ bezierpatch.h | 2 -- 2 files changed, 3 insertions(+), 44 deletions(-) diff --git a/bezierpatch.cc b/bezierpatch.cc index a7244ef44..f2e520a00 100644 --- a/bezierpatch.cc +++ b/bezierpatch.cc @@ -793,45 +793,6 @@ void BezierTriangle::render(const triple *p, std::vector zbuffer; -void transform(const std::vector& b) -{ - unsigned n=b.size(); - zbuffer.resize(n); - - double Tz0=glm::value_ptr(vk->viewMat)[2]; - double Tz1=glm::value_ptr(vk->viewMat)[6]; - double Tz2=glm::value_ptr(vk->viewMat)[10]; - for(unsigned i=0; i < n; ++i) { - const glm::vec3 v=b[i].position; - zbuffer[i]=Tz0*v.x+Tz1*v.y+Tz2*v.z; - } -} - -// Sort nonintersecting triangles by depth. -int compare(const void *p, const void *P) -{ - unsigned Ia=((uint32_t *) p)[0]; - unsigned Ib=((uint32_t *) p)[1]; - unsigned Ic=((uint32_t *) p)[2]; - - unsigned IA=((uint32_t *) P)[0]; - unsigned IB=((uint32_t *) P)[1]; - unsigned IC=((uint32_t *) P)[2]; - - return zbuffer[Ia]+zbuffer[Ib]+zbuffer[Ic] < - zbuffer[IA]+zbuffer[IB]+zbuffer[IC] ? -1 : 1; -} - -// what is this for? -void sortTriangles() -{ - if(!vk->transparentData.indices.empty()) { - transform(vk->transparentData.colorVertices); - qsort(&vk->transparentData.indices[0],vk->transparentData.indices.size()/3, - 3*sizeof(uint32_t),compare); - } -} - void Triangles::queue(size_t nP, const triple* P, size_t nN, const triple* N, size_t nC, const prc::RGBAColour* C, size_t nI, const uint32_t (*PP)[3], const uint32_t (*NN)[3], @@ -873,9 +834,9 @@ void Triangles::queue(size_t nP, const triple* P, size_t nN, const triple* N, data.colorVertices[PI1]=ColorVertex{P1,N[NI[1]],MaterialIndex,glm::make_vec4(c1)}; data.colorVertices[PI2]=ColorVertex{P2,N[NI[2]],MaterialIndex,glm::make_vec4(c2)}; } else { - data.colorVertices[PI0]=ColorVertex{P0,N[NI[0]],MaterialIndex,glm::vec4(1.0f)}; - data.colorVertices[PI1]=ColorVertex{P1,N[NI[1]],MaterialIndex,glm::vec4(1.0f)}; - data.colorVertices[PI2]=ColorVertex{P2,N[NI[2]],MaterialIndex,glm::vec4(1.0f)}; + data.colorVertices[PI0]=ColorVertex{P0,N[NI[0]],MaterialIndex}; + data.colorVertices[PI1]=ColorVertex{P1,N[NI[1]],MaterialIndex}; + data.colorVertices[PI2]=ColorVertex{P2,N[NI[2]],MaterialIndex}; } triple Q[]={P0,P1,P2}; if(!offscreen(3,Q)) { diff --git a/bezierpatch.h b/bezierpatch.h index 61b0a8a81..f7cfa03ef 100644 --- a/bezierpatch.h +++ b/bezierpatch.h @@ -224,8 +224,6 @@ struct Triangles : public BezierPatch { } }; -extern void sortTriangles(); - #endif } //namespace camp From d57861c5386b7ce591632a321a16a1bdd6e31592 Mon Sep 17 00:00:00 2001 From: John Bowman Date: Mon, 17 Jun 2024 22:00:18 -0700 Subject: [PATCH 17/51] Reject negative zoomFactors again. --- vkrender.cc | 32 ++++++++++++++------------------ 1 file changed, 14 insertions(+), 18 deletions(-) diff --git a/vkrender.cc b/vkrender.cc index e4bcc5262..0039cb9a8 100644 --- a/vkrender.cc +++ b/vkrender.cc @@ -385,13 +385,12 @@ void AsyVkRender::scrollCallback(GLFWwindow* window, double xoffset, double yoff auto app = reinterpret_cast(glfwGetWindowUserPointer(window)); auto zoomFactor = settings::getSetting("zoomfactor"); - if (zoomFactor == 0.0) - return; - - if (yoffset > 0) - app->Zoom0 *= zoomFactor; - else - app->Zoom0 /= zoomFactor; + if(zoomFactor > 0.0) { + if (yoffset > 0) + app->Zoom0 *= zoomFactor; + else + app->Zoom0 /= zoomFactor; + } app->update(); } @@ -4905,17 +4904,14 @@ void AsyVkRender::capzoom() void AsyVkRender::zoom(double dx, double dy) { double zoomFactor=settings::getSetting("zoomfactor"); - - if (zoomFactor == 0.0) - return; - - double zoomStep=settings::getSetting("zoomstep"); - const double limit=log(0.1*DBL_MAX)/log(zoomFactor); - double stepPower=zoomStep*dy; - if(fabs(stepPower) < limit) { - Zoom0 *= std::pow(zoomFactor,-stepPower); - capzoom(); - update(); + if (zoomFactor > 0.0) { + double zoomStep=settings::getSetting("zoomstep"); + const double limit=log(0.1*DBL_MAX)/log(zoomFactor); + double stepPower=zoomStep*dy; + if(fabs(stepPower) < limit) { + Zoom0 *= std::pow(zoomFactor,-stepPower); + update(); + } } } From 25a22b70292ac8550444bf3ebc5bbdc23702f048 Mon Sep 17 00:00:00 2001 From: John Bowman Date: Mon, 17 Jun 2024 22:10:25 -0700 Subject: [PATCH 18/51] Fix offscreen culling of triangle groups. --- bezierpatch.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/bezierpatch.cc b/bezierpatch.cc index f2e520a00..59ce924d8 100644 --- a/bezierpatch.cc +++ b/bezierpatch.cc @@ -803,6 +803,7 @@ void Triangles::queue(size_t nP, const triple* P, size_t nN, const triple* N, data.clear(); Onscreen=true; transparent=Transparent; + notRendered(); data.colorVertices.resize(nP); data.indices.resize(3*nI); From 41b647719577759dbb7a5fabde1834e5381fc612 Mon Sep 17 00:00:00 2001 From: John Bowman Date: Mon, 17 Jun 2024 23:06:35 -0700 Subject: [PATCH 19/51] VK: Hide window while fitting. --- vkrender.cc | 8 +++++++- vkrender.h | 1 + 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/vkrender.cc b/vkrender.cc index 0039cb9a8..cc5fb26ca 100644 --- a/vkrender.cc +++ b/vkrender.cc @@ -4334,6 +4334,11 @@ void AsyVkRender::display() drawFrame(); + if(hidden) { + glfwShowWindow(window); + hidden=false; + } + if (mode != DRAWMODE_OUTLINE) remesh = false; @@ -5023,7 +5028,6 @@ void AsyVkRender::setosize() { } void AsyVkRender::fitscreen(bool reposition) { - if(Animate && Fitscreen == 2) Fitscreen=0; switch(Fitscreen) { @@ -5056,6 +5060,8 @@ void AsyVkRender::fitscreen(bool reposition) { void AsyVkRender::toggleFitScreen() { + glfwHideWindow(window); + hidden=true; Fitscreen = (Fitscreen + 1) % 3; fitscreen(); } diff --git a/vkrender.h b/vkrender.h index 4c2f8973d..bd28c2dfb 100644 --- a/vkrender.h +++ b/vkrender.h @@ -401,6 +401,7 @@ class AsyVkRender bool ibl=false; bool offscreen=false; bool vkexit=false; + bool hidden=false; bool vkthread=false;; bool initialize=true; From b947a8381eea50864bbd920343ffe406fd418771 Mon Sep 17 00:00:00 2001 From: John Bowman Date: Mon, 17 Jun 2024 23:19:05 -0700 Subject: [PATCH 20/51] VK: Hide window while resizing. --- vkrender.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/vkrender.cc b/vkrender.cc index cc5fb26ca..52494db8d 100644 --- a/vkrender.cc +++ b/vkrender.cc @@ -4957,7 +4957,6 @@ void AsyVkRender::windowposition(int& x, int& y, int Width, int Height) } void AsyVkRender::setsize(int w, int h, bool reposition) { - int x,y; capsize(w,h); @@ -5019,6 +5018,8 @@ void AsyVkRender::reshape0(int Width, int Height) { lastHeight=height; } + glfwHideWindow(window); + hidden=true; setProjection(); } From df757fd3d916fe98d8e34edc3ec240bee773ada0 Mon Sep 17 00:00:00 2001 From: John Bowman Date: Tue, 18 Jun 2024 12:32:31 -0700 Subject: [PATCH 21/51] VK: Support nolight. --- vkrender.cc | 36 ++++++++++++++++++++---------------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/vkrender.cc b/vkrender.cc index 52494db8d..469354017 100644 --- a/vkrender.cc +++ b/vkrender.cc @@ -2576,21 +2576,23 @@ void AsyVkRender::createBuffers() void AsyVkRender::createMaterialAndLightBuffers() { - materialBf = createBufferUnique( - vk::BufferUsageFlagBits::eStorageBuffer | vk::BufferUsageFlagBits::eTransferDst, - VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, - sizeof(camp::Material) * nmaterials, - 0, - VMA_MEMORY_USAGE_AUTO, - VARIABLE_NAME(materialBf)); + if(nmaterials > 0) + materialBf = createBufferUnique( + vk::BufferUsageFlagBits::eStorageBuffer | vk::BufferUsageFlagBits::eTransferDst, + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, + sizeof(camp::Material) * nmaterials, + 0, + VMA_MEMORY_USAGE_AUTO, + VARIABLE_NAME(materialBf)); - lightBf = createBufferUnique( - vk::BufferUsageFlagBits::eStorageBuffer | vk::BufferUsageFlagBits::eTransferDst, - VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, - sizeof(camp::Light) * nlights, - 0, - VMA_MEMORY_USAGE_AUTO, - VARIABLE_NAME(lightBf)); + if(nlights > 0) + lightBf = createBufferUnique( + vk::BufferUsageFlagBits::eStorageBuffer | vk::BufferUsageFlagBits::eTransferDst, + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, + sizeof(camp::Light) * nlights, + 0, + VMA_MEMORY_USAGE_AUTO, + VARIABLE_NAME(lightBf)); } void AsyVkRender::createImmediateRenderTargets() @@ -3517,8 +3519,10 @@ void AsyVkRender::updateBuffers() createMaterialAndLightBuffers(); writeMaterialAndLightDescriptors(); - copyToBuffer(lightBf.getBuffer(), &lights[0], lights.size() * sizeof(Light)); - copyToBuffer(materialBf.getBuffer(), &materials[0], materials.size() * sizeof(camp::Material)); + if(lights.size() > 0) + copyToBuffer(lightBf.getBuffer(), lights.data(), lights.size() * sizeof(Light)); + if(materials.size() > 0) + copyToBuffer(materialBf.getBuffer(), materials.data(), materials.size() * sizeof(camp::Material)); shouldUpdateBuffers=false; } From e90ff23936d271ae2120e0d80c9b2a9a4acb7f9c Mon Sep 17 00:00:00 2001 From: John Bowman Date: Tue, 18 Jun 2024 13:56:14 -0700 Subject: [PATCH 22/51] Avoid duplicate library. --- configure.ac | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index 02c9c7968..8392078c7 100644 --- a/configure.ac +++ b/configure.ac @@ -470,10 +470,10 @@ case "$OSTYPE" in VULKAN_LIBS="" ;; *) - VULKAN_LIBS="-lMachineIndependent -lOSDependent -lGenericCodeGen " + VULKAN_LIBS="-lMachineIndependent -lOSDependent -lGenericCodeGen -lglslang" ;; esac - LIBS=$LIBS"-lglfw -lvulkan "$VULKAN_LIBS"-lSPIRV -lglslang " + LIBS=$LIBS"-lglfw -lvulkan "$VULKAN_LIBS"-lSPIRV " AC_CHECK_LIB([glslang],[glslang_initialize_process], [ AC_DEFINE(HAVE_LIBVULKAN,1, From 25ac230f5d94c1db31becb59833b30328da8631e Mon Sep 17 00:00:00 2001 From: John Bowman Date: Tue, 18 Jun 2024 15:00:05 -0700 Subject: [PATCH 23/51] Check if DISPLAY environment variable is defined. --- vkrender.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/vkrender.cc b/vkrender.cc index 469354017..9615b25e7 100644 --- a/vkrender.cc +++ b/vkrender.cc @@ -1030,8 +1030,8 @@ void AsyVkRender::createAllocator() void AsyVkRender::pickPhysicalDevice() { - string display(getenv("DISPLAY")); - bool remote=display.find(":") != 0; + char *display=getenv("DISPLAY"); + bool remote=display ? string(display).find(":") != 0 : false; auto const getDeviceScore = [this,remote](vk::PhysicalDevice& device) -> std::size_t From 750826b1d0d92cce71626d56c2d3ca6218506bab Mon Sep 17 00:00:00 2001 From: Cole White Date: Wed, 19 Jun 2024 20:19:26 -0600 Subject: [PATCH 24/51] Add space to fix library list in configure file. --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 8392078c7..bb4f95676 100644 --- a/configure.ac +++ b/configure.ac @@ -470,7 +470,7 @@ case "$OSTYPE" in VULKAN_LIBS="" ;; *) - VULKAN_LIBS="-lMachineIndependent -lOSDependent -lGenericCodeGen -lglslang" + VULKAN_LIBS="-lMachineIndependent -lOSDependent -lGenericCodeGen -lglslang " ;; esac LIBS=$LIBS"-lglfw -lvulkan "$VULKAN_LIBS"-lSPIRV " From 26edf619bb536fd927da35b6e5415bf7cf35eb63 Mon Sep 17 00:00:00 2001 From: Cole White Date: Thu, 20 Jun 2024 19:10:27 -0600 Subject: [PATCH 25/51] Add logging for failure to create render passes. --- vkrender.cc | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/vkrender.cc b/vkrender.cc index 9615b25e7..45fd3f1a5 100644 --- a/vkrender.cc +++ b/vkrender.cc @@ -2924,6 +2924,10 @@ void AsyVkRender::createCountRenderPass() ); countRenderPass = device->createRenderPass2Unique(renderPassCI); + + if (!countRenderPass) { + throw std::runtime_error("Failed to create the count render pass."); + } } void AsyVkRender::createGraphicsRenderPass() @@ -3058,6 +3062,10 @@ void AsyVkRender::createGraphicsRenderPass() ); opaqueGraphicsRenderPass = device->createRenderPass2Unique(opaqueRenderPassCI); + if (!opaqueGraphicsRenderPass) { + throw std::runtime_error("Failed to create the opaque render pass."); + } + auto renderPassCI = vk::RenderPassCreateInfo2( vk::RenderPassCreateFlags(), attachments.size(), @@ -3068,6 +3076,10 @@ void AsyVkRender::createGraphicsRenderPass() dependencies.data() ); graphicsRenderPass = device->createRenderPass2Unique(renderPassCI); + + if (!graphicsRenderPass) { + throw std::runtime_error("Failed to create the graphics render pass."); + } } void AsyVkRender::createGraphicsPipelineLayout() From 982f95e99cfab8ce75190737fe8eb4b3d2434bce Mon Sep 17 00:00:00 2001 From: John Bowman Date: Wed, 26 Jun 2024 14:39:10 -0700 Subject: [PATCH 26/51] Fix last revision. --- drawsurface.cc | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/drawsurface.cc b/drawsurface.cc index 2145b33a1..897969af6 100644 --- a/drawsurface.cc +++ b/drawsurface.cc @@ -489,11 +489,7 @@ bool drawBezierTriangle::write(abs3Doutfile *out) } else { double prerender=vk->getRenderResolution(Min); if(prerender) { -<<<<<<< HEAD - float c[16]; -======= - GLfloat c[12]; ->>>>>>> master + float c[12]; if(colors) for(size_t i=0; i < 3; ++i) storecolor(c,4*i,colors[i]); From d938602555a329852c4c310a808db15852e8371a Mon Sep 17 00:00:00 2001 From: John Bowman Date: Fri, 28 Jun 2024 11:41:49 -0700 Subject: [PATCH 27/51] Fix segmentation fault. --- vkrender.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vkrender.h b/vkrender.h index bd28c2dfb..30f9f4dee 100644 --- a/vkrender.h +++ b/vkrender.h @@ -74,7 +74,7 @@ class picture; #define RAW_VIEW(x) static_cast(sizeof(x)), x #define ST_VIEW(s) static_cast(sizeof(s)), &s -typedef mem::map MaterialMap; +typedef std::map MaterialMap; template inline T ceilquotient(T a, T b) From 1247f8d6674bcf54ed90ba6d5ebbe0ac3a79529f Mon Sep 17 00:00:00 2001 From: Cole White Date: Sat, 29 Jun 2024 12:27:56 -0600 Subject: [PATCH 28/51] Use memory requirements2 instance extension if available. --- vkrender.cc | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/vkrender.cc b/vkrender.cc index 45fd3f1a5..3ede0027e 100644 --- a/vkrender.cc +++ b/vkrender.cc @@ -885,8 +885,9 @@ void AsyVkRender::createInstance() VK_MAKE_VERSION(1, 0, 0), VK_API_VERSION_1_2 ); - auto extensions = getRequiredInstanceExtensions(); + auto supportedExtensions = getInstanceExtensions(); auto supportedLayers = vk::enumerateInstanceLayerProperties(); + auto extensions = getRequiredInstanceExtensions(); auto isLayerSupported = [supportedLayers](std::string layerName) { return std::find_if( @@ -897,6 +898,15 @@ void AsyVkRender::createInstance() }) != supportedLayers.end(); }; + auto isExtensionSupported = [supportedExtensions](std::string extension) { + return std::find_if( + supportedExtensions.begin(), + supportedExtensions.end(), + [extension](std::string const& supportedExt) { + return supportedExt == extension; + }) != supportedExtensions.end(); + }; + #ifdef VALIDATION if (isLayerSupported(VALIDATION_LAYER)) { validationLayers.emplace_back(VALIDATION_LAYER); @@ -913,6 +923,12 @@ void AsyVkRender::createInstance() } } + // For some Mac users, there is the instance extension available VK_KHR_get_memory_requirements2, which may + // be needed for VMA + if (isExtensionSupported(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME)) { + extensions.emplace_back(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME); + } + auto const instanceCI = vk::InstanceCreateInfo( vk::InstanceCreateFlagBits::eEnumeratePortabilityKHR, &appInfo, From 6623866fe69752e79f184e386ef0427fbf60ef67 Mon Sep 17 00:00:00 2001 From: Cole White Date: Sat, 27 Jul 2024 17:22:20 -0600 Subject: [PATCH 29/51] Use all available extensions to test VMA support. --- vkrender.cc | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/vkrender.cc b/vkrender.cc index b6891930d..374420c8b 100644 --- a/vkrender.cc +++ b/vkrender.cc @@ -923,19 +923,19 @@ void AsyVkRender::createInstance() } } - // For some Mac users, there is the instance extension available VK_KHR_get_memory_requirements2, which may - // be needed for VMA - if (isExtensionSupported(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME)) { - extensions.emplace_back(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME); - } + // Use all available extensions temporarily as a test to get VMA to work on some Mac machines + std::vector allExtensions {}; + + // Fill allExtensions with the supported extension list + std::transform(supportedExtensions.begin(), supportedExtensions.end(), std::back_inserter(allExtensions), [](std::string const& ext) { return ext.c_str(); }); auto const instanceCI = vk::InstanceCreateInfo( vk::InstanceCreateFlagBits::eEnumeratePortabilityKHR, &appInfo, validationLayers.size(), validationLayers.data(), - extensions.size(), - extensions.data() + allExtensions.size(), + allExtensions.data() ); instance = vk::createInstanceUnique(instanceCI); VULKAN_HPP_DEFAULT_DISPATCHER.init(*instance); From 6717897942efb2bfe079e1c41c088fa51fd7469b Mon Sep 17 00:00:00 2001 From: Cole White Date: Mon, 5 Aug 2024 22:14:31 -0600 Subject: [PATCH 30/51] Resolve vkGetBufferMemoryRequirements2 VMA function. --- vkrender.cc | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/vkrender.cc b/vkrender.cc index 374420c8b..9be7ca76a 100644 --- a/vkrender.cc +++ b/vkrender.cc @@ -923,19 +923,13 @@ void AsyVkRender::createInstance() } } - // Use all available extensions temporarily as a test to get VMA to work on some Mac machines - std::vector allExtensions {}; - - // Fill allExtensions with the supported extension list - std::transform(supportedExtensions.begin(), supportedExtensions.end(), std::back_inserter(allExtensions), [](std::string const& ext) { return ext.c_str(); }); - auto const instanceCI = vk::InstanceCreateInfo( vk::InstanceCreateFlagBits::eEnumeratePortabilityKHR, &appInfo, validationLayers.size(), validationLayers.data(), - allExtensions.size(), - allExtensions.data() + extensions.size(), + extensions.data() ); instance = vk::createInstanceUnique(instanceCI); VULKAN_HPP_DEFAULT_DISPATCHER.init(*instance); @@ -1033,6 +1027,7 @@ void AsyVkRender::createAllocator() VmaVulkanFunctions vkFuncs = {}; vkFuncs.vkGetInstanceProcAddr = vk::defaultDispatchLoaderDynamic.vkGetInstanceProcAddr; vkFuncs.vkGetDeviceProcAddr = vk::defaultDispatchLoaderDynamic.vkGetDeviceProcAddr; + vkFuncs.vkGetBufferMemoryRequirements2KHR = vk::defaultDispatchLoaderDynamic.vkGetBufferMemoryRequirements2; VmaAllocatorCreateInfo createInfo = {}; createInfo.vulkanApiVersion = VK_API_VERSION_1_2; From 84cb65444fb36648601b5c81849597658cfbcc1d Mon Sep 17 00:00:00 2001 From: John Bowman Date: Fri, 19 Jul 2024 09:31:26 -0700 Subject: [PATCH 31/51] WebGL: Allow triangle data array assignments. --- webgl/gl.js | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/webgl/gl.js b/webgl/gl.js index 5e6fc1ac5..024a886fc 100644 --- a/webgl/gl.js +++ b/webgl/gl.js @@ -2159,14 +2159,15 @@ class Triangles extends Geometry { super(); this.CenterIndex=CenterIndex; this.MaterialIndex=MaterialIndex; - this.Min=this.Bounds(Positions,Math.min); - this.Max=this.Bounds(Positions,Math.max); - this.controlpoints=Positions; - this.Normals=Normals; - this.Colors=Colors; - this.Indices=Indices; + this.controlpoints=window.Positions; + this.Normals=window.Normals; + this.Colors=window.Colors; + this.Indices=window.Indices; this.transparent=Materials[this.MaterialIndex].diffuse[3] < 1; + + this.Min=this.Bounds(this.controlpoints,Math.min); + this.Max=this.Bounds(this.controlpoints,Math.max); } Bounds(p,m) { From ac640f4c0f761a0c7d43e65a9de515c322195da2 Mon Sep 17 00:00:00 2001 From: John Bowman Date: Fri, 19 Jul 2024 09:40:42 -0700 Subject: [PATCH 32/51] Update asygl. --- base/webgl/asygl-1.02.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/base/webgl/asygl-1.02.js b/base/webgl/asygl-1.02.js index ce184c978..5b9fbfa64 100644 --- a/base/webgl/asygl-1.02.js +++ b/base/webgl/asygl-1.02.js @@ -36,4 +36,4 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.*/ -let vertex="\n#ifdef WEBGL2\n#define IN in\n#define OUT out\n#else\n#define IN attribute\n#define OUT varying\n#endif\n\nIN vec3 position;\n#ifdef WIDTH\nIN float width;\n#endif\n#ifdef NORMAL\nIN vec3 normal;\n#endif\n\nIN float materialIndex;\n\n#ifdef WEBGL2\nflat out int MaterialIndex;\n#ifdef COLOR\nOUT vec4 Color;\n#endif\n\n#else\nOUT vec4 diffuse;\nOUT vec3 specular;\nOUT float roughness,metallic,fresnel0;\nOUT vec4 emissive;\n\nstruct Material {\n vec4 diffuse,emissive,specular;\n vec4 parameters;\n};\n\nuniform Material Materials[Nmaterials];\n#endif\n\n#ifdef COLOR\nIN vec4 color;\n#endif\n\nuniform mat3 normMat;\nuniform mat4 viewMat;\nuniform mat4 projViewMat;\n\n#ifdef NORMAL\n#ifndef ORTHOGRAPHIC\nOUT vec3 ViewPosition;\n#endif\nOUT vec3 Normal;\n#endif\n\nvoid main(void)\n{\n vec4 v=vec4(position,1.0);\n gl_Position=projViewMat*v;\n\n#ifdef NORMAL\n#ifndef ORTHOGRAPHIC\n ViewPosition=(viewMat*v).xyz;\n#endif\n Normal=normalize(normal*normMat);\n#endif\n\n#ifdef WEBGL2\n MaterialIndex=int(materialIndex);\n#ifdef COLOR\n Color=color;\n#endif\n#else\n#ifdef NORMAL\n Material m;\n#ifdef TRANSPARENT\n m=Materials[int(abs(materialIndex))-1];\n emissive=m.emissive;\n if(materialIndex >= 0.0)\n diffuse=m.diffuse;\n else {\n diffuse=color;\n#if nlights == 0\n emissive += color;\n#endif\n }\n#else\n m=Materials[int(materialIndex)];\n emissive=m.emissive;\n#ifdef COLOR\n diffuse=color;\n#if nlights == 0\n emissive += color;\n#endif\n#else\n diffuse=m.diffuse;\n#endif // COLOR\n#endif // TRANSPARENT\n specular=m.specular.rgb;\n vec4 parameters=m.parameters;\n roughness=1.0-parameters[0];\n metallic=parameters[1];\n fresnel0=parameters[2];\n#else\n emissive=Materials[int(materialIndex)].emissive;\n#endif // NORMAL\n#endif // WEBGL2\n\n#ifdef WIDTH\n gl_PointSize=width;\n#endif\n}\n",fragment="\n#ifdef WEBGL2\n#define IN in\nout vec4 outValue;\n#define OUTVALUE outValue\n#else\n#define IN varying\n#define OUTVALUE gl_FragColor\n#endif\n\n#ifdef WEBGL2\nflat in int MaterialIndex;\n\nstruct Material {\n vec4 diffuse,emissive,specular;\n vec4 parameters;\n};\n\nuniform Material Materials[Nmaterials];\n\nvec4 diffuse;\nvec3 specular;\nfloat roughness,metallic,fresnel0;\nvec4 emissive;\n\n#ifdef COLOR\nin vec4 Color;\n#endif\n\n#else\nIN vec4 diffuse;\nIN vec3 specular;\nIN float roughness,metallic,fresnel0;\nIN vec4 emissive;\n#endif\n\n#ifdef NORMAL\n\n#ifndef ORTHOGRAPHIC\nIN vec3 ViewPosition;\n#endif\nIN vec3 Normal;\n\nvec3 normal;\n\nstruct Light {\n vec3 direction;\n vec3 color;\n};\n\nuniform Light Lights[Nlights];\n\n#ifdef USE_IBL\nuniform sampler2D reflBRDFSampler;\nuniform sampler2D diffuseSampler;\nuniform sampler2D reflImgSampler;\n\nconst float pi=acos(-1.0);\nconst float piInv=1.0/pi;\nconst float twopi=2.0*pi;\nconst float twopiInv=1.0/twopi;\n\n// (x,y,z) -> (r,theta,phi);\n// theta -> [0,pi]: colatitude\n// phi -> [-pi,pi]: longitude\nvec3 cart2sphere(vec3 cart)\n{\n float x=cart.x;\n float y=cart.z;\n float z=cart.y;\n\n float r=length(cart);\n float theta=r > 0.0 ? acos(z/r) : 0.0;\n float phi=atan(y,x);\n\n return vec3(r,theta,phi);\n}\n\nvec2 normalizedAngle(vec3 cartVec)\n{\n vec3 sphericalVec=cart2sphere(cartVec);\n sphericalVec.y=sphericalVec.y*piInv;\n sphericalVec.z=0.75-sphericalVec.z*twopiInv;\n return sphericalVec.zy;\n}\n\nvec3 IBLColor(vec3 viewDir)\n{\n vec3 IBLDiffuse=diffuse.rgb*texture(diffuseSampler,normalizedAngle(normal)).rgb;\n vec3 reflectVec=normalize(reflect(-viewDir,normal));\n vec2 reflCoord=normalizedAngle(reflectVec);\n vec3 IBLRefl=textureLod(reflImgSampler,reflCoord,roughness*ROUGHNESS_STEP_COUNT).rgb;\n vec2 IBLbrdf=texture(reflBRDFSampler,vec2(dot(normal,viewDir),roughness)).rg;\n float specularMultiplier=fresnel0*IBLbrdf.x+IBLbrdf.y;\n vec3 dielectric=IBLDiffuse+specularMultiplier*IBLRefl;\n vec3 metal=diffuse.rgb*IBLRefl;\n return mix(dielectric,metal,metallic);\n}\n#else\nfloat Roughness2;\nfloat NDF_TRG(vec3 h)\n{\n float ndoth=max(dot(normal,h),0.0);\n float alpha2=Roughness2*Roughness2;\n float denom=ndoth*ndoth*(alpha2-1.0)+1.0;\n return denom != 0.0 ? alpha2/(denom*denom) : 0.0;\n}\n\nfloat GGX_Geom(vec3 v)\n{\n float ndotv=max(dot(v,normal),0.0);\n float ap=1.0+Roughness2;\n float k=0.125*ap*ap;\n return ndotv/((ndotv*(1.0-k))+k);\n}\n\nfloat Geom(vec3 v, vec3 l)\n{\n return GGX_Geom(v)*GGX_Geom(l);\n}\n\nfloat Fresnel(vec3 h, vec3 v, float fresnel0)\n{\n float a=1.0-max(dot(h,v),0.0);\n float b=a*a;\n return fresnel0+(1.0-fresnel0)*b*b*a;\n}\n\n// physical based shading using UE4 model.\nvec3 BRDF(vec3 viewDirection, vec3 lightDirection)\n{\n vec3 lambertian=diffuse.rgb;\n vec3 h=normalize(lightDirection+viewDirection);\n\n float omegain=max(dot(viewDirection,normal),0.0);\n float omegaln=max(dot(lightDirection,normal),0.0);\n\n float D=NDF_TRG(h);\n float G=Geom(viewDirection,lightDirection);\n float F=Fresnel(h,viewDirection,fresnel0);\n\n float denom=4.0*omegain*omegaln;\n float rawReflectance=denom > 0.0 ? (D*G)/denom : 0.0;\n\n vec3 dielectric=mix(lambertian,rawReflectance*specular,F);\n vec3 metal=rawReflectance*diffuse.rgb;\n\n return mix(dielectric,metal,metallic);\n}\n#endif\n\n#endif\n\nvoid main(void)\n{\n#ifdef WEBGL2\n#ifdef NORMAL\n Material m;\n#ifdef TRANSPARENT\n m=Materials[abs(MaterialIndex)-1];\n emissive=m.emissive;\n if(MaterialIndex >= 0)\n diffuse=m.diffuse;\n else {\n diffuse=Color;\n#if nlights == 0\n emissive += Color;\n#endif\n }\n#else\n m=Materials[MaterialIndex];\n emissive=m.emissive;\n#ifdef COLOR\n diffuse=Color;\n#if nlights == 0\n emissive += Color;\n#endif\n#else\n diffuse=m.diffuse;\n#endif // COLOR\n#endif // TRANSPARENT\n specular=m.specular.rgb;\n vec4 parameters=m.parameters;\n roughness=1.0-parameters[0];\n metallic=parameters[1];\n fresnel0=parameters[2];\n#else\n emissive=Materials[MaterialIndex].emissive;\n#endif // NORMAL\n#endif // WEBGL2\n\n#if defined(NORMAL) && nlights > 0\n normal=normalize(Normal);\n normal=gl_FrontFacing ? normal : -normal;\n#ifdef ORTHOGRAPHIC\n vec3 viewDir=vec3(0.0,0.0,1.0);\n#else\n vec3 viewDir=-normalize(ViewPosition);\n#endif\n\nvec3 color;\n#ifdef USE_IBL\n color=IBLColor(viewDir);\n#else\n Roughness2=roughness*roughness;\n color=emissive.rgb;\n for(int i=0; i < nlights; ++i) {\n Light Li=Lights[i];\n vec3 L=Li.direction;\n float cosTheta=max(dot(normal,L),0.0);\n vec3 radiance=cosTheta*Li.color;\n color += BRDF(viewDir,L)*radiance;\n }\n#endif\n OUTVALUE=vec4(color,diffuse.a);\n#else\n OUTVALUE=emissive;\n#endif\n}\n";!function(t,e){if("object"==typeof exports&&"object"==typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var i=e();for(var n in i)("object"==typeof exports?exports:t)[n]=i[n]}}("undefined"!=typeof self?self:this,(function(){return function(t){var e={};function i(n){if(e[n])return e[n].exports;var r=e[n]={i:n,l:!1,exports:{}};return t[n].call(r.exports,r,r.exports,i),r.l=!0,r.exports}return i.m=t,i.c=e,i.d=function(t,e,n){i.o(t,e)||Object.defineProperty(t,e,{configurable:!1,enumerable:!0,get:n})},i.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return i.d(e,"a",e),e},i.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},i.p="",i(i.s=1)}([function(t,e,i){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.setMatrixArrayType=function(t){e.ARRAY_TYPE=t},e.toRadian=function(t){return t*r},e.equals=function(t,e){return Math.abs(t-e)<=n*Math.max(1,Math.abs(t),Math.abs(e))};var n=e.EPSILON=1e-6;e.ARRAY_TYPE="undefined"!=typeof Float32Array?Float32Array:Array,e.RANDOM=Math.random;var r=Math.PI/180},function(t,e,i){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.mat4=e.mat3=void 0;var n=s(i(2)),r=s(i(3));function s(t){if(t&&t.__esModule)return t;var e={};if(null!=t)for(var i in t)Object.prototype.hasOwnProperty.call(t,i)&&(e[i]=t[i]);return e.default=t,e}e.mat3=n,e.mat4=r},function(t,e,i){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.create=function(){var t=new n.ARRAY_TYPE(9);return t[0]=1,t[1]=0,t[2]=0,t[3]=0,t[4]=1,t[5]=0,t[6]=0,t[7]=0,t[8]=1,t},e.fromMat4=function(t,e){return t[0]=e[0],t[1]=e[1],t[2]=e[2],t[3]=e[4],t[4]=e[5],t[5]=e[6],t[6]=e[8],t[7]=e[9],t[8]=e[10],t},e.invert=function(t,e){var i=e[0],n=e[1],r=e[2],s=e[3],a=e[4],o=e[5],h=e[6],l=e[7],c=e[8],d=c*a-o*l,m=-c*s+o*h,f=l*s-a*h,u=i*d+n*m+r*f;if(!u)return null;return u=1/u,t[0]=d*u,t[1]=(-c*n+r*l)*u,t[2]=(o*n-r*a)*u,t[3]=m*u,t[4]=(c*i-r*h)*u,t[5]=(-o*i+r*s)*u,t[6]=f*u,t[7]=(-l*i+n*h)*u,t[8]=(a*i-n*s)*u,t};var n=function(t){if(t&&t.__esModule)return t;var e={};if(null!=t)for(var i in t)Object.prototype.hasOwnProperty.call(t,i)&&(e[i]=t[i]);return e.default=t,e}(i(0))},function(t,e,i){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.create=function(){var t=new n.ARRAY_TYPE(16);return t[0]=1,t[1]=0,t[2]=0,t[3]=0,t[4]=0,t[5]=1,t[6]=0,t[7]=0,t[8]=0,t[9]=0,t[10]=1,t[11]=0,t[12]=0,t[13]=0,t[14]=0,t[15]=1,t},e.identity=function(t){return t[0]=1,t[1]=0,t[2]=0,t[3]=0,t[4]=0,t[5]=1,t[6]=0,t[7]=0,t[8]=0,t[9]=0,t[10]=1,t[11]=0,t[12]=0,t[13]=0,t[14]=0,t[15]=1,t},e.invert=function(t,e){var i=e[0],n=e[1],r=e[2],s=e[3],a=e[4],o=e[5],h=e[6],l=e[7],c=e[8],d=e[9],m=e[10],f=e[11],u=e[12],p=e[13],v=e[14],x=e[15],g=i*o-n*a,w=i*h-r*a,M=i*l-s*a,b=n*h-r*o,R=n*l-s*o,T=r*l-s*h,y=c*p-d*u,A=c*v-m*u,E=c*x-f*u,I=d*v-m*p,L=d*x-f*p,N=m*x-f*v,O=g*N-w*L+M*I+b*E-R*A+T*y;if(!O)return null;return O=1/O,t[0]=(o*N-h*L+l*I)*O,t[1]=(r*L-n*N-s*I)*O,t[2]=(p*T-v*R+x*b)*O,t[3]=(m*R-d*T-f*b)*O,t[4]=(h*E-a*N-l*A)*O,t[5]=(i*N-r*E+s*A)*O,t[6]=(v*M-u*T-x*w)*O,t[7]=(c*T-m*M+f*w)*O,t[8]=(a*L-o*E+l*y)*O,t[9]=(n*E-i*L-s*y)*O,t[10]=(u*R-p*M+x*g)*O,t[11]=(d*M-c*R-f*g)*O,t[12]=(o*A-a*I-h*y)*O,t[13]=(i*I-n*A+r*y)*O,t[14]=(p*w-u*b-v*g)*O,t[15]=(c*b-d*w+m*g)*O,t},e.multiply=r,e.translate=function(t,e,i){var n=i[0],r=i[1],s=i[2],a=void 0,o=void 0,h=void 0,l=void 0,c=void 0,d=void 0,m=void 0,f=void 0,u=void 0,p=void 0,v=void 0,x=void 0;e===t?(t[12]=e[0]*n+e[4]*r+e[8]*s+e[12],t[13]=e[1]*n+e[5]*r+e[9]*s+e[13],t[14]=e[2]*n+e[6]*r+e[10]*s+e[14],t[15]=e[3]*n+e[7]*r+e[11]*s+e[15]):(a=e[0],o=e[1],h=e[2],l=e[3],c=e[4],d=e[5],m=e[6],f=e[7],u=e[8],p=e[9],v=e[10],x=e[11],t[0]=a,t[1]=o,t[2]=h,t[3]=l,t[4]=c,t[5]=d,t[6]=m,t[7]=f,t[8]=u,t[9]=p,t[10]=v,t[11]=x,t[12]=a*n+c*r+u*s+e[12],t[13]=o*n+d*r+p*s+e[13],t[14]=h*n+m*r+v*s+e[14],t[15]=l*n+f*r+x*s+e[15]);return t},e.rotate=function(t,e,i,r){var s,a,o,h,l,c,d,m,f,u,p,v,x,g,w,M,b,R,T,y,A,E,I,L,N=r[0],O=r[1],_=r[2],P=Math.sqrt(N*N+O*O+_*_);if(Math.abs(P)t.getUniformLocation(e,"Materials["+i+"]."+n);t.uniform4fv(n("diffuse"),new Float32Array(this.diffuse)),t.uniform4fv(n("emissive"),new Float32Array(this.emissive)),t.uniform4fv(n("specular"),new Float32Array(this.specular)),t.uniform4f(n("parameters"),this.shininess,this.metallic,this.fresnel0,0)}}let $,q,K,Z,Q,J,tt,et,it;class nt{constructor(t,e){this.direction=t,this.color=e}setUniform(e,i){let n=n=>t.getUniformLocation(e,"Lights["+i+"]."+n);t.uniform3fv(n("direction"),new Float32Array(this.direction)),t.uniform3fv(n("color"),new Float32Array(this.color))}}function rt(e=!1){let i=t.getParameter(t.MAX_VERTEX_UNIFORM_VECTORS);r=Math.floor((i-14)/4),m=Math.min(Math.max(m,c.length),r),pixelOpt=["WIDTH"],materialOpt=["NORMAL"],colorOpt=["NORMAL","COLOR"],transparentOpt=["NORMAL","COLOR","TRANSPARENT"],e&&(materialOpt.push("USE_IBL"),transparentOpt.push("USE_IBL")),ge=Nt(pixelOpt),we=Nt(materialOpt),Me=Nt(colorOpt),be=Nt(transparentOpt)}function st(){t.deleteProgram(be),t.deleteProgram(Me),t.deleteProgram(we),t.deleteProgram(ge)}function at(){let i=o.webgl2?window.top.document.asygl2[e]:window.top.document.asygl[e];i.gl=t,i.nlights=l.length,i.Nmaterials=m,i.maxMaterials=r,i.pixelShader=ge,i.materialShader=we,i.colorShader=Me,i.transparentShader=be}function ot(t,e){let i;return o.webgl2&&(i=t.getContext("webgl2",{alpha:e}),o.embedded&&!i)?(o.webgl2=!1,o.ibl=!1,ht(!1),null):(i||(o.webgl2=!1,o.ibl=!1,i=t.getContext("webgl",{alpha:e})),i||alert("Could not initialize WebGL"),i)}function ht(s=!0){if(o.ibl&&(o.webgl2=!0),e=o.background[3]<1,o.embedded){let a=window.top.document;if(s&&(n=o.canvas.getContext("2d")),i=o.webgl2?a.offscreen2:a.offscreen,i||(i=a.createElement("canvas"),o.webgl2?a.offscreen2=i:a.offscreen=i),o.webgl2?a.asygl2||(a.asygl2=Array(2)):a.asygl||(a.asygl=Array(2)),asygl=o.webgl2?a.asygl2:a.asygl,asygl[e]&&asygl[e].gl)!function(){let i=o.webgl2?window.top.document.asygl2[e]:window.top.document.asygl[e];t=i.gl,d=i.nlights,m=i.Nmaterials,r=i.maxMaterials,ge=i.pixelShader,we=i.materialShader,Me=i.colorShader,be=i.transparentShader}(),(l.length!=d||Math.min(c.length,r)>m)&&(rt(),at());else{if(rc=ot(i,e),!rc)return;t=rc,rt(),o.webgl2?a.asygl2[e]={}:a.asygl[e]={},at()}}else t=ot(o.canvas,e),rt();$=t.getExtension("OES_element_index_uint"),q=t.TRIANGLES,K=new mt(t.POINTS),Z=new mt(t.LINES),Q=new mt,J=new mt,tt=new mt,et=new mt}function lt(t,e,i,n=[]){let r=o.webgl2?"300 es":"100",s=Array(...n),a=[["nlights",0==V?l.length:0],["Nmaterials",m]],h=[["int","Nlights",Math.max(l.length,1)]];o.webgl2&&s.push("WEBGL2"),o.ibl&&a.push(["ROUGHNESS_STEP_COUNT",8..toFixed(2)]),o.orthographic&&s.push("ORTHOGRAPHIC"),macros_str=a.map(t=>`#define ${t[0]} ${t[1]}`).join("\n"),define_str=s.map(t=>"#define "+t).join("\n"),const_str=h.map(t=>`const ${t[0]} ${t[1]}=${t[2]};`).join("\n"),ext_str=[].map(t=>`#extension ${t}: enable`).join("\n"),shaderSrc=`#version ${r}\n${ext_str}\n${define_str}\n${const_str}\n${macros_str}\n\n\n#ifdef GL_FRAGMENT_PRECISION_HIGH\nprecision highp float;\n#else\nprecision mediump float;\n#endif\n \n${e}\n `;let c=t.createShader(i);return t.shaderSource(c,shaderSrc),t.compileShader(c),t.getShaderParameter(c,t.COMPILE_STATUS)?c:(alert(t.getShaderInfoLog(c)),null)}function ct(e,i,n,r=t.ARRAY_BUFFER){return e.length>0&&(0==i&&(i=t.createBuffer(),n=!0),t.bindBuffer(r,i),n&&t.bufferData(r,e,t.STATIC_DRAW)),i}function dt(e,i,n=e.indices){if(0==e.indices.length)return;let r=i!=ge;!function(e,i){let n=i==ge;t.useProgram(i),t.enableVertexAttribArray(yt),n&&t.enableVertexAttribArray(Lt);let r=!n&&l.length>0;r&&t.enableVertexAttribArray(At);t.enableVertexAttribArray(Et),i.projViewMatUniform=t.getUniformLocation(i,"projViewMat"),i.viewMatUniform=t.getUniformLocation(i,"viewMat"),i.normMatUniform=t.getUniformLocation(i,"normMat"),(i==Me||i==be)&&t.enableVertexAttribArray(It);if(r)for(let t=0;t0&&t.vertexAttribPointer(At,3,t.FLOAT,!1,24,12):t.vertexAttribPointer(Lt,1,t.FLOAT,!1,16,12),e.materialsBuffer=ct(new Int16Array(e.materialIndices),e.materialsBuffer,s),t.vertexAttribPointer(Et,1,t.SHORT,!1,2,0),i!=Me&&i!=be||(e.colorsBuffer=ct(new Float32Array(e.colors),e.colorsBuffer,s),t.vertexAttribPointer(It,4,t.FLOAT,!0,0,0)),e.indicesBuffer=ct($?new Uint32Array(n):new Uint16Array(n),e.indicesBuffer,s,t.ELEMENT_ARRAY_BUFFER),e.rendered=!0,t.drawElements(r?V?t.LINES:e.type:t.POINTS,n.length,$?t.UNSIGNED_INT:t.UNSIGNED_SHORT,0)}class mt{constructor(t){this.type=t||q,this.verticesBuffer=0,this.materialsBuffer=0,this.colorsBuffer=0,this.indicesBuffer=0,this.rendered=!1,this.partial=!1,this.clear()}clear(){this.vertices=[],this.materialIndices=[],this.colors=[],this.indices=[],this.nvertices=0,this.materials=[],this.materialTable=[]}vertex(t,e){return this.vertices.push(t[0]),this.vertices.push(t[1]),this.vertices.push(t[2]),this.vertices.push(e[0]),this.vertices.push(e[1]),this.vertices.push(e[2]),this.materialIndices.push(it),this.nvertices++}Vertex(t,e,i=[0,0,0,0]){return this.vertices.push(t[0]),this.vertices.push(t[1]),this.vertices.push(t[2]),this.vertices.push(e[0]),this.vertices.push(e[1]),this.vertices.push(e[2]),this.materialIndices.push(it),this.colors.push(i[0]),this.colors.push(i[1]),this.colors.push(i[2]),this.colors.push(i[3]),this.nvertices++}vertex0(t,e){return this.vertices.push(t[0]),this.vertices.push(t[1]),this.vertices.push(t[2]),this.vertices.push(e),this.materialIndices.push(it),this.nvertices++}iVertex(t,e,i,n,r=[0,0,0,0]){let s=6*t;this.vertices[s]=e[0],this.vertices[s+1]=e[1],this.vertices[s+2]=e[2],this.vertices[s+3]=i[0],this.vertices[s+4]=i[1],this.vertices[s+5]=i[2],this.materialIndices[t]=it;let a=4*t;this.colors[a]=r[0],this.colors[a+1]=r[1],this.colors[a+2]=r[2],this.colors[a+3]=r[3],n&&this.indices.push(t)}append(t){ft(this.vertices,t.vertices),ft(this.materialIndices,t.materialIndices),ft(this.colors,t.colors),function(t,e,i){let n=t.length,r=e.length;t.length+=e.length;for(let s=0;sthis.X&&(this.X=h),lthis.Y&&(this.Y=l)}return(this.X<-1.01||this.x>1.01||this.Y<-1.01||this.y>1.01)&&(this.Onscreen=!1,!0)}T(t){let e=this.c[0],i=this.c[1],n=this.c[2],r=t[0]-e,s=t[1]-i,a=t[2]-n;return[r*I[0]+s*I[3]+a*I[6]+e,r*I[1]+s*I[4]+a*I[7]+i,r*I[2]+s*I[5]+a*I[8]+n]}Tcorners(t,e){return[this.T(t),this.T([t[0],t[1],e[2]]),this.T([t[0],e[1],t[2]]),this.T([t[0],e[1],e[2]]),this.T([e[0],t[1],t[2]]),this.T([e[0],t[1],e[2]]),this.T([e[0],e[1],t[2]]),this.T(e)]}setMaterial(t,e){null==t.materialTable[this.MaterialIndex]&&(t.materials.length>=m&&(t.partial=!0,e()),t.materialTable[this.MaterialIndex]=t.materials.length,t.materials.push(c[this.MaterialIndex])),it=t.materialTable[this.MaterialIndex]}render(){let t;var e,i;if(this.setMaterialIndex(),0==this.CenterIndex?(e=this.Min,i=this.Max,t=[e,[e[0],e[1],i[2]],[e[0],i[1],e[2]],[e[0],i[1],i[2]],[i[0],e[1],e[2]],[i[0],e[1],i[2]],[i[0],i[1],e[2]],i]):(this.c=o.Centers[this.CenterIndex-1],t=this.Tcorners(this.Min,this.Max)),this.offscreen(t))return this.data.clear(),void this.notRendered();let n,r=this.controlpoints;if(0==this.CenterIndex){if(!U&&this.Onscreen)return void this.append();n=r}else{let t=r.length;n=Array(t);for(let e=0;e=-n||0==r)return i;--r,n*=2;let s=new Ot(t[0],t[1],t[2],t[3]),a=new Ot(t[4],t[5],t[6],t[7]),o=new Ot(t[8],t[9],t[10],t[11]),h=new Ot(t[12],t[13],t[14],t[15]),l=new Ot(t[0],t[4],t[8],t[12]),c=new Ot(s.m0,a.m0,o.m0,h.m0),d=new Ot(s.m3,a.m3,o.m3,h.m3),m=new Ot(s.m5,a.m5,o.m5,h.m5),f=new Ot(s.m4,a.m4,o.m4,h.m4),u=new Ot(s.m2,a.m2,o.m2,h.m2),p=new Ot(t[3],t[7],t[11],t[15]),v=[t[0],s.m0,s.m3,s.m5,l.m0,c.m0,d.m0,m.m0,l.m3,c.m3,d.m3,m.m3,l.m5,c.m5,d.m5,m.m5];i=this.bound(v,e,i,n,r);let x=[l.m5,c.m5,d.m5,m.m5,l.m4,c.m4,d.m4,m.m4,l.m2,c.m2,d.m2,m.m2,t[12],h.m0,h.m3,h.m5];i=this.bound(x,e,i,n,r);let g=[m.m5,f.m5,u.m5,p.m5,m.m4,f.m4,u.m4,p.m4,m.m2,f.m2,u.m2,p.m2,h.m5,h.m4,h.m2,t[15]];i=this.bound(g,e,i,n,r);let w=[s.m5,s.m4,s.m2,t[3],m.m0,f.m0,u.m0,p.m0,m.m3,f.m3,u.m3,p.m3,m.m5,f.m5,u.m5,p.m5];return this.bound(w,e,i,n,r)}cornerboundtri(t,e){let i=e(t[0],t[6]);return e(i,t[9])}controlboundtri(t,e){let i=e(t[1],t[2]);return i=e(i,t[3]),i=e(i,t[4]),i=e(i,t[5]),i=e(i,t[7]),e(i,t[8])}boundtri(t,e,i,n,r){if(i=e(i,this.cornerboundtri(t,e)),e(-1,1)*(i-this.controlboundtri(t,e))>=-n||0==r)return i;--r,n*=2;let s=new Pt(t),a=[s.l003,s.l102,s.l012,s.l201,s.l111,s.l021,s.l300,s.l210,s.l120,s.l030];i=this.boundtri(a,e,i,n,r);let o=[s.l300,s.r102,s.r012,s.r201,s.r111,s.r021,s.r300,s.r210,s.r120,s.r030];i=this.boundtri(o,e,i,n,r);let h=[s.l030,s.u102,s.u012,s.u201,s.u111,s.u021,s.r030,s.u210,s.u120,s.u030];i=this.boundtri(h,e,i,n,r);let l=[s.r030,s.u201,s.r021,s.u102,s.c111,s.r012,s.l030,s.l120,s.l210,s.l300];return this.boundtri(l,e,i,n,r)}Bounds(t,e,i){let n=Array(3),r=t.length,s=Array(r);for(let a=0;a<3;++a){for(let e=0;e0&&this.append()}append(){this.transparent?tt.append(this.data):this.color?J.append(this.data):Q.append(this.data)}notRendered(){this.transparent?tt.rendered=!1:this.color?J.rendered=!1:Q.rendered=!1}Render(t,e,i,n,r,s,a,o,h,l,c,d,m,f,u,p,v){let x=this.Distance(t);if(x[0]0&&this.append()}Render3(t,e,i,n,r,s,a,o,h,l,c,d,m){if(this.Distance3(t)this.epsilon?r:(r=Ft(t,e,i),Ut(r)>this.epsilon?r:zt(t,e,i,n))}sumdifferential(t,e,i,n,r,s,a){let o=this.differential(t,e,i,n),h=this.differential(t,r,s,a);return[o[0]+h[0],o[1]+h[1],o[2]+h[2]]}normal(t,e,i,n,r,s,a){let o=3*(r[0]-n[0]),h=3*(r[1]-n[1]),l=3*(r[2]-n[2]),c=3*(i[0]-n[0]),d=3*(i[1]-n[1]),m=3*(i[2]-n[2]),f=[h*m-l*d,l*c-o*m,o*d-h*c];if(Ut(f)>this.epsilon)return f;let u=[c,d,m],p=[o,h,l],v=Ft(n,i,e),x=Ft(n,r,s),g=Bt(x,u),w=Bt(p,v);if(f=[g[0]+w[0],g[1]+w[1],g[2]+w[2]],Ut(f)>this.epsilon)return f;let M=zt(n,i,e,t),b=zt(n,r,s,a);g=Bt(p,M),w=Bt(b,u);let R=Bt(x,v);return f=[g[0]+w[0]+R[0],g[1]+w[1]+R[1],g[2]+w[2]+R[2]],Ut(f)>this.epsilon?f:(g=Bt(b,v),w=Bt(x,M),f=[g[0]+w[0],g[1]+w[1],g[2]+w[2]],Ut(f)>this.epsilon?f:Bt(b,M))}}function xt(t){return 0<=t&&t<=1}class gt{constructor(t,e,i){const n=1e3*Number.EPSILON,r=n*n;if(Math.abs(t)<=n*Math.abs(e)+r*Math.abs(i))Math.abs(e)>n*Math.abs(i)?(this.roots=1,this.t1=-i/e):0==i?(this.roots=1,this.t1=0):this.roots=0;else{let r=.5*e/t,s=e*r;if(Math.abs(s)<=n*Math.abs(i)){let e=-i/t;e>=0?(this.roots=2,this.t2=Math.sqrt(e),this.t1=-this.t2):this.roots=0}else{let t=-2*i/s;if(t>-1){this.roots=2;let e=r*function(t){return t/(Math.sqrt(1+t)+1)}(t),i=-e-2*r;i<=e?(this.t1=i,this.t2=e):(this.t1=e,this.t2=i)}else-1==t?(this.roots=1,this.t1=this.t2=-r):this.roots=0}}}}class wt extends ut{constructor(t,e,i,n,r){if(super(),this.controlpoints=t,this.CenterIndex=e,this.MaterialIndex=i,n&&r)this.Min=n,this.Max=r;else{let t=this.Bounds(this.controlpoints);this.Min=t[0],this.Max=t[1]}}Bounds(t){let e=Array(3),i=Array(3),n=t.length,r=Array(n);for(let h=0;h<3;++h){for(let e=0;e0&&this.append()}append(){Z.append(this.data)}notRendered(){Z.rendered=!1}Render(t,e,i){let n=t[0],r=t[1],s=t[2],a=t[3];if(Ht(n,r,s,a)0?-1-it:1+it;for(let e=0,i=this.Indices.length;e1?i[1]:n;if(h&&0!=h.length||(h=n),this.Colors.length>0){let t=i.length>2?i[2]:n;t&&0!=t.length||(t=n);let e=this.Colors[t[0]],l=this.Colors[t[1]],c=this.Colors[t[2]];this.transparent|=e[3]+l[3]+c[3]<3,0==V?(this.data.iVertex(n[0],r,this.Normals[h[0]],o,e),this.data.iVertex(n[1],s,this.Normals[h[1]],o,l),this.data.iVertex(n[2],a,this.Normals[h[2]],o,c)):(this.data.iVertex(n[0],r,this.Normals[h[0]],o,e),this.data.iVertex(n[1],s,this.Normals[h[1]],o,l),this.data.iVertex(n[1],s,this.Normals[h[1]],o,l),this.data.iVertex(n[2],a,this.Normals[h[2]],o,c),this.data.iVertex(n[2],a,this.Normals[h[2]],o,c),this.data.iVertex(n[0],r,this.Normals[h[0]],o,e))}else 0==V?(this.data.iVertex(n[0],r,this.Normals[h[0]],o),this.data.iVertex(n[1],s,this.Normals[h[1]],o),this.data.iVertex(n[2],a,this.Normals[h[2]],o)):(this.data.iVertex(n[0],r,this.Normals[h[0]],o),this.data.iVertex(n[1],s,this.Normals[h[1]],o),this.data.iVertex(n[1],s,this.Normals[h[1]],o),this.data.iVertex(n[2],a,this.Normals[h[2]],o),this.data.iVertex(n[2],a,this.Normals[h[2]],o),this.data.iVertex(n[0],r,this.Normals[h[0]],o))}this.data.nvertices=t.length,this.data.indices.length>0&&this.append()}append(){this.transparent?tt.append(this.data):et.append(this.data)}notRendered(){this.transparent?tt.rendered=!1:et.rendered=!1}}function Rt(){M=-Math.tan(.5*o.angleOfView)*o.maxBound[2],_.x=_.y=0,_.z=.5*(o.minBound[2]+o.maxBound[2]),x=v=o.zoom0,S.zmin=o.minBound[2],S.zmax=o.maxBound[2],P.x=P.y=0,_e(),U=!0,Oe()}function Tt(){mat4.identity(T),Rt(),window.top.asyWebApplication&&window.top.asyWebApplication.setProjection(""),window.parent.asyProjection=!1}let yt=0,At=1,Et=2,It=3,Lt=4;function Nt(e=[]){let i=lt(t,vertex,t.VERTEX_SHADER,e),n=lt(t,fragment,t.FRAGMENT_SHADER,e),r=t.createProgram();return t.attachShader(r,i),t.attachShader(r,n),t.bindAttribLocation(r,yt,"position"),t.bindAttribLocation(r,At,"normal"),t.bindAttribLocation(r,Et,"materialIndex"),t.bindAttribLocation(r,It,"color"),t.bindAttribLocation(r,Lt,"width"),t.linkProgram(r),t.getProgramParameter(r,t.LINK_STATUS)||alert("Could not initialize shaders"),r}class Ot{constructor(t,e,i,n){this.m0=.5*(t+e);let r=.5*(e+i);this.m2=.5*(i+n),this.m3=.5*(this.m0+r),this.m4=.5*(r+this.m2),this.m5=.5*(this.m3+this.m4)}}class _t{constructor(t,e,i,n){this.m0=[.5*(t[0]+e[0]),.5*(t[1]+e[1]),.5*(t[2]+e[2])];let r=.5*(e[0]+i[0]),s=.5*(e[1]+i[1]),a=.5*(e[2]+i[2]);this.m2=[.5*(i[0]+n[0]),.5*(i[1]+n[1]),.5*(i[2]+n[2])],this.m3=[.5*(this.m0[0]+r),.5*(this.m0[1]+s),.5*(this.m0[2]+a)],this.m4=[.5*(r+this.m2[0]),.5*(s+this.m2[1]),.5*(a+this.m2[2])],this.m5=[.5*(this.m3[0]+this.m4[0]),.5*(this.m3[1]+this.m4[1]),.5*(this.m3[2]+this.m4[2])]}}class Pt{constructor(t){this.l003=t[0];let e=t[1],i=t[2],n=t[3],r=t[4],s=t[5];this.r300=t[6];let a=t[7],o=t[8];this.u030=t[9],this.u021=.5*(this.u030+s),this.u120=.5*(this.u030+o);let h=.5*(s+i),l=.5*(o+r),c=.5*(o+a),d=.5*(i+r);this.l012=.5*(i+this.l003);let m=.5*(r+n);this.r210=.5*(a+this.r300),this.l102=.5*(this.l003+e);let f=.5*(e+n);this.r201=.5*(n+this.r300),this.u012=.5*(this.u021+h),this.u210=.5*(this.u120+c),this.l021=.5*(h+this.l012);let u=.5*l+.25*(r+e);this.r120=.5*(c+this.r210);let p=.5*d+.25*(r+a),v=.25*(s+r)+.5*m;this.l201=.5*(this.l102+f),this.r102=.5*(f+this.r201),this.l210=.5*(p+this.l201),this.r012=.5*(p+this.r102),this.l300=.5*(this.l201+this.r102),this.r021=.5*(v+this.r120),this.u201=.5*(this.u210+v),this.r030=.5*(this.u210+this.r120),this.u102=.5*(this.u012+u),this.l120=.5*(this.l021+u),this.l030=.5*(this.u012+this.l021),this.l111=.5*(d+this.l102),this.r111=.5*(m+this.r210),this.u111=.5*(this.u021+l),this.c111=.25*(h+c+f+r)}}function St(t){let e=1/(Math.sqrt(t[0]*t[0]+t[1]*t[1]+t[2]*t[2])||1);return[t[0]*e,t[1]*e,t[2]*e]}function Ut(t){return t[0]*t[0]+t[1]*t[1]+t[2]*t[2]}function Vt(t,e){return t[0]*e[0]+t[1]*e[1]+t[2]*e[2]}function Bt(t,e){return[t[1]*e[2]-t[2]*e[1],t[2]*e[0]-t[0]*e[2],t[0]*e[1]-t[1]*e[0]]}function Dt(t,e,i,n,r){let s=1-r,a=s*s;return a*s*t+r*(3*(a*e+r*s*i)+r*r*n)}function Ct(t,e){return[e[0]-t[0],e[1]-t[1],e[2]-t[2]]}function Ft(t,e,i){return[3*(t[0]+i[0])-6*e[0],3*(t[1]+i[1])-6*e[1],3*(t[2]+i[2])-6*e[2]]}function zt(t,e,i,n){return[n[0]-t[0]+3*(e[0]-i[0]),n[1]-t[1]+3*(e[1]-i[1]),n[2]-t[2]+3*(e[2]-i[2])]}function Ht(t,e,i,n){let r=[1/3*(n[0]-t[0]),1/3*(n[1]-t[1]),1/3*(n[2]-t[2])];return Math.max(Ut([e[0]-r[0]-t[0],e[1]-r[1]-t[1],e[2]-r[2]-t[2]]),Ut([n[0]-r[0]-i[0],n[1]-r[1]-i[1],n[2]-r[2]-i[2]]))}function Xt(t,e,i,n){let r=[e[0]-t[0],e[1]-t[1],e[2]-t[2]],s=[n[0]-i[0],n[1]-i[1],n[2]-i[2]];return Math.max(Ut(Bt(r,St(s))),Ut(Bt(s,St(r))))/9}function Gt(t){return[Math.min(t[0][0],t[1][0],t[2][0],t[3][0],t[4][0],t[5][0],t[6][0],t[7][0]),Math.min(t[0][1],t[1][1],t[2][1],t[3][1],t[4][1],t[5][1],t[6][1],t[7][1]),Math.min(t[0][2],t[1][2],t[2][2],t[3][2],t[4][2],t[5][2],t[6][2],t[7][2])]}function Wt(t){return[Math.max(t[0][0],t[1][0],t[2][0],t[3][0],t[4][0],t[5][0],t[6][0],t[7][0]),Math.max(t[0][1],t[1][1],t[2][1],t[3][1],t[4][1],t[5][1],t[6][1],t[7][1]),Math.max(t[0][2],t[1][2],t[2][2],t[3][2],t[4][2],t[5][2],t[6][2],t[7][2])]}function jt(t){oe||he(),B=!0,D=t.clientX,C=t.clientY}let kt,Yt,$t=!1;function qt(t){return Math.hypot(t[0].pageX-t[1].pageX,t[0].pageY-t[1].pageY)}function Kt(t){t.preventDefault(),oe||he();let e=t.targetTouches;pe=ve=$t=!1,ue||(1!=e.length||B||(Yt=(new Date).getTime(),touchId=e[0].identifier,D=e[0].pageX,C=e[0].pageY),2!=e.length||B||(touchId=e[0].identifier,kt=qt(e),$t=!0))}function Zt(t){B=!1}function Qt(t,e,i,n,r){if(t==i&&e==n)return;let[s,a]=function(t,e){let i=re(t),n=re(e),r=Vt(i,n);return[r>1?0:r<-1?f:Math.acos(r),St(Bt(i,n))]}([t,-e],[i,-n]);mat4.fromRotation(O,2*r*R*s/v,a),mat4.multiply(T,O,T)}function Jt(t,e,i,n){let r=1/v;P.x+=(i-t)*r*s,P.y-=(n-e)*r*a}function te(t,e,i,n){o.orthographic?Jt(t,e,i,n):(_.x+=(i-t)*(S.xmax-S.xmin),_.y-=(n-e)*(S.ymax-S.ymin))}function ee(){var t,e;t=A,e=T,mat4.fromTranslation(O,[_.x,_.y,_.z]),mat4.invert(N,O),mat4.multiply(t,e,N),mat4.multiply(t,O,t),mat4.translate(A,A,[_.x,_.y,0]),mat3.fromMat4(L,A),mat3.invert(I,L),mat4.multiply(E,y,A)}function ie(){let t=Math.sqrt(Number.MAX_VALUE),e=1/t;v<=e&&(v=e),v>=t&&(v=t),(1.5*v1.5*x)&&(U=!0,x=v)}function ne(t){let e=o.zoomStep*a*t;const i=Math.log(.1*Number.MAX_VALUE)/Math.log(o.zoomFactor);Math.abs(e)1&&(denom=1/n,e*=denom,i*=denom),[e,i,Math.sqrt(Math.max(1-i*i-e*e,0))]}function se(t,e,i,n){ne(e-n)}function ae(t,e,i,n=1){let r;switch(i){case 1:r=Qt;break;case 2:r=Jt;break;case 3:r=se;break;case 4:r=te;break;default:r=(t,e,i,n)=>{}}r((D-s)/s,(C-a)/a,(t-s)/s,(e-a)/a,n),D=t,C=e,_e(),Oe()}let oe=0;function he(){oe=1,o.canvas.addEventListener("wheel",me,!1)}function le(){let t,e,i;[t,e,i]=function(){let t=Array(3),e=Array(3),i=Array(3),n=_.x,r=_.y,s=.5*(S.zmin+S.zmax);for(let a=0;a<3;++a){let h=0,l=0,c=0,d=4*a;for(let t=0;t<4;++t){let e=4*t,i=T[e],a=T[e+1],m=T[e+2],f=T[e+3],u=o.Transform[d+t];h+=u*(f-n*i-r*a-s*m),c+=u*a,l+=u*(f-n*i-r*a)}t[a]=h,e[a]=c,i[a]=l}return[t,e,i]}();let n=o.orthographic?" orthographic(":" perspective(",r="".padStart(n.length),s="currentprojection=\n"+n+"camera=("+t+"),\n"+r+"up=("+e+"),\n"+r+"target=("+i+"),\n"+r+"zoom="+v*o.initialZoom/o.zoom0;return o.orthographic||(s+=",\n"+r+"angle="+2*Math.atan(Math.tan(.5*o.angleOfView)/v)/u),0==g&&0==w||(s+=",\n"+r+"viewportshift=("+g+","+w+")"),o.orthographic||(s+=",\n"+r+"autoadjust=false"),s+=");\n",window.parent.asyProjection=!0,s}function ce(t){if(oe||he(),o.embedded&&oe&&27==t.keyCode)return oe=0,void o.canvas.removeEventListener("wheel",me,!1);let e=[];switch(t.key){case"x":e=[1,0,0];break;case"y":e=[0,1,0];break;case"z":e=[0,0,1];break;case"h":Tt();break;case"m":++V,3==V&&(V=0),2!=V&&(o.embedded||st(),rt(o.ibl)),U=!0,Oe();break;case"+":case"=":case">":v*=o.zoomFactor,de();break;case"-":case"_":case"<":v/=o.zoomFactor,de();break;case"c":window.top.asyWebApplication||prompt("Ctrl+c Enter to copy currentprojection to clipboard; then append to asy file:",le())}e.length>0&&(mat4.rotate(T,T,.1,e),ee(),Oe())}function de(){ie(),_e(),Oe()}function me(t){t.preventDefault(),t.deltaY<0?v*=o.zoomFactor:v/=o.zoomFactor,de()}function fe(t){if(!B)return;let e,i=t.clientX,n=t.clientY;e=t.getModifierState("Control")?2:t.getModifierState("Shift")?3:t.getModifierState("Alt")?4:1,ae(i,n,e)}let ue=!1,pe=!1,ve=!1;function xe(t){if(t.preventDefault(),ue)return;let e=t.targetTouches;if(!$t&&1==e.length&&touchId==e[0].identifier){let t=e[0].pageX,i=e[0].pageY,n=t-D,r=i-C,s=n*n+r*r<=o.shiftHoldDistance*o.shiftHoldDistance;if(s&&!pe&&!ve&&(new Date).getTime()-Yt>o.shiftWaitTime&&(navigator.vibrate&&window.navigator.vibrate(o.vibrateTime),pe=!0),pe)ae(t,i,2);else if(!s){ve=!0,ae(e[0].pageX,e[0].pageY,1,.5)}}if($t&&!pe&&2==e.length&&touchId==e[0].identifier){let t=qt(e),i=t-kt;ue=!0,i*=o.zoomPinchFactor,i>o.zoomPinchCap&&(i=o.zoomPinchCap),i<-o.zoomPinchCap&&(i=-o.zoomPinchCap),ne(i/b),kt=t,pe=ve=ue=!1,_e(),Oe()}}let ge,we,Me,be,Re=[];function Te(){dt(K,ge),K.clear()}function ye(){dt(Z,we),Z.clear()}function Ae(){dt(Q,we),Q.clear()}function Ee(){dt(J,Me),J.clear()}function Ie(){dt(et,be),et.rendered=!1,et.clear()}function Le(){let e=tt.indices;if(V>0)return dt(tt,be,e),void tt.clear();if(e.length>0){!function(t){let e=A[2],i=A[6],n=A[10];Re.length=t.length;for(let r=0;re);n.sort((function(t,i){let n=3*t;Ia=e[n],Ib=e[n+1],Ic=e[n+2];let r=3*i;return IA=e[r],IB=e[r+1],IC=e[r+2],Re[Ia]+Re[Ib]+Re[Ic]void 0&&(t=void 0),e>void 0&&(e=void 0),P.x*=t/o.canvasWidth,P.y*=e/o.canvasHeight,o.canvasWidth=t,o.canvasHeight=e,o.embedded&&(o.canvas.width=i.width=o.canvasWidth,o.canvas.height=i.height=o.canvasHeight),b=Math.hypot(o.canvasWidth,o.canvasHeight),s=.5*o.canvas.width,a=.5*o.canvas.height,R=1+8*Math.hypot(o.viewportMargin[0],o.viewportMargin[1])/b,Pe(),_e(),U=!0}function Ue(){if(o.zoom0=o.initialZoom,window.top.asyWebApplication&&""==window.top.asyWebApplication.getProjection()&&(window.parent.asyProjection=!1),o.absolute&&!o.embedded)o.canvasWidth=o.canvasWidth0*window.devicePixelRatio,o.canvasHeight=o.canvasHeight0*window.devicePixelRatio;else{let t=o.canvasWidth0/o.canvasHeight0;o.canvasWidth=Math.max(window.innerWidth-10,10),o.canvasHeight=Math.max(window.innerHeight-10,10),!o.orthographic&&!window.parent.asyProjection&&o.canvasWidthe%4!=3)}function ze(e,i,n=t.RGB16F){let r=e.width(),s=e.height(),a=t.createTexture();return t.activeTexture(t.TEXTURE0+i),t.bindTexture(t.TEXTURE_2D,a),t.pixelStorei(t.UNPACK_ALIGNMENT,1),t.texParameteri(t.TEXTURE_2D,t.TEXTURE_MIN_FILTER,t.LINEAR),t.texParameteri(t.TEXTURE_2D,t.TEXTURE_MAG_FILTER,t.LINEAR),t.texImage2D(t.TEXTURE_2D,0,n,r,s,0,t.RGB,t.FLOAT,Fe(e)),a}window.webGLStart=function(){o.canvas=document.getElementById("Asymptote"),o.embedded=window.top.document!=document,ht(),t.enable(t.BLEND),t.blendFunc(t.SRC_ALPHA,t.ONE_MINUS_SRC_ALPHA),t.enable(t.DEPTH_TEST),t.enable(t.SCISSOR_TEST),o.canvas.onmousedown=jt,document.onmouseup=Zt,document.onmousemove=fe,o.canvas.onkeydown=ce,o.embedded||he(),o.canvas.addEventListener("touchstart",Kt,!1),o.canvas.addEventListener("touchend",Zt,!1),o.canvas.addEventListener("touchcancel",Zt,!1),o.canvas.addEventListener("touchleave",Zt,!1),o.canvas.addEventListener("touchmove",xe,!1),document.addEventListener("keydown",ce,!1),o.canvasWidth0=o.canvasWidth,o.canvasHeight0=o.canvasHeight,mat4.identity(T),0!=window.innerWidth&&0!=window.innerHeight&&Ue(),window.addEventListener("resize",Ue,!1),o.ibl&&async function(){let e=o.imageURL+o.image+"/";function i(t){return new Promise(e=>setTimeout(e,t))}for(;!Module.EXRLoader;)await i(0);promises=[Ce(o.imageURL+"refl.exr").then(t=>{let e=new Module.EXRLoader(t);j=ze(e,0)}),Ce(e+"diffuse.exr").then(t=>{let e=new Module.EXRLoader(t);W=ze(e,1)})],refl_promise=[],refl_promise.push(Ce(e+"refl0.exr"));for(let t=1;t<=8;++t)refl_promise.push(Ce(e+"refl"+t+"w.exr"));finished_promise=Promise.all(refl_promise).then(e=>{let i=t.createTexture();t.activeTexture(t.TEXTURE0+2),t.pixelStorei(t.UNPACK_ALIGNMENT,1),t.bindTexture(t.TEXTURE_2D,i),t.texParameteri(t.TEXTURE_2D,t.TEXTURE_MAX_LEVEL,e.length-1),t.texParameteri(t.TEXTURE_2D,t.TEXTURE_MIN_FILTER,t.LINEAR_MIPMAP_LINEAR),t.texParameteri(t.TEXTURE_2D,t.TEXTURE_MAG_FILTER,t.LINEAR),t.texParameterf(t.TEXTURE_2D,t.TEXTURE_MIN_LOD,0),t.texParameterf(t.TEXTURE_2D,t.TEXTURE_MAX_LOD,8);for(let i=0;ia?St(r):(r=[2*i[0]-e[0]-n[0],2*i[1]-e[1]-n[1],2*i[2]-e[2]-n[2]],Ut(r)>a?St(r):[n[0]-t[0]+3*(e[0]-i[0]),n[1]-t[1]+3*(e[1]-i[1]),n[2]-t[2]+3*(e[2]-i[2])])}let s=[n[0]-t[0]+3*(e[0]-i[0]),n[1]-t[1]+3*(e[1]-i[1]),n[2]-t[2]+3*(e[2]-i[2])],o=[2*(t[0]+i[0])-4*e[0],2*(t[1]+i[1])-4*e[1],2*(t[2]+i[2])-4*e[2]],h=[e[0]-t[0],e[1]-t[1],e[2]-t[2]],l=r*r,c=[s[0]*l+o[0]*r+h[0],s[1]*l+o[1]*r+h[1],s[2]*l+o[2]*r+h[2]];return Ut(c)>a?St(c):(l=2*r,c=[s[0]*l+o[0],s[1]*l+o[1],s[2]*l+o[2]],Ut(c)>a?St(c):St(s))}let h=Array(r.length),l=[e[0]-t[0],e[1]-t[1],e[2]-t[2]];Ut(l)i?St(e):(e=Bt(t,[0,0,1]),Ut(e)>i?St(e):[1,0,0])}(l);h[0]=new s(t,c,l);for(let a=1;at.getUniformLocation(e,"Materials["+i+"]."+n);t.uniform4fv(n("diffuse"),new Float32Array(this.diffuse)),t.uniform4fv(n("emissive"),new Float32Array(this.emissive)),t.uniform4fv(n("specular"),new Float32Array(this.specular)),t.uniform4f(n("parameters"),this.shininess,this.metallic,this.fresnel0,0)}}let $,q,K,Z,Q,J,tt,et,it;class nt{constructor(t,e){this.direction=t,this.color=e}setUniform(e,i){let n=n=>t.getUniformLocation(e,"Lights["+i+"]."+n);t.uniform3fv(n("direction"),new Float32Array(this.direction)),t.uniform3fv(n("color"),new Float32Array(this.color))}}function rt(e=!1){let i=t.getParameter(t.MAX_VERTEX_UNIFORM_VECTORS);r=Math.floor((i-14)/4),m=Math.min(Math.max(m,c.length),r),pixelOpt=["WIDTH"],materialOpt=["NORMAL"],colorOpt=["NORMAL","COLOR"],transparentOpt=["NORMAL","COLOR","TRANSPARENT"],e&&(materialOpt.push("USE_IBL"),transparentOpt.push("USE_IBL")),ge=Nt(pixelOpt),we=Nt(materialOpt),Me=Nt(colorOpt),be=Nt(transparentOpt)}function st(){t.deleteProgram(be),t.deleteProgram(Me),t.deleteProgram(we),t.deleteProgram(ge)}function at(){let i=o.webgl2?window.top.document.asygl2[e]:window.top.document.asygl[e];i.gl=t,i.nlights=l.length,i.Nmaterials=m,i.maxMaterials=r,i.pixelShader=ge,i.materialShader=we,i.colorShader=Me,i.transparentShader=be}function ot(t,e){let i;return o.webgl2&&(i=t.getContext("webgl2",{alpha:e}),o.embedded&&!i)?(o.webgl2=!1,o.ibl=!1,ht(!1),null):(i||(o.webgl2=!1,o.ibl=!1,i=t.getContext("webgl",{alpha:e})),i||alert("Could not initialize WebGL"),i)}function ht(s=!0){if(o.ibl&&(o.webgl2=!0),e=o.background[3]<1,o.embedded){let a=window.top.document;if(s&&(n=o.canvas.getContext("2d")),i=o.webgl2?a.offscreen2:a.offscreen,i||(i=a.createElement("canvas"),o.webgl2?a.offscreen2=i:a.offscreen=i),o.webgl2?a.asygl2||(a.asygl2=Array(2)):a.asygl||(a.asygl=Array(2)),asygl=o.webgl2?a.asygl2:a.asygl,asygl[e]&&asygl[e].gl)!function(){let i=o.webgl2?window.top.document.asygl2[e]:window.top.document.asygl[e];t=i.gl,d=i.nlights,m=i.Nmaterials,r=i.maxMaterials,ge=i.pixelShader,we=i.materialShader,Me=i.colorShader,be=i.transparentShader}(),(l.length!=d||Math.min(c.length,r)>m)&&(rt(),at());else{if(rc=ot(i,e),!rc)return;t=rc,rt(),o.webgl2?a.asygl2[e]={}:a.asygl[e]={},at()}}else t=ot(o.canvas,e),rt();$=t.getExtension("OES_element_index_uint"),q=t.TRIANGLES,K=new mt(t.POINTS),Z=new mt(t.LINES),Q=new mt,J=new mt,tt=new mt,et=new mt}function lt(t,e,i,n=[]){let r=o.webgl2?"300 es":"100",s=Array(...n),a=[["nlights",0==V?l.length:0],["Nmaterials",m]],h=[["int","Nlights",Math.max(l.length,1)]];o.webgl2&&s.push("WEBGL2"),o.ibl&&a.push(["ROUGHNESS_STEP_COUNT",8..toFixed(2)]),o.orthographic&&s.push("ORTHOGRAPHIC"),macros_str=a.map(t=>`#define ${t[0]} ${t[1]}`).join("\n"),define_str=s.map(t=>"#define "+t).join("\n"),const_str=h.map(t=>`const ${t[0]} ${t[1]}=${t[2]};`).join("\n"),ext_str=[].map(t=>`#extension ${t}: enable`).join("\n"),shaderSrc=`#version ${r}\n${ext_str}\n${define_str}\n${const_str}\n${macros_str}\n\n\n#ifdef GL_FRAGMENT_PRECISION_HIGH\nprecision highp float;\n#else\nprecision mediump float;\n#endif\n \n${e}\n `;let c=t.createShader(i);return t.shaderSource(c,shaderSrc),t.compileShader(c),t.getShaderParameter(c,t.COMPILE_STATUS)?c:(alert(t.getShaderInfoLog(c)),null)}function ct(e,i,n,r=t.ARRAY_BUFFER){return e.length>0&&(0==i&&(i=t.createBuffer(),n=!0),t.bindBuffer(r,i),n&&t.bufferData(r,e,t.STATIC_DRAW)),i}function dt(e,i,n=e.indices){if(0==e.indices.length)return;let r=i!=ge;!function(e,i){let n=i==ge;t.useProgram(i),t.enableVertexAttribArray(yt),n&&t.enableVertexAttribArray(Lt);let r=!n&&l.length>0;r&&t.enableVertexAttribArray(At);t.enableVertexAttribArray(Et),i.projViewMatUniform=t.getUniformLocation(i,"projViewMat"),i.viewMatUniform=t.getUniformLocation(i,"viewMat"),i.normMatUniform=t.getUniformLocation(i,"normMat"),(i==Me||i==be)&&t.enableVertexAttribArray(It);if(r)for(let t=0;t0&&t.vertexAttribPointer(At,3,t.FLOAT,!1,24,12):t.vertexAttribPointer(Lt,1,t.FLOAT,!1,16,12),e.materialsBuffer=ct(new Int16Array(e.materialIndices),e.materialsBuffer,s),t.vertexAttribPointer(Et,1,t.SHORT,!1,2,0),i!=Me&&i!=be||(e.colorsBuffer=ct(new Float32Array(e.colors),e.colorsBuffer,s),t.vertexAttribPointer(It,4,t.FLOAT,!0,0,0)),e.indicesBuffer=ct($?new Uint32Array(n):new Uint16Array(n),e.indicesBuffer,s,t.ELEMENT_ARRAY_BUFFER),e.rendered=!0,t.drawElements(r?V?t.LINES:e.type:t.POINTS,n.length,$?t.UNSIGNED_INT:t.UNSIGNED_SHORT,0)}class mt{constructor(t){this.type=t||q,this.verticesBuffer=0,this.materialsBuffer=0,this.colorsBuffer=0,this.indicesBuffer=0,this.rendered=!1,this.partial=!1,this.clear()}clear(){this.vertices=[],this.materialIndices=[],this.colors=[],this.indices=[],this.nvertices=0,this.materials=[],this.materialTable=[]}vertex(t,e){return this.vertices.push(t[0]),this.vertices.push(t[1]),this.vertices.push(t[2]),this.vertices.push(e[0]),this.vertices.push(e[1]),this.vertices.push(e[2]),this.materialIndices.push(it),this.nvertices++}Vertex(t,e,i=[0,0,0,0]){return this.vertices.push(t[0]),this.vertices.push(t[1]),this.vertices.push(t[2]),this.vertices.push(e[0]),this.vertices.push(e[1]),this.vertices.push(e[2]),this.materialIndices.push(it),this.colors.push(i[0]),this.colors.push(i[1]),this.colors.push(i[2]),this.colors.push(i[3]),this.nvertices++}vertex0(t,e){return this.vertices.push(t[0]),this.vertices.push(t[1]),this.vertices.push(t[2]),this.vertices.push(e),this.materialIndices.push(it),this.nvertices++}iVertex(t,e,i,n,r=[0,0,0,0]){let s=6*t;this.vertices[s]=e[0],this.vertices[s+1]=e[1],this.vertices[s+2]=e[2],this.vertices[s+3]=i[0],this.vertices[s+4]=i[1],this.vertices[s+5]=i[2],this.materialIndices[t]=it;let a=4*t;this.colors[a]=r[0],this.colors[a+1]=r[1],this.colors[a+2]=r[2],this.colors[a+3]=r[3],n&&this.indices.push(t)}append(t){ft(this.vertices,t.vertices),ft(this.materialIndices,t.materialIndices),ft(this.colors,t.colors),function(t,e,i){let n=t.length,r=e.length;t.length+=e.length;for(let s=0;sthis.X&&(this.X=h),lthis.Y&&(this.Y=l)}return(this.X<-1.01||this.x>1.01||this.Y<-1.01||this.y>1.01)&&(this.Onscreen=!1,!0)}T(t){let e=this.c[0],i=this.c[1],n=this.c[2],r=t[0]-e,s=t[1]-i,a=t[2]-n;return[r*I[0]+s*I[3]+a*I[6]+e,r*I[1]+s*I[4]+a*I[7]+i,r*I[2]+s*I[5]+a*I[8]+n]}Tcorners(t,e){return[this.T(t),this.T([t[0],t[1],e[2]]),this.T([t[0],e[1],t[2]]),this.T([t[0],e[1],e[2]]),this.T([e[0],t[1],t[2]]),this.T([e[0],t[1],e[2]]),this.T([e[0],e[1],t[2]]),this.T(e)]}setMaterial(t,e){null==t.materialTable[this.MaterialIndex]&&(t.materials.length>=m&&(t.partial=!0,e()),t.materialTable[this.MaterialIndex]=t.materials.length,t.materials.push(c[this.MaterialIndex])),it=t.materialTable[this.MaterialIndex]}render(){let t;var e,i;if(this.setMaterialIndex(),0==this.CenterIndex?(e=this.Min,i=this.Max,t=[e,[e[0],e[1],i[2]],[e[0],i[1],e[2]],[e[0],i[1],i[2]],[i[0],e[1],e[2]],[i[0],e[1],i[2]],[i[0],i[1],e[2]],i]):(this.c=o.Centers[this.CenterIndex-1],t=this.Tcorners(this.Min,this.Max)),this.offscreen(t))return this.data.clear(),void this.notRendered();let n,r=this.controlpoints;if(0==this.CenterIndex){if(!U&&this.Onscreen)return void this.append();n=r}else{let t=r.length;n=Array(t);for(let e=0;e=-n||0==r)return i;--r,n*=2;let s=new Ot(t[0],t[1],t[2],t[3]),a=new Ot(t[4],t[5],t[6],t[7]),o=new Ot(t[8],t[9],t[10],t[11]),h=new Ot(t[12],t[13],t[14],t[15]),l=new Ot(t[0],t[4],t[8],t[12]),c=new Ot(s.m0,a.m0,o.m0,h.m0),d=new Ot(s.m3,a.m3,o.m3,h.m3),m=new Ot(s.m5,a.m5,o.m5,h.m5),f=new Ot(s.m4,a.m4,o.m4,h.m4),u=new Ot(s.m2,a.m2,o.m2,h.m2),p=new Ot(t[3],t[7],t[11],t[15]),v=[t[0],s.m0,s.m3,s.m5,l.m0,c.m0,d.m0,m.m0,l.m3,c.m3,d.m3,m.m3,l.m5,c.m5,d.m5,m.m5];i=this.bound(v,e,i,n,r);let x=[l.m5,c.m5,d.m5,m.m5,l.m4,c.m4,d.m4,m.m4,l.m2,c.m2,d.m2,m.m2,t[12],h.m0,h.m3,h.m5];i=this.bound(x,e,i,n,r);let g=[m.m5,f.m5,u.m5,p.m5,m.m4,f.m4,u.m4,p.m4,m.m2,f.m2,u.m2,p.m2,h.m5,h.m4,h.m2,t[15]];i=this.bound(g,e,i,n,r);let w=[s.m5,s.m4,s.m2,t[3],m.m0,f.m0,u.m0,p.m0,m.m3,f.m3,u.m3,p.m3,m.m5,f.m5,u.m5,p.m5];return this.bound(w,e,i,n,r)}cornerboundtri(t,e){let i=e(t[0],t[6]);return e(i,t[9])}controlboundtri(t,e){let i=e(t[1],t[2]);return i=e(i,t[3]),i=e(i,t[4]),i=e(i,t[5]),i=e(i,t[7]),e(i,t[8])}boundtri(t,e,i,n,r){if(i=e(i,this.cornerboundtri(t,e)),e(-1,1)*(i-this.controlboundtri(t,e))>=-n||0==r)return i;--r,n*=2;let s=new Pt(t),a=[s.l003,s.l102,s.l012,s.l201,s.l111,s.l021,s.l300,s.l210,s.l120,s.l030];i=this.boundtri(a,e,i,n,r);let o=[s.l300,s.r102,s.r012,s.r201,s.r111,s.r021,s.r300,s.r210,s.r120,s.r030];i=this.boundtri(o,e,i,n,r);let h=[s.l030,s.u102,s.u012,s.u201,s.u111,s.u021,s.r030,s.u210,s.u120,s.u030];i=this.boundtri(h,e,i,n,r);let l=[s.r030,s.u201,s.r021,s.u102,s.c111,s.r012,s.l030,s.l120,s.l210,s.l300];return this.boundtri(l,e,i,n,r)}Bounds(t,e,i){let n=Array(3),r=t.length,s=Array(r);for(let a=0;a<3;++a){for(let e=0;e0&&this.append()}append(){this.transparent?tt.append(this.data):this.color?J.append(this.data):Q.append(this.data)}notRendered(){this.transparent?tt.rendered=!1:this.color?J.rendered=!1:Q.rendered=!1}Render(t,e,i,n,r,s,a,o,h,l,c,d,m,f,u,p,v){let x=this.Distance(t);if(x[0]0&&this.append()}Render3(t,e,i,n,r,s,a,o,h,l,c,d,m){if(this.Distance3(t)this.epsilon?r:(r=Ft(t,e,i),Ut(r)>this.epsilon?r:zt(t,e,i,n))}sumdifferential(t,e,i,n,r,s,a){let o=this.differential(t,e,i,n),h=this.differential(t,r,s,a);return[o[0]+h[0],o[1]+h[1],o[2]+h[2]]}normal(t,e,i,n,r,s,a){let o=3*(r[0]-n[0]),h=3*(r[1]-n[1]),l=3*(r[2]-n[2]),c=3*(i[0]-n[0]),d=3*(i[1]-n[1]),m=3*(i[2]-n[2]),f=[h*m-l*d,l*c-o*m,o*d-h*c];if(Ut(f)>this.epsilon)return f;let u=[c,d,m],p=[o,h,l],v=Ft(n,i,e),x=Ft(n,r,s),g=Bt(x,u),w=Bt(p,v);if(f=[g[0]+w[0],g[1]+w[1],g[2]+w[2]],Ut(f)>this.epsilon)return f;let M=zt(n,i,e,t),b=zt(n,r,s,a);g=Bt(p,M),w=Bt(b,u);let R=Bt(x,v);return f=[g[0]+w[0]+R[0],g[1]+w[1]+R[1],g[2]+w[2]+R[2]],Ut(f)>this.epsilon?f:(g=Bt(b,v),w=Bt(x,M),f=[g[0]+w[0],g[1]+w[1],g[2]+w[2]],Ut(f)>this.epsilon?f:Bt(b,M))}}function xt(t){return 0<=t&&t<=1}class gt{constructor(t,e,i){const n=1e3*Number.EPSILON,r=n*n;if(Math.abs(t)<=n*Math.abs(e)+r*Math.abs(i))Math.abs(e)>n*Math.abs(i)?(this.roots=1,this.t1=-i/e):0==i?(this.roots=1,this.t1=0):this.roots=0;else{let r=.5*e/t,s=e*r;if(Math.abs(s)<=n*Math.abs(i)){let e=-i/t;e>=0?(this.roots=2,this.t2=Math.sqrt(e),this.t1=-this.t2):this.roots=0}else{let t=-2*i/s;if(t>-1){this.roots=2;let e=r*function(t){return t/(Math.sqrt(1+t)+1)}(t),i=-e-2*r;i<=e?(this.t1=i,this.t2=e):(this.t1=e,this.t2=i)}else-1==t?(this.roots=1,this.t1=this.t2=-r):this.roots=0}}}}class wt extends ut{constructor(t,e,i,n,r){if(super(),this.controlpoints=t,this.CenterIndex=e,this.MaterialIndex=i,n&&r)this.Min=n,this.Max=r;else{let t=this.Bounds(this.controlpoints);this.Min=t[0],this.Max=t[1]}}Bounds(t){let e=Array(3),i=Array(3),n=t.length,r=Array(n);for(let h=0;h<3;++h){for(let e=0;e0&&this.append()}append(){Z.append(this.data)}notRendered(){Z.rendered=!1}Render(t,e,i){let n=t[0],r=t[1],s=t[2],a=t[3];if(Ht(n,r,s,a)0?-1-it:1+it;for(let e=0,i=this.Indices.length;e1?i[1]:n;if(h&&0!=h.length||(h=n),this.Colors.length>0){let t=i.length>2?i[2]:n;t&&0!=t.length||(t=n);let e=this.Colors[t[0]],l=this.Colors[t[1]],c=this.Colors[t[2]];this.transparent|=e[3]+l[3]+c[3]<3,0==V?(this.data.iVertex(n[0],r,this.Normals[h[0]],o,e),this.data.iVertex(n[1],s,this.Normals[h[1]],o,l),this.data.iVertex(n[2],a,this.Normals[h[2]],o,c)):(this.data.iVertex(n[0],r,this.Normals[h[0]],o,e),this.data.iVertex(n[1],s,this.Normals[h[1]],o,l),this.data.iVertex(n[1],s,this.Normals[h[1]],o,l),this.data.iVertex(n[2],a,this.Normals[h[2]],o,c),this.data.iVertex(n[2],a,this.Normals[h[2]],o,c),this.data.iVertex(n[0],r,this.Normals[h[0]],o,e))}else 0==V?(this.data.iVertex(n[0],r,this.Normals[h[0]],o),this.data.iVertex(n[1],s,this.Normals[h[1]],o),this.data.iVertex(n[2],a,this.Normals[h[2]],o)):(this.data.iVertex(n[0],r,this.Normals[h[0]],o),this.data.iVertex(n[1],s,this.Normals[h[1]],o),this.data.iVertex(n[1],s,this.Normals[h[1]],o),this.data.iVertex(n[2],a,this.Normals[h[2]],o),this.data.iVertex(n[2],a,this.Normals[h[2]],o),this.data.iVertex(n[0],r,this.Normals[h[0]],o))}this.data.nvertices=t.length,this.data.indices.length>0&&this.append()}append(){this.transparent?tt.append(this.data):et.append(this.data)}notRendered(){this.transparent?tt.rendered=!1:et.rendered=!1}}function Rt(){M=-Math.tan(.5*o.angleOfView)*o.maxBound[2],_.x=_.y=0,_.z=.5*(o.minBound[2]+o.maxBound[2]),x=v=o.zoom0,S.zmin=o.minBound[2],S.zmax=o.maxBound[2],P.x=P.y=0,_e(),U=!0,Oe()}function Tt(){mat4.identity(T),Rt(),window.top.asyWebApplication&&window.top.asyWebApplication.setProjection(""),window.parent.asyProjection=!1}let yt=0,At=1,Et=2,It=3,Lt=4;function Nt(e=[]){let i=lt(t,vertex,t.VERTEX_SHADER,e),n=lt(t,fragment,t.FRAGMENT_SHADER,e),r=t.createProgram();return t.attachShader(r,i),t.attachShader(r,n),t.bindAttribLocation(r,yt,"position"),t.bindAttribLocation(r,At,"normal"),t.bindAttribLocation(r,Et,"materialIndex"),t.bindAttribLocation(r,It,"color"),t.bindAttribLocation(r,Lt,"width"),t.linkProgram(r),t.getProgramParameter(r,t.LINK_STATUS)||alert("Could not initialize shaders"),r}class Ot{constructor(t,e,i,n){this.m0=.5*(t+e);let r=.5*(e+i);this.m2=.5*(i+n),this.m3=.5*(this.m0+r),this.m4=.5*(r+this.m2),this.m5=.5*(this.m3+this.m4)}}class _t{constructor(t,e,i,n){this.m0=[.5*(t[0]+e[0]),.5*(t[1]+e[1]),.5*(t[2]+e[2])];let r=.5*(e[0]+i[0]),s=.5*(e[1]+i[1]),a=.5*(e[2]+i[2]);this.m2=[.5*(i[0]+n[0]),.5*(i[1]+n[1]),.5*(i[2]+n[2])],this.m3=[.5*(this.m0[0]+r),.5*(this.m0[1]+s),.5*(this.m0[2]+a)],this.m4=[.5*(r+this.m2[0]),.5*(s+this.m2[1]),.5*(a+this.m2[2])],this.m5=[.5*(this.m3[0]+this.m4[0]),.5*(this.m3[1]+this.m4[1]),.5*(this.m3[2]+this.m4[2])]}}class Pt{constructor(t){this.l003=t[0];let e=t[1],i=t[2],n=t[3],r=t[4],s=t[5];this.r300=t[6];let a=t[7],o=t[8];this.u030=t[9],this.u021=.5*(this.u030+s),this.u120=.5*(this.u030+o);let h=.5*(s+i),l=.5*(o+r),c=.5*(o+a),d=.5*(i+r);this.l012=.5*(i+this.l003);let m=.5*(r+n);this.r210=.5*(a+this.r300),this.l102=.5*(this.l003+e);let f=.5*(e+n);this.r201=.5*(n+this.r300),this.u012=.5*(this.u021+h),this.u210=.5*(this.u120+c),this.l021=.5*(h+this.l012);let u=.5*l+.25*(r+e);this.r120=.5*(c+this.r210);let p=.5*d+.25*(r+a),v=.25*(s+r)+.5*m;this.l201=.5*(this.l102+f),this.r102=.5*(f+this.r201),this.l210=.5*(p+this.l201),this.r012=.5*(p+this.r102),this.l300=.5*(this.l201+this.r102),this.r021=.5*(v+this.r120),this.u201=.5*(this.u210+v),this.r030=.5*(this.u210+this.r120),this.u102=.5*(this.u012+u),this.l120=.5*(this.l021+u),this.l030=.5*(this.u012+this.l021),this.l111=.5*(d+this.l102),this.r111=.5*(m+this.r210),this.u111=.5*(this.u021+l),this.c111=.25*(h+c+f+r)}}function St(t){let e=1/(Math.sqrt(t[0]*t[0]+t[1]*t[1]+t[2]*t[2])||1);return[t[0]*e,t[1]*e,t[2]*e]}function Ut(t){return t[0]*t[0]+t[1]*t[1]+t[2]*t[2]}function Vt(t,e){return t[0]*e[0]+t[1]*e[1]+t[2]*e[2]}function Bt(t,e){return[t[1]*e[2]-t[2]*e[1],t[2]*e[0]-t[0]*e[2],t[0]*e[1]-t[1]*e[0]]}function Ct(t,e,i,n,r){let s=1-r,a=s*s;return a*s*t+r*(3*(a*e+r*s*i)+r*r*n)}function Dt(t,e){return[e[0]-t[0],e[1]-t[1],e[2]-t[2]]}function Ft(t,e,i){return[3*(t[0]+i[0])-6*e[0],3*(t[1]+i[1])-6*e[1],3*(t[2]+i[2])-6*e[2]]}function zt(t,e,i,n){return[n[0]-t[0]+3*(e[0]-i[0]),n[1]-t[1]+3*(e[1]-i[1]),n[2]-t[2]+3*(e[2]-i[2])]}function Ht(t,e,i,n){let r=[1/3*(n[0]-t[0]),1/3*(n[1]-t[1]),1/3*(n[2]-t[2])];return Math.max(Ut([e[0]-r[0]-t[0],e[1]-r[1]-t[1],e[2]-r[2]-t[2]]),Ut([n[0]-r[0]-i[0],n[1]-r[1]-i[1],n[2]-r[2]-i[2]]))}function Xt(t,e,i,n){let r=[e[0]-t[0],e[1]-t[1],e[2]-t[2]],s=[n[0]-i[0],n[1]-i[1],n[2]-i[2]];return Math.max(Ut(Bt(r,St(s))),Ut(Bt(s,St(r))))/9}function Gt(t){return[Math.min(t[0][0],t[1][0],t[2][0],t[3][0],t[4][0],t[5][0],t[6][0],t[7][0]),Math.min(t[0][1],t[1][1],t[2][1],t[3][1],t[4][1],t[5][1],t[6][1],t[7][1]),Math.min(t[0][2],t[1][2],t[2][2],t[3][2],t[4][2],t[5][2],t[6][2],t[7][2])]}function Wt(t){return[Math.max(t[0][0],t[1][0],t[2][0],t[3][0],t[4][0],t[5][0],t[6][0],t[7][0]),Math.max(t[0][1],t[1][1],t[2][1],t[3][1],t[4][1],t[5][1],t[6][1],t[7][1]),Math.max(t[0][2],t[1][2],t[2][2],t[3][2],t[4][2],t[5][2],t[6][2],t[7][2])]}function jt(t){oe||he(),B=!0,C=t.clientX,D=t.clientY}let kt,Yt,$t=!1;function qt(t){return Math.hypot(t[0].pageX-t[1].pageX,t[0].pageY-t[1].pageY)}function Kt(t){t.preventDefault(),oe||he();let e=t.targetTouches;pe=ve=$t=!1,ue||(1!=e.length||B||(Yt=(new Date).getTime(),touchId=e[0].identifier,C=e[0].pageX,D=e[0].pageY),2!=e.length||B||(touchId=e[0].identifier,kt=qt(e),$t=!0))}function Zt(t){B=!1}function Qt(t,e,i,n,r){if(t==i&&e==n)return;let[s,a]=function(t,e){let i=re(t),n=re(e),r=Vt(i,n);return[r>1?0:r<-1?f:Math.acos(r),St(Bt(i,n))]}([t,-e],[i,-n]);mat4.fromRotation(O,2*r*R*s/v,a),mat4.multiply(T,O,T)}function Jt(t,e,i,n){let r=1/v;P.x+=(i-t)*r*s,P.y-=(n-e)*r*a}function te(t,e,i,n){o.orthographic?Jt(t,e,i,n):(_.x+=(i-t)*(S.xmax-S.xmin),_.y-=(n-e)*(S.ymax-S.ymin))}function ee(){var t,e;t=A,e=T,mat4.fromTranslation(O,[_.x,_.y,_.z]),mat4.invert(N,O),mat4.multiply(t,e,N),mat4.multiply(t,O,t),mat4.translate(A,A,[_.x,_.y,0]),mat3.fromMat4(L,A),mat3.invert(I,L),mat4.multiply(E,y,A)}function ie(){let t=Math.sqrt(Number.MAX_VALUE),e=1/t;v<=e&&(v=e),v>=t&&(v=t),(1.5*v1.5*x)&&(U=!0,x=v)}function ne(t){let e=o.zoomStep*a*t;const i=Math.log(.1*Number.MAX_VALUE)/Math.log(o.zoomFactor);Math.abs(e)1&&(denom=1/n,e*=denom,i*=denom),[e,i,Math.sqrt(Math.max(1-i*i-e*e,0))]}function se(t,e,i,n){ne(e-n)}function ae(t,e,i,n=1){let r;switch(i){case 1:r=Qt;break;case 2:r=Jt;break;case 3:r=se;break;case 4:r=te;break;default:r=(t,e,i,n)=>{}}r((C-s)/s,(D-a)/a,(t-s)/s,(e-a)/a,n),C=t,D=e,_e(),Oe()}let oe=0;function he(){oe=1,o.canvas.addEventListener("wheel",me,!1)}function le(){let t,e,i;[t,e,i]=function(){let t=Array(3),e=Array(3),i=Array(3),n=_.x,r=_.y,s=.5*(S.zmin+S.zmax);for(let a=0;a<3;++a){let h=0,l=0,c=0,d=4*a;for(let t=0;t<4;++t){let e=4*t,i=T[e],a=T[e+1],m=T[e+2],f=T[e+3],u=o.Transform[d+t];h+=u*(f-n*i-r*a-s*m),c+=u*a,l+=u*(f-n*i-r*a)}t[a]=h,e[a]=c,i[a]=l}return[t,e,i]}();let n=o.orthographic?" orthographic(":" perspective(",r="".padStart(n.length),s="currentprojection=\n"+n+"camera=("+t+"),\n"+r+"up=("+e+"),\n"+r+"target=("+i+"),\n"+r+"zoom="+v*o.initialZoom/o.zoom0;return o.orthographic||(s+=",\n"+r+"angle="+2*Math.atan(Math.tan(.5*o.angleOfView)/v)/u),0==g&&0==w||(s+=",\n"+r+"viewportshift=("+g+","+w+")"),o.orthographic||(s+=",\n"+r+"autoadjust=false"),s+=");\n",window.parent.asyProjection=!0,s}function ce(t){if(oe||he(),o.embedded&&oe&&27==t.keyCode)return oe=0,void o.canvas.removeEventListener("wheel",me,!1);let e=[];switch(t.key){case"x":e=[1,0,0];break;case"y":e=[0,1,0];break;case"z":e=[0,0,1];break;case"h":Tt();break;case"m":++V,3==V&&(V=0),2!=V&&(o.embedded||st(),rt(o.ibl)),U=!0,Oe();break;case"+":case"=":case">":v*=o.zoomFactor,de();break;case"-":case"_":case"<":v/=o.zoomFactor,de();break;case"c":window.top.asyWebApplication||prompt("Ctrl+c Enter to copy currentprojection to clipboard; then append to asy file:",le())}e.length>0&&(mat4.rotate(T,T,.1,e),ee(),Oe())}function de(){ie(),_e(),Oe()}function me(t){t.preventDefault(),t.deltaY<0?v*=o.zoomFactor:v/=o.zoomFactor,de()}function fe(t){if(!B)return;let e,i=t.clientX,n=t.clientY;e=t.getModifierState("Control")?2:t.getModifierState("Shift")?3:t.getModifierState("Alt")?4:1,ae(i,n,e)}let ue=!1,pe=!1,ve=!1;function xe(t){if(t.preventDefault(),ue)return;let e=t.targetTouches;if(!$t&&1==e.length&&touchId==e[0].identifier){let t=e[0].pageX,i=e[0].pageY,n=t-C,r=i-D,s=n*n+r*r<=o.shiftHoldDistance*o.shiftHoldDistance;if(s&&!pe&&!ve&&(new Date).getTime()-Yt>o.shiftWaitTime&&(navigator.vibrate&&window.navigator.vibrate(o.vibrateTime),pe=!0),pe)ae(t,i,2);else if(!s){ve=!0,ae(e[0].pageX,e[0].pageY,1,.5)}}if($t&&!pe&&2==e.length&&touchId==e[0].identifier){let t=qt(e),i=t-kt;ue=!0,i*=o.zoomPinchFactor,i>o.zoomPinchCap&&(i=o.zoomPinchCap),i<-o.zoomPinchCap&&(i=-o.zoomPinchCap),ne(i/b),kt=t,pe=ve=ue=!1,_e(),Oe()}}let ge,we,Me,be,Re=[];function Te(){dt(K,ge),K.clear()}function ye(){dt(Z,we),Z.clear()}function Ae(){dt(Q,we),Q.clear()}function Ee(){dt(J,Me),J.clear()}function Ie(){dt(et,be),et.rendered=!1,et.clear()}function Le(){let e=tt.indices;if(V>0)return dt(tt,be,e),void tt.clear();if(e.length>0){!function(t){let e=A[2],i=A[6],n=A[10];Re.length=t.length;for(let r=0;re);n.sort((function(t,i){let n=3*t;Ia=e[n],Ib=e[n+1],Ic=e[n+2];let r=3*i;return IA=e[r],IB=e[r+1],IC=e[r+2],Re[Ia]+Re[Ib]+Re[Ic]void 0&&(t=void 0),e>void 0&&(e=void 0),P.x*=t/o.canvasWidth,P.y*=e/o.canvasHeight,o.canvasWidth=t,o.canvasHeight=e,o.embedded&&(o.canvas.width=i.width=o.canvasWidth,o.canvas.height=i.height=o.canvasHeight),b=Math.hypot(o.canvasWidth,o.canvasHeight),s=.5*o.canvas.width,a=.5*o.canvas.height,R=1+8*Math.hypot(o.viewportMargin[0],o.viewportMargin[1])/b,Pe(),_e(),U=!0}function Ue(){if(o.zoom0=o.initialZoom,window.top.asyWebApplication&&""==window.top.asyWebApplication.getProjection()&&(window.parent.asyProjection=!1),o.absolute&&!o.embedded)o.canvasWidth=o.canvasWidth0*window.devicePixelRatio,o.canvasHeight=o.canvasHeight0*window.devicePixelRatio;else{let t=o.canvasWidth0/o.canvasHeight0;o.canvasWidth=Math.max(window.innerWidth-10,10),o.canvasHeight=Math.max(window.innerHeight-10,10),!o.orthographic&&!window.parent.asyProjection&&o.canvasWidthe%4!=3)}function ze(e,i,n=t.RGB16F){let r=e.width(),s=e.height(),a=t.createTexture();return t.activeTexture(t.TEXTURE0+i),t.bindTexture(t.TEXTURE_2D,a),t.pixelStorei(t.UNPACK_ALIGNMENT,1),t.texParameteri(t.TEXTURE_2D,t.TEXTURE_MIN_FILTER,t.LINEAR),t.texParameteri(t.TEXTURE_2D,t.TEXTURE_MAG_FILTER,t.LINEAR),t.texImage2D(t.TEXTURE_2D,0,n,r,s,0,t.RGB,t.FLOAT,Fe(e)),a}window.webGLStart=function(){o.canvas=document.getElementById("Asymptote"),o.embedded=window.top.document!=document,ht(),t.enable(t.BLEND),t.blendFunc(t.SRC_ALPHA,t.ONE_MINUS_SRC_ALPHA),t.enable(t.DEPTH_TEST),t.enable(t.SCISSOR_TEST),o.canvas.onmousedown=jt,document.onmouseup=Zt,document.onmousemove=fe,o.canvas.onkeydown=ce,o.embedded||he(),o.canvas.addEventListener("touchstart",Kt,!1),o.canvas.addEventListener("touchend",Zt,!1),o.canvas.addEventListener("touchcancel",Zt,!1),o.canvas.addEventListener("touchleave",Zt,!1),o.canvas.addEventListener("touchmove",xe,!1),document.addEventListener("keydown",ce,!1),o.canvasWidth0=o.canvasWidth,o.canvasHeight0=o.canvasHeight,mat4.identity(T),0!=window.innerWidth&&0!=window.innerHeight&&Ue(),window.addEventListener("resize",Ue,!1),o.ibl&&async function(){let e=o.imageURL+o.image+"/";function i(t){return new Promise(e=>setTimeout(e,t))}for(;!Module.EXRLoader;)await i(0);promises=[De(o.imageURL+"refl.exr").then(t=>{let e=new Module.EXRLoader(t);j=ze(e,0)}),De(e+"diffuse.exr").then(t=>{let e=new Module.EXRLoader(t);W=ze(e,1)})],refl_promise=[],refl_promise.push(De(e+"refl0.exr"));for(let t=1;t<=8;++t)refl_promise.push(De(e+"refl"+t+"w.exr"));finished_promise=Promise.all(refl_promise).then(e=>{let i=t.createTexture();t.activeTexture(t.TEXTURE0+2),t.pixelStorei(t.UNPACK_ALIGNMENT,1),t.bindTexture(t.TEXTURE_2D,i),t.texParameteri(t.TEXTURE_2D,t.TEXTURE_MAX_LEVEL,e.length-1),t.texParameteri(t.TEXTURE_2D,t.TEXTURE_MIN_FILTER,t.LINEAR_MIPMAP_LINEAR),t.texParameteri(t.TEXTURE_2D,t.TEXTURE_MAG_FILTER,t.LINEAR),t.texParameterf(t.TEXTURE_2D,t.TEXTURE_MIN_LOD,0),t.texParameterf(t.TEXTURE_2D,t.TEXTURE_MAX_LOD,8);for(let i=0;ia?St(r):(r=[2*i[0]-e[0]-n[0],2*i[1]-e[1]-n[1],2*i[2]-e[2]-n[2]],Ut(r)>a?St(r):[n[0]-t[0]+3*(e[0]-i[0]),n[1]-t[1]+3*(e[1]-i[1]),n[2]-t[2]+3*(e[2]-i[2])])}let s=[n[0]-t[0]+3*(e[0]-i[0]),n[1]-t[1]+3*(e[1]-i[1]),n[2]-t[2]+3*(e[2]-i[2])],o=[2*(t[0]+i[0])-4*e[0],2*(t[1]+i[1])-4*e[1],2*(t[2]+i[2])-4*e[2]],h=[e[0]-t[0],e[1]-t[1],e[2]-t[2]],l=r*r,c=[s[0]*l+o[0]*r+h[0],s[1]*l+o[1]*r+h[1],s[2]*l+o[2]*r+h[2]];return Ut(c)>a?St(c):(l=2*r,c=[s[0]*l+o[0],s[1]*l+o[1],s[2]*l+o[2]],Ut(c)>a?St(c):St(s))}let h=Array(r.length),l=[e[0]-t[0],e[1]-t[1],e[2]-t[2]];Ut(l)i?St(e):(e=Bt(t,[0,0,1]),Ut(e)>i?St(e):[1,0,0])}(l);h[0]=new s(t,c,l);for(let a=1;a Date: Sun, 21 Jul 2024 18:41:41 -0700 Subject: [PATCH 33/51] Simplify code. --- base/graph3.asy | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/base/graph3.asy b/base/graph3.asy index b9b872f45..b474ef980 100644 --- a/base/graph3.asy +++ b/base/graph3.asy @@ -1659,7 +1659,7 @@ surface surface(picture pic=currentpicture, triple[][] f, bool[][] cond={}) surface s=surface(count); s.index=new int[nx][ny]; - int k=-1; + int k=0; for(int i=0; i < nx; ++i) { bool[] condi,condp; if(!all) { @@ -1670,13 +1670,15 @@ surface surface(picture pic=currentpicture, triple[][] f, bool[][] cond={}) triple[] fp=f[i+1]; int[] indexi=s.index[i]; for(int j=0; j < ny; ++j) { - if(all || (condi[j] && condi[j+1] && condp[j] && condp[j+1])) - s.s[++k]=patch(new triple[] { + if(all || (condi[j] && condi[j+1] && condp[j] && condp[j+1])) { + s.s[k]=patch(new triple[] { Scale(pic,fi[j]), Scale(pic,fp[j]), Scale(pic,fp[j+1]), Scale(pic,fi[j+1])}); - indexi[j]=k; + indexi[j]=k; + ++k; + } } } @@ -2062,11 +2064,13 @@ surface surface(picture pic=currentpicture, triple f(pair z), surface s=surface(sx.length); s.index=new int[nu][nv]; - int k=-1; + int k=0; for(int i=0; i < nu; ++i) { int[] indexi=s.index[i]; - for(int j=0; j < nv; ++j) - indexi[j]=++k; + for(int j=0; j < nv; ++j) { + indexi[j]=k; + ++k; + } } for(int k=0; k < sx.length; ++k) { From cc2d5ea6bed3fc870e6541b3feece2e0da288e68 Mon Sep 17 00:00:00 2001 From: John Bowman Date: Sun, 21 Jul 2024 18:42:08 -0700 Subject: [PATCH 34/51] Update comment. --- base/plain_prethree.asy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/base/plain_prethree.asy b/base/plain_prethree.asy index 886639625..f4302219b 100644 --- a/base/plain_prethree.asy +++ b/base/plain_prethree.asy @@ -161,7 +161,7 @@ projection currentprojection; struct light { real[][] diffuse; - real[][] specular; // For PRC only + real[][] specular; pen background=nullpen; // Background color of the 3D canvas. real specularfactor; triple[] position; // Only directional lights are currently implemented. From 3950f1384b857a341e5855728e7ad2db4f89d019 Mon Sep 17 00:00:00 2001 From: John Bowman Date: Sun, 21 Jul 2024 20:32:17 -0700 Subject: [PATCH 35/51] Output triangle group for indexed surfaces given render option tessellate=true. Fix triangle group normals. --- base/three.asy | 10 +-- base/three_surface.asy | 155 ++++++++++++++++++++++++++++------ drawsurface.h | 6 +- examples/filesurface.asy | 14 +-- examples/gamma3.asy | 2 +- examples/projectelevation.asy | 2 +- examples/smoothelevation.asy | 2 +- 7 files changed, 142 insertions(+), 49 deletions(-) diff --git a/base/three.asy b/base/three.asy index b93833f66..089267a87 100644 --- a/base/three.asy +++ b/base/three.asy @@ -46,15 +46,15 @@ restricted interaction Billboard=interaction(1); struct render { - // PRC parameters: - real compression; // lossy compression parameter (0=no compression) + real compression; // lossy PRC compression parameter (0=no compression) real granularity; // PRC rendering granularity - bool closed; // use one-sided rendering? + bool closed; // use one-sided PRC rendering? + bool tessellate; // use tessellated mesh to store straight patches? - bool3 merge; // merge nodes before rendering, for faster but - // lower quality PRC rendering (the value default means + bool3 merge; // merge PRC nodes before rendering, for faster but + // lower quality rendering (the value default means // merge opaque patches only). int sphere; // PRC sphere type (PRCsphere or NURBSsphere). diff --git a/base/three_surface.asy b/base/three_surface.asy index 073d36164..46d0a8e84 100644 --- a/base/three_surface.asy +++ b/base/three_surface.asy @@ -409,14 +409,15 @@ struct patch { // A constructor for a triangle or convex quadrilateral. void operator init(triple[] external, triple[] internal=new triple[], pen[] colors=new pen[], bool3 planar=default) { - init(); - straight=true; if(colors.length != 0) this.colors=copy(colors); if(external.length == 3) { + triangular=true; + this.planar=true; + init(); P=new triple[][] { {external[0]}, {interp(external[0],external[1],1/3), @@ -426,10 +427,8 @@ struct patch { {external[1],interp(external[1],external[2],1/3), interp(external[1],external[2],2/3),external[2]} }; - planar=true; - triangular=true; - init(); } else { + init(); if(internal.length == 0 && planar == default) this.planar=normal(external) != O; else this.planar=planar; @@ -789,10 +788,11 @@ struct surface { } void operator init(triple[][][] P, pen[][] colors=new pen[][], + bool3 straight=false, bool3 planar=default, bool triangular=false) { s=sequence(new patch(int i) { - return patch(P[i],colors.length == 0 ? new pen[] : colors[i],planar, - triangular); + return patch(P[i],colors.length == 0 ? new pen[] : colors[i], + straight,planar,triangular); },P.length); } @@ -1421,6 +1421,7 @@ void _draw(frame f, path3 g, triple center=O, material m, int computeNormals(triple[] v, int[][] vi, triple[] n, int[][] ni) { triple lastnormal=O; + n.delete(); for(int i=0; i < vi.length; ++i) { int[] vii=vi[i]; int[] nii=ni[i]; @@ -1434,7 +1435,7 @@ int computeNormals(triple[] v, int[][] vi, triple[] n, int[][] ni) return ni.length; } -// Draw triangles on a frame. +// Draw a triangle group on a frame. void draw(frame f, triple[] v, int[][] vi, triple[] n={}, int[][] ni={}, material m=currentpen, pen[] p={}, int[][] pi={}, light light=currentlight, render render=defaultrender) @@ -1481,21 +1482,25 @@ void draw(frame f, triple[] v, int[][] vi, render.interaction.type); } -// Draw triangles on a picture. +// Draw a triangle group on a picture. void draw(picture pic=currentpicture, triple[] v, int[][] vi, triple[] n={}, int[][] ni={}, material m=currentpen, pen[] p={}, int[][] pi={}, light light=currentlight, render render=defaultrender) { - bool normals=ni.length > 0; - if(!normals) { - ni=new int[vi.length][3]; - normals=computeNormals(v,vi,n,ni) > 0; - } bool colors=pi.length > 0; + // TODO: copy inputs + pic.add(new void(frame f, transform3 t, picture pic, projection P) { triple[] v=t*v; - triple[] n=t*n; + bool normals=ni.length > 0; + if(normals) { + transform3 T=transpose(inverse(shiftless(t))); + n=sequence(new triple(int i) {return unit(T*n[i]);},n.length) ; + } else { + ni=new int[vi.length][3]; + normals=computeNormals(v,vi,n,ni) > 0; + } if(is3D()) { render Render=render(render,interaction(render.interaction, @@ -1540,9 +1545,11 @@ void draw(picture pic=currentpicture, triple[] v, int[][] vi, } },true); - for(int[] vii : vi) - for(int viij : vii) - pic.addPoint(v[viij]); + for(int[] vii : vi) { + pic.addPoint(v[vii[0]]); + pic.addPoint(v[vii[1]]); + pic.addPoint(v[vii[2]]); + } } void tensorshade(transform t=identity(), frame f, patch s, @@ -1685,6 +1692,100 @@ void draw(transform t=identity(), frame f, surface s, int nu=1, int nv=1, draw(t,f,s,nu,nv,surfacepen,meshpen,light,meshlight,name,render,P); } +// draw a triangle group for the tessellation of a surface containing +// indexed patches. +void drawTessellation(picture pic=currentpicture, surface s, + material surfacepen=currentpen, pen meshpen=nullpen, + light light=currentlight, light meshlight=nolight, + string name="", render render=defaultrender) +{ + int nU=s.index.length; + if(nU == 0) return; + int nV=s.index[0].length; + if(nV == 0) return; + + int N=(nU+1)*(nV+1); + triple[] v=new triple[N]; + triple[] n=new triple[N]; + + bool colors=s.s[0].colors.length > 0; + pen[] p; + if(colors) + p=new pen[N]; + + int index(int i,int j) {return (nV+1)*i+j;} + + int k=0; + for(int U=0; U < nU; ++U) { + for(int V=0; V < nV; ++V) { + patch q=s.s[s.index[U][V]]; + v[k]=q.P[0][0]; + n[k]=unit(q.normal00()); + if(colors) + p[k]=q.colors[0]; + ++k; + } + patch q=s.s[s.index[U][nV-1]]; + v[k]=q.P[0][3]; + n[k]=unit(q.normal01()); + if(colors) + p[k]=q.colors[3]; + ++k; + } + + for(int V=0; V < nV; ++V) { + patch q=s.s[s.index[nU-1][V]]; + v[k]=q.P[3][0]; + n[k]=unit(q.normal10()); + if(colors) + p[k]=q.colors[1]; + ++k; + } + patch q=s.s[s.index[nU-1][nV-1]]; + v[k]=q.P[3][3]; + n[k]=unit(q.normal11()); + if(colors) + p[k]=q.colors[2]; + ++k; + + int[][] vi=new int[nU*nV][]; + int k=0; + for(int i=0; i < nU; ++i) { + for(int j=0; j < nV; ++j) { + vi[k]=new int[] {index(i,j),index(i+1,j),index(i+1,j+1)}; + ++k; + vi[k]=new int[] {index(i,j),index(i+1,j+1),index(i,j+1)}; + ++k; + } + } + + draw(pic,v,vi,n,vi,surfacepen,p,colors ? vi : new int[][],light); + + if(!invisible(meshpen)) { + if(is3D()) meshpen=thin()+squarecap+meshpen; + pic.add(new void(frame f, transform3 t, picture pic, projection P) { + surface S=t*s; + bool group=name != "" || render.defaultnames; + + for(int k=0; k < S.s.length; ++k) { + patch q=S.s[k]; + if(group) + begingroup3(f,meshname(name),render); + draw(f,q.P[0][0]--q.P[3][0]--q.P[3][3]--q.P[0][3]--cycle, + meshpen,meshlight,partname(k,render), + render); + if(group) + endgroup3(f); + } + }); + + for(int k=0; k < s.s.length; ++k) { + patch q=s.s[k]; + addPath(pic,q.P[0][0]--q.P[3][0]--q.P[3][3]--q.P[0][3]--cycle,meshpen); + } + } +} + void draw(picture pic=currentpicture, surface s, int nu=1, int nv=1, material[] surfacepen, pen[] meshpen=nullpens, light light=currentlight, light meshlight=nolight, string name="", @@ -1692,12 +1793,8 @@ void draw(picture pic=currentpicture, surface s, int nu=1, int nv=1, { if(s.empty()) return; - bool cyclic=surfacepen.cyclic; surfacepen=copy(surfacepen); - surfacepen.cyclic=cyclic; - cyclic=meshpen.cyclic; meshpen=copy(meshpen); - meshpen.cyclic=cyclic; pic.add(new void(frame f, transform3 t, picture pic, projection P) { surface S=t*s; @@ -1739,11 +1836,15 @@ void draw(picture pic=currentpicture, surface s, int nu=1, int nv=1, light light=currentlight, light meshlight=nolight, string name="", render render=defaultrender) { - material[] surfacepen={surfacepen}; - pen[] meshpen={meshpen}; - surfacepen.cyclic=true; - meshpen.cyclic=true; - draw(pic,s,nu,nv,surfacepen,meshpen,light,meshlight,name,render); + if(render.tessellate && s.index.length > 0) { + drawTessellation(pic,s,surfacepen,meshpen,light,meshlight,name,render); + } else { + material[] surfacepen={surfacepen}; + surfacepen.cyclic=true; + pen[] meshpen={meshpen}; + meshpen.cyclic=true; + draw(pic,s,nu,nv,surfacepen,meshpen,light,meshlight,name,render); + } } void draw(picture pic=currentpicture, surface s, int nu=1, int nv=1, diff --git a/drawsurface.h b/drawsurface.h index 5657388ef..0be0382ac 100644 --- a/drawsurface.h +++ b/drawsurface.h @@ -642,9 +642,9 @@ class drawBaseTriangles : public drawElement { for(size_t i=0; i < nN; i++) N[i]=s->N[i]; } else { - double T[]={t[0],t[1],t[2], - t[4],t[5],t[6], - t[8],t[9],t[10]}; + double T[]={t[0],t[4],t[8], + t[1],t[5],t[9], + t[2],t[6],t[10]}; run::inverse(T,3); for(size_t i=0; i < nN; i++) N[i]=unit(Transform3(s->N[i],T)); diff --git a/examples/filesurface.asy b/examples/filesurface.asy index bfa500ebf..d3c0093af 100644 --- a/examples/filesurface.asy +++ b/examples/filesurface.asy @@ -8,13 +8,13 @@ real[] x=in; real[] y=in; real[][] z=in; -surface s=surface(z,x,y,linear,linear); -real[] level=uniform(min(z)*(1-sqrtEpsilon),max(z)*(1+sqrtEpsilon),4); +surface s=surface(z,x,y); +real[] level=uniform(min(z)*(1-sqrtEpsilon),max(z)*(1+sqrtEpsilon),256); s.colors(palette(s.map(new real(triple v) {return find(level >= v.z);}), Rainbow())); -draw(s,meshpen=thick(),render(merge=true)); +draw(s,meshpen=thick(),render(tessellate=true)); triple m=currentpicture.userMin(); triple M=currentpicture.userMax(); @@ -24,13 +24,5 @@ xaxis3("$x$",Bounds,InTicks); yaxis3("$y$",Bounds,InTicks(Step=1,step=0.1)); zaxis3("$z$",Bounds,InTicks); -/* - picture palette; - size3(palette,1cm); - draw(palette,unitcube,red); - frame F=palette.fit3(); - add(F,(M.x,m.y,m.z)); -*/ - currentprojection=perspective(camera=target+realmult(dir(68,225),M-m), target=target); diff --git a/examples/gamma3.asy b/examples/gamma3.asy index 6fc56065c..410e9fedf 100644 --- a/examples/gamma3.asy +++ b/examples/gamma3.asy @@ -22,7 +22,7 @@ real Arg(triple v) } s.colors(palette(s.map(Arg),Wheel())); -draw(s,render(compression=Low,merge=true)); +draw(s,render(tessellate=false)); real xmin=point((-1,-1,-1)).x; real xmax=point((1,1,1)).x; diff --git a/examples/projectelevation.asy b/examples/projectelevation.asy index 6ffe51266..36a0901ff 100644 --- a/examples/projectelevation.asy +++ b/examples/projectelevation.asy @@ -12,6 +12,6 @@ surface s=surface(f,(-1/2,-1/2),(1/2,1/2),50,Spline); surface S=planeproject(unitsquare3)*s; S.colors(palette(s.map(zpart),Rainbow())); draw(S,nolight); -draw(s,lightgray+opacity(0.7)); +draw(s,lightgray+opacity(0.7),render(tessellate=false)); grid3(XYZgrid); diff --git a/examples/smoothelevation.asy b/examples/smoothelevation.asy index a7995b707..a375366b8 100644 --- a/examples/smoothelevation.asy +++ b/examples/smoothelevation.asy @@ -15,7 +15,7 @@ real f(pair z) {return cos(2*pi*z.x)*sin(2*pi*z.y);} surface s=surface(f,(-1/2,-1/2),(1/2,1/2),20,Spline); s.colors(palette(s.map(zpart),Rainbow())); -draw(s); +draw(s,render(tessellate=false)); scale(true); From 1671e0c0ea52467600adcb1b46f2d6dbc7c10fa9 Mon Sep 17 00:00:00 2001 From: Cole White Date: Thu, 15 Aug 2024 17:10:41 -0600 Subject: [PATCH 36/51] Use vulkan dynamic function loading. --- vkrender.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/vkrender.cc b/vkrender.cc index 9c4b83d6c..137dd6bb0 100644 --- a/vkrender.cc +++ b/vkrender.cc @@ -1,4 +1,5 @@ #define VMA_IMPLEMENTATION +#define VMA_DYNAMIC_VULKAN_FUNCTIONS 1 #include "vkrender.h" #include "shaderResources.h" #include "picture.h" From 6d38e52f7baff76834da5c8a44efbc4604d25a40 Mon Sep 17 00:00:00 2001 From: Cole White Date: Thu, 15 Aug 2024 17:19:05 -0600 Subject: [PATCH 37/51] Disable VMA static functions.' --- vkrender.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/vkrender.cc b/vkrender.cc index 137dd6bb0..f55232c16 100644 --- a/vkrender.cc +++ b/vkrender.cc @@ -1,4 +1,6 @@ #define VMA_IMPLEMENTATION +#define VULKAN_HPP_DISPATCH_LOADER_DYNAMIC 1 +#define VMA_STATIC_VULKAN_FUNCTIONS 0 #define VMA_DYNAMIC_VULKAN_FUNCTIONS 1 #include "vkrender.h" #include "shaderResources.h" From 7d7a7d541296d0590b96640d9fbaab92296496e4 Mon Sep 17 00:00:00 2001 From: Cole White Date: Thu, 15 Aug 2024 17:28:46 -0600 Subject: [PATCH 38/51] Use all available extensions. --- vkrender.cc | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/vkrender.cc b/vkrender.cc index f55232c16..589c5e3eb 100644 --- a/vkrender.cc +++ b/vkrender.cc @@ -929,13 +929,20 @@ void AsyVkRender::createInstance() } } + std::vector all_extensions; + all_extensions.reserve(supportedExtensions.size()); + + for (const auto& str : supportedExtensions) { + all_extensions.push_back(str.c_str()); + } + auto const instanceCI = vk::InstanceCreateInfo( vk::InstanceCreateFlagBits::eEnumeratePortabilityKHR, &appInfo, validationLayers.size(), validationLayers.data(), - extensions.size(), - extensions.data() + all_extensions.size(), + all_extensions.data() ); instance = vk::createInstanceUnique(instanceCI); VULKAN_HPP_DEFAULT_DISPATCHER.init(*instance); @@ -1033,7 +1040,7 @@ void AsyVkRender::createAllocator() VmaVulkanFunctions vkFuncs = {}; vkFuncs.vkGetInstanceProcAddr = vk::defaultDispatchLoaderDynamic.vkGetInstanceProcAddr; vkFuncs.vkGetDeviceProcAddr = vk::defaultDispatchLoaderDynamic.vkGetDeviceProcAddr; - vkFuncs.vkGetBufferMemoryRequirements2KHR = vk::defaultDispatchLoaderDynamic.vkGetBufferMemoryRequirements2; + vkFuncs.vkGetBufferMemoryRequirements2KHR = vk::defaultDispatchLoaderDynamic.vkGetBufferMemoryRequirements2 ? vk::defaultDispatchLoaderDynamic.vkGetBufferMemoryRequirements2 : vk::defaultDispatchLoaderDynamic.vkGetBufferMemoryRequirements2KHR; VmaAllocatorCreateInfo createInfo = {}; createInfo.vulkanApiVersion = VK_API_VERSION_1_2; From 28208161b823ba55068036fb388433c767cf95ce Mon Sep 17 00:00:00 2001 From: Cole White Date: Thu, 15 Aug 2024 17:35:09 -0600 Subject: [PATCH 39/51] Use memory requirements device extension. --- vkrender.cc | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/vkrender.cc b/vkrender.cc index 589c5e3eb..fc941c374 100644 --- a/vkrender.cc +++ b/vkrender.cc @@ -1255,6 +1255,12 @@ void AsyVkRender::createLogicalDevice() } } + if (supportedDeviceExtensions.find(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME) != supportedDeviceExtensions.end()) { + extensions.push_back(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME); + + std::cout << "Using logical device memory requirements extension!" << std::endl; + } + queueFamilyIndices = findQueueFamilies(physicalDevice, View ? &*surface : nullptr); std::vector queueCIs; From e1c3ebce8fa64b116464a006567587d84631e6d1 Mon Sep 17 00:00:00 2001 From: Cole White Date: Thu, 15 Aug 2024 17:42:03 -0600 Subject: [PATCH 40/51] Provide vkGetImageMemoryRequirements2. --- vkrender.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/vkrender.cc b/vkrender.cc index fc941c374..f13e2dc7c 100644 --- a/vkrender.cc +++ b/vkrender.cc @@ -1041,6 +1041,7 @@ void AsyVkRender::createAllocator() vkFuncs.vkGetInstanceProcAddr = vk::defaultDispatchLoaderDynamic.vkGetInstanceProcAddr; vkFuncs.vkGetDeviceProcAddr = vk::defaultDispatchLoaderDynamic.vkGetDeviceProcAddr; vkFuncs.vkGetBufferMemoryRequirements2KHR = vk::defaultDispatchLoaderDynamic.vkGetBufferMemoryRequirements2 ? vk::defaultDispatchLoaderDynamic.vkGetBufferMemoryRequirements2 : vk::defaultDispatchLoaderDynamic.vkGetBufferMemoryRequirements2KHR; + vkFuncs.vkGetImageMemoryRequirements2KHR = vk::defaultDispatchLoaderDynamic.vkGetImageMemoryRequirements2 ? vk::defaultDispatchLoaderDynamic.vkGetImageMemoryRequirements2 : vk::defaultDispatchLoaderDynamic.vkGetImageMemoryRequirements2KHR; VmaAllocatorCreateInfo createInfo = {}; createInfo.vulkanApiVersion = VK_API_VERSION_1_2; From ddc42492bdb06cd08b4dd74a89ffff2368545d2d Mon Sep 17 00:00:00 2001 From: Cole White Date: Thu, 15 Aug 2024 17:48:29 -0600 Subject: [PATCH 41/51] Provide more KHR functions to VMA. --- vkrender.cc | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/vkrender.cc b/vkrender.cc index f13e2dc7c..ee41f5d38 100644 --- a/vkrender.cc +++ b/vkrender.cc @@ -1042,6 +1042,8 @@ void AsyVkRender::createAllocator() vkFuncs.vkGetDeviceProcAddr = vk::defaultDispatchLoaderDynamic.vkGetDeviceProcAddr; vkFuncs.vkGetBufferMemoryRequirements2KHR = vk::defaultDispatchLoaderDynamic.vkGetBufferMemoryRequirements2 ? vk::defaultDispatchLoaderDynamic.vkGetBufferMemoryRequirements2 : vk::defaultDispatchLoaderDynamic.vkGetBufferMemoryRequirements2KHR; vkFuncs.vkGetImageMemoryRequirements2KHR = vk::defaultDispatchLoaderDynamic.vkGetImageMemoryRequirements2 ? vk::defaultDispatchLoaderDynamic.vkGetImageMemoryRequirements2 : vk::defaultDispatchLoaderDynamic.vkGetImageMemoryRequirements2KHR; + vkFuncs.vkBindBufferMemory2KHR = vk::defaultDispatchLoaderDynamic.vkBindBufferMemory2 ? vk::defaultDispatchLoaderDynamic.vkBindBufferMemory2 : vk::defaultDispatchLoaderDynamic.vkBindBufferMemory2KHR; + vkFuncs.vkBindImageMemory2KHR = vk::defaultDispatchLoaderDynamic.vkBindImageMemory2 ? vk::defaultDispatchLoaderDynamic.vkBindImageMemory2 : vk::defaultDispatchLoaderDynamic.vkBindImageMemory2KHR; VmaAllocatorCreateInfo createInfo = {}; createInfo.vulkanApiVersion = VK_API_VERSION_1_2; @@ -1262,6 +1264,10 @@ void AsyVkRender::createLogicalDevice() std::cout << "Using logical device memory requirements extension!" << std::endl; } + if (supportedDeviceExtensions.find(VK_KHR_BIND_MEMORY_2_EXTENSION_NAME) != supportedDeviceExtensions.end()) { + extensions.push_back(VK_KHR_BIND_MEMORY_2_EXTENSION_NAME); + } + queueFamilyIndices = findQueueFamilies(physicalDevice, View ? &*surface : nullptr); std::vector queueCIs; From 681600cdc62d5ee2d213186ff00bbbe9134d4dbf Mon Sep 17 00:00:00 2001 From: Cole White Date: Thu, 15 Aug 2024 17:52:39 -0600 Subject: [PATCH 42/51] Remove VMA preprocessor definitions. --- vkrender.cc | 3 --- 1 file changed, 3 deletions(-) diff --git a/vkrender.cc b/vkrender.cc index ee41f5d38..a19aa0944 100644 --- a/vkrender.cc +++ b/vkrender.cc @@ -1,7 +1,4 @@ #define VMA_IMPLEMENTATION -#define VULKAN_HPP_DISPATCH_LOADER_DYNAMIC 1 -#define VMA_STATIC_VULKAN_FUNCTIONS 0 -#define VMA_DYNAMIC_VULKAN_FUNCTIONS 1 #include "vkrender.h" #include "shaderResources.h" #include "picture.h" From ad7e58261ec680992e410d569b6934bb5a6e4320 Mon Sep 17 00:00:00 2001 From: Cole White Date: Thu, 15 Aug 2024 18:06:26 -0600 Subject: [PATCH 43/51] Add error message for null fence. --- vkrender.cc | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/vkrender.cc b/vkrender.cc index a19aa0944..fc80b5b7a 100644 --- a/vkrender.cc +++ b/vkrender.cc @@ -1604,6 +1604,11 @@ vk::CommandBuffer AsyVkRender::beginSingleCommands() void AsyVkRender::endSingleCommands(vk::CommandBuffer cmd) { vk::UniqueFence fence = device->createFenceUnique(vk::FenceCreateInfo()); + + if (!fence.get()) { + std::cout << "Fence failed to allocate." << std::endl; + } + cmd.end(); auto info = vk::SubmitInfo(); From a0936f3deaf20e33dc99d8cae0f678a485956dbd Mon Sep 17 00:00:00 2001 From: John Bowman Date: Thu, 15 Aug 2024 18:31:38 -0700 Subject: [PATCH 44/51] Add glsllang dependencies for MacOS. --- configure.ac | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/configure.ac b/configure.ac index 6bcbf16c4..09a14b417 100644 --- a/configure.ac +++ b/configure.ac @@ -465,14 +465,7 @@ case "$OSTYPE" in AC_CHECK_LIB([vulkan], [vkCreateInstance], [ LIBS_SAVE=$LIBS - case "$OSTYPE" in - darwin*) - VULKAN_LIBS="" - ;; - *) - VULKAN_LIBS="-lMachineIndependent -lOSDependent -lGenericCodeGen -lglslang " - ;; - esac + VULKAN_LIBS="-lMachineIndependent -lOSDependent -lGenericCodeGen " LIBS=$LIBS"-lglfw -lvulkan "$VULKAN_LIBS"-lSPIRV " AC_CHECK_LIB([glslang],[glslang_initialize_process], [ From 94cdbb88c144df4ed0847a10376ebe67ae84fe49 Mon Sep 17 00:00:00 2001 From: Cole White Date: Thu, 15 Aug 2024 20:04:39 -0600 Subject: [PATCH 45/51] Enable fragmentStoresAndAtomics --- vkrender.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/vkrender.cc b/vkrender.cc index fc80b5b7a..2f9a95921 100644 --- a/vkrender.cc +++ b/vkrender.cc @@ -1303,6 +1303,8 @@ void AsyVkRender::createLogicalDevice() vk::PhysicalDeviceFeatures deviceFeatures; deviceFeatures.fillModeNonSolid = true; + // Needed for some Mac machines. + deviceFeatures.fragmentStoresAndAtomics = true; // deviceFeatures.shaderStorageImageWriteWithoutFormat=true; // deviceFeatures.shaderStorageImageReadWithoutFormat=true; From bfcd48054fcfede628433ee1ea64ca4bb463a047 Mon Sep 17 00:00:00 2001 From: John Bowman Date: Sun, 25 Aug 2024 16:25:51 -0700 Subject: [PATCH 46/51] Hide diagnostic when verbose < 2. --- vkrender.cc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/vkrender.cc b/vkrender.cc index 2f9a95921..3a31a8e57 100644 --- a/vkrender.cc +++ b/vkrender.cc @@ -1257,8 +1257,9 @@ void AsyVkRender::createLogicalDevice() if (supportedDeviceExtensions.find(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME) != supportedDeviceExtensions.end()) { extensions.push_back(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME); - - std::cout << "Using logical device memory requirements extension!" << std::endl; + if (settings::verbose > 1) + std::cout << "Using logical device memory requirements extension." + << std::endl; } if (supportedDeviceExtensions.find(VK_KHR_BIND_MEMORY_2_EXTENSION_NAME) != supportedDeviceExtensions.end()) { From da449d86eba8b4f86d838cc1cc3f012e167dede6 Mon Sep 17 00:00:00 2001 From: Cole White Date: Thu, 5 Sep 2024 17:58:24 -0600 Subject: [PATCH 47/51] Resolve validation errors. --- vkrender.cc | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/vkrender.cc b/vkrender.cc index 3a31a8e57..ff90f8cbe 100644 --- a/vkrender.cc +++ b/vkrender.cc @@ -1239,9 +1239,11 @@ void AsyVkRender::createLogicalDevice() { auto const supportedDeviceExtensions = getDeviceExtensions(physicalDevice); std::vector extensions(deviceExtensions.begin(), deviceExtensions.end()); + bool usePortability = false; if (supportedDeviceExtensions.find(VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME) != supportedDeviceExtensions.end()) { extensions.push_back(VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME); + usePortability = true; } if (View) { extensions.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME); @@ -1284,6 +1286,7 @@ void AsyVkRender::createLogicalDevice() queueCIs.push_back(queueCI); } + void * extensionChain = nullptr; auto portabilityFeatures = vk::PhysicalDevicePortabilitySubsetFeaturesKHR( false, true @@ -1311,8 +1314,16 @@ void AsyVkRender::createLogicalDevice() physicalDevice.getProperties2(&props); + if (usePortability) { + extensionChain = &portabilityFeatures; + } + if (interlock) { - portabilityFeatures.pNext = &interlockFeatures; + if (usePortability) { + portabilityFeatures.pNext = &interlockFeatures; + } else { + extensionChain = &interlockFeatures; + } } auto deviceCI = vk::DeviceCreateInfo( @@ -1321,7 +1332,7 @@ void AsyVkRender::createLogicalDevice() VEC_VIEW(validationLayers), VEC_VIEW(extensions), &deviceFeatures, - &portabilityFeatures + extensionChain ); device = physicalDevice.createDeviceUnique(deviceCI, nullptr); @@ -4183,6 +4194,13 @@ void AsyVkRender::drawFrame() recreatePipeline = false; } + checkVkResult(device->waitForFences( + 1, &*frameObject.inFlightFence, VK_TRUE, std::numeric_limits::max() + )); + checkVkResult(device->resetFences( + 1, &*frameObject.inFlightFence + )); + uint32_t imageIndex=0; // index of the current swap chain image to render to // Get the image index from the swapchain if not viewing. @@ -4196,13 +4214,6 @@ void AsyVkRender::drawFrame() else if (result != vk::Result::eSuccess && result != vk::Result::eSuboptimalKHR) throw std::runtime_error("Failed to acquire next swapchain image."); } - - checkVkResult(device->waitForFences( - 1, &*frameObject.inFlightFence, VK_TRUE, std::numeric_limits::max() - )); - checkVkResult(device->resetFences( - 1, &*frameObject.inFlightFence - )); frameObject.commandBuffer->reset(vk::CommandBufferResetFlagBits()); updateUniformBuffer(currentFrame); From 0ffc39538ec81650e8ada6bf345720cd434ab6ba Mon Sep 17 00:00:00 2001 From: Cole White Date: Fri, 6 Sep 2024 19:09:44 -0600 Subject: [PATCH 48/51] Update portability settings for mac. --- vkrender.cc | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/vkrender.cc b/vkrender.cc index ff90f8cbe..d2486bbdf 100644 --- a/vkrender.cc +++ b/vkrender.cc @@ -1288,6 +1288,12 @@ void AsyVkRender::createLogicalDevice() void * extensionChain = nullptr; auto portabilityFeatures = vk::PhysicalDevicePortabilitySubsetFeaturesKHR( + false, + true, + false, + false, + false, + false, false, true ); From 169dad3de54d72f68d0eb4e41e6304df9e132f55 Mon Sep 17 00:00:00 2001 From: Cole White Date: Sat, 7 Sep 2024 16:25:00 -0600 Subject: [PATCH 49/51] Fix deadlock. --- vkrender.cc | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/vkrender.cc b/vkrender.cc index d2486bbdf..d680c76ba 100644 --- a/vkrender.cc +++ b/vkrender.cc @@ -824,7 +824,7 @@ void AsyVkRender::recreateSwapChain() glfwWaitEvents(); } -// device->waitIdle(); + device->waitIdle(); createSwapChain(); @@ -1288,12 +1288,6 @@ void AsyVkRender::createLogicalDevice() void * extensionChain = nullptr; auto portabilityFeatures = vk::PhysicalDevicePortabilitySubsetFeaturesKHR( - false, - true, - false, - false, - false, - false, false, true ); @@ -4203,9 +4197,6 @@ void AsyVkRender::drawFrame() checkVkResult(device->waitForFences( 1, &*frameObject.inFlightFence, VK_TRUE, std::numeric_limits::max() )); - checkVkResult(device->resetFences( - 1, &*frameObject.inFlightFence - )); uint32_t imageIndex=0; // index of the current swap chain image to render to @@ -4220,6 +4211,9 @@ void AsyVkRender::drawFrame() else if (result != vk::Result::eSuccess && result != vk::Result::eSuboptimalKHR) throw std::runtime_error("Failed to acquire next swapchain image."); } + checkVkResult(device->resetFences( + 1, &*frameObject.inFlightFence + )); frameObject.commandBuffer->reset(vk::CommandBufferResetFlagBits()); updateUniformBuffer(currentFrame); From b6ea1db8ad9179e32352477821a62b2092c12df1 Mon Sep 17 00:00:00 2001 From: Cole White Date: Fri, 13 Sep 2024 13:44:59 -0600 Subject: [PATCH 50/51] Fix semaphore validation error. --- vkrender.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/vkrender.cc b/vkrender.cc index d680c76ba..8b36309a8 100644 --- a/vkrender.cc +++ b/vkrender.cc @@ -836,6 +836,7 @@ void AsyVkRender::recreateSwapChain() createImmediateRenderTargets(); writeDescriptorSets(); createImageViews(); + createSyncObjects(); createCountRenderPass(); createGraphicsRenderPass(); createGraphicsPipelines(); From 9d8bf07c7e03e4cbad3be44a3c5e98abfe45dd65 Mon Sep 17 00:00:00 2001 From: Cole White Date: Fri, 13 Sep 2024 15:32:58 -0600 Subject: [PATCH 51/51] Add MacOS debug profile. --- .vscode/launch.json | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/.vscode/launch.json b/.vscode/launch.json index d26b53299..c2625b067 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -1,6 +1,39 @@ { "version": "0.2.0", "configurations": [ + { + "name": "MacOS Debug", + "type": "cppdbg", + "request": "launch", + "program": "${workspaceFolder}/asy", + "args": ["-V", "triangles"], + "stopAtEntry": false, + "cwd": "${fileDirname}", + "environment": [ + { + "name": "ASYMPTOTE_DIR", + "value": "${workspaceFolder}/base" + }, + { + "name": "DYLD_LIBRARY_PATH", + "value": "/usr/local/lib/:" + }, + { + "name": "VK_ICD_FILENAMES", + "value": "/usr/local/share/vulkan/icd.d/MoltenVK_icd.json" + }, + { + "name": "VK_DRIVER_FILES", + "value": "/usr/local/share/vulkan/icd.d/MoltenVK_icd.json" + }, + { + "name": "VK_ADD_LAYER_PATH", + "value": "/usr/local/share/vulkan/explicit_layer.d" + } + ], + "externalConsole": false, + "MIMode": "lldb" + }, { "name": "asy 3d linux", "type": "cppdbg",