*/}}
Browse Source

resource lookup

Yiming Wu 2 years ago
parent
commit
734e701eaf

+ 129 - 108
source/lagui/la_data.c

@@ -99,7 +99,7 @@ void laStopUsingDataBlock(void *HyperUserMem, laProp *prop, laPanel* p){
     for (iul = users->pFirst; iul; iul = next_iul){
         next_iul = iul->Pointer.pNext;
         if(local && (iull=iul) && iull->Instance!=HyperUserMem) continue;
-        if (/*prop == iul->Which &&*/ iul->Pointer.p == p){
+        if (/*prop == iul->Which &&*/ iul->Pointer.p == p||iul->Additional==p){
             lstRemoveItem(users,iul);
             memFree(iul);
         }
@@ -602,11 +602,10 @@ laPropContainer *laAddPropertyContainer(const char *Identifier, const char *Name
         laProp* p=laAddEnumProperty(pc, "__modified", "Modified", "Data block is modified", LA_WIDGET_ENUM_ICON_PLAIN,0,0,0,0,-1,laget_InstanceModified,0,0,0,0,0,0,0,0,LA_READ_ONLY|LA_UDF_IGNORE);
         laAddEnumItemAs(p, "MODIFIED", "Modified", "Data block is modified", 1, L'🌑');
         laAddEnumItemAs(p, "CLEAN", "Clean", "Data block is clean", 0, 0);
-        laAddStringProperty(pc, "__uid","UID","UID for shared resoure lookup",0,0,0,0,0,-1,0,laget_InstanceUID,laset_InstanceUID,0,0);
+        laAddStringProperty(pc, "__uid","UID","UID for shared resoure lookup",0,0,0,0,0,-1,0,laget_InstanceUID,laset_InstanceUID,0,LA_UDF_IGNORE);
     }
 
     laAddSubGroup(pc, "__self", "Self", "Own instance", Identifier,0,0,0,-1,0,laget_InstanceSelf,0,0,0,0,0,LA_UDF_REFER|LA_UDF_IGNORE);   
-
     lstAppendItem(&MAIN.PropContainers, pc);
 
     return pc;
@@ -2829,7 +2828,7 @@ void la_AddDataInst(void *ReadInstance, char *ReadNUID, void *ActualInstance){
     if (ReadNUID) l = hsh16MDoHashNUID(&MAIN.DBInst2, ReadNUID);
     else { l = hsh16MDoHashLongPtr(&MAIN.DBInst1, ReadInstance); ((laMemNode*)head)->ReadInstance = ReadInstance; }
 
-    lstAppendItem(l, head);
+    lstPushItem(l, head); //always push so we get the latest during ptr sync.
 }
 
 laPtrSync *la_AddPtrSyncDirect(void *Refer, void *Parent, laProp *Sub){
@@ -2840,50 +2839,70 @@ laPtrSync *la_AddPtrSyncDirect(void *Refer, void *Parent, laProp *Sub){
 
     return ps;
 }
-laPtrSync *la_AddPtrSync(char *ReferReadNUID, void *ActualParent, laProp *Sub){
-    laPtrSync *ps = memAcquireSimple(sizeof(laPtrSync));
-    ps->RefDB = la_GetReadDBInstNUID(ReferReadNUID);
-    ps->Parent = ActualParent; //la_GetWriteDBInst(ActualParent);
-    ps->Prop = Sub;
-    return ps;
-}
 laPtrSyncCommand *la_AddPtrSyncCommand(void *ReadRefer, void *ParentInst, char *ReadNUID, laProp *Sub){
     laPtrSyncCommand *psc = memAcquireSimple(sizeof(laPtrSyncCommand));
     psc->Target = la_AddPtrSyncDirect(0, ParentInst, Sub);
     psc->ReadInstance = ReadRefer;
-    if (ReadNUID) strcpy(psc->ReadNUID.String, ReadNUID);
-    lstAppendItem(&MAIN.PtrSyncCommandList, psc);
+    if (ReadNUID){ strcpy(psc->ReadNUID.String, ReadNUID); lstAppendItem(&MAIN.PtrSyncHyper2Commands, psc); }
+    else{ lstAppendItem(&MAIN.PtrSyncAddressCommands, psc); }
     return psc;
 }
 
 void la_ResetInstance(void* inst, laPropContainer* pc);
+void laRequestAdditionalRegistry(laUDFRegistry* r);
+laUDFOwnHyperItem* laNewHyperResource(char* uid);
+laUDFOwnHyperItem* laFindHyperResource(char* uid);
 
 void la_ExecutePtrSyncCommand(int Mode){
     int i;
-    laPtrSyncCommand *psc;
+    laPtrSyncCommand *psc,*NextPSC;
     laPtrSync *ps;
     void *dbi;
     laListHandle *lps, *ldbi;
     laListHandle L2 = {0};
     int FailCount = 0, AllCount = 0;
 
-    while (psc = lstPopItem(&MAIN.PtrSyncCommandList)){
-        ps = psc->Target;
-        if (psc->ReadNUID.String[0]) dbi = la_GetReadDBInstNUID(psc->ReadNUID.String);
-        elif (psc->ReadInstance) dbi = la_GetReadDBInstPtr(psc->ReadInstance); // should remove from hash and clear readinst when get this.
+    while (psc = lstPopItem(&MAIN.PtrSyncAddressCommands)){
+        ps = psc->Target; dbi=0; if (psc->ReadInstance) dbi = la_GetReadDBInstPtr(psc->ReadInstance);
 
         if (dbi){
-            //if (Mode == LA_UDF_APPEND)dbi->ReadInst = dbi->ActualInst;
-            ps->RefDB = dbi;
-            laSetActiveInstance(ps->Prop, ps->Parent, dbi);
+            //if (Mode == LA_udf_read)dbi->ReadInst = dbi->ActualInst; //??
+            ps->RefDB = dbi; laSetActiveInstance(ps->Prop, ps->Parent, dbi);
+        }else{ FailCount++; }
+
+        AllCount++; memFree(psc);
+    }
+
+    laUDFOwnHyperItem* ohi;
+    for(psc=MAIN.PtrSyncHyper2Commands.pFirst;psc;psc=NextPSC){
+        NextPSC=psc->Item.pNext; ps = psc->Target; dbi=0; if (psc->ReadNUID.String[0]) dbi = la_GetReadDBInstNUID(psc->ReadNUID.String);
+        if (dbi){
+            //if (Mode == LA_udf_read)dbi->ReadInst = dbi->ActualInst; //??
+            ps->RefDB = dbi; laSetActiveInstance(ps->Prop, ps->Parent, dbi);
+            lstRemoveItem(&MAIN.PtrSyncHyper2Commands,psc);memFree(psc);
         }else{
-            FailCount++;
+            if(!(ohi=laFindHyperResource(psc->ReadNUID.String))){
+                logPrint("Can't find resource %s\n", psc->ReadNUID.String);
+                lstRemoveItem(&MAIN.PtrSyncHyper2Commands,psc);memFree(psc);
+                FailCount++;
+            }else{
+                laRequestAdditionalRegistry(ohi->Registry);
+                lstRemoveItem(&MAIN.PtrSyncHyper2Commands,psc);
+                lstPushItem(&MAIN.PtrSyncHyper2Commands,psc); continue;
+            }
         }
-        AllCount++;
-        memFree(psc);
+        AllCount++; 
     }
 
     logPrint("Reference Match: Total %d, Failed %d\n", AllCount, FailCount);
+
+    laUDFRegistry*r;
+    while(r=lstPopPointer(&MAIN.PendingResourceRequests)){
+        laManagedUDF* m;
+        logPrint("[INFO] Loading additional resource: %s\n",r->Path->Ptr);
+        laUDF* udf = laOpenUDF(r->Path->Ptr, 1, 0, &m);
+        if (udf){ laExtractUDF(udf, m, LA_UDF_MODE_OVERWRITE, 0); laCloseUDF(udf); }else{ logPrint("[WARN] Can't open resource: %s\n",r->Path->Ptr); }
+    }
 }
 
 int la_ExtractFakeProp(laUDF *udf){
@@ -3091,7 +3110,7 @@ int la_ExtractProp(laUDF *udf, laManagedUDF* mUDF, laPropPack *pp, void *ParentI
                                         laUID uid; la_PeekHyperUID(udf, &uid.String);
                                         Instance = la_GetReadDBInstNUID(uid.String);
                                         if(Instance){ la_ResetInstance(Instance, pc); replaced=1; }
-                                        else{ logPrint("[Note] Hyper2 item [%s] from property '%s' hasn't been loaded yet, will append.\n", uid.String, p->Identifier); }
+                                        else{ /*logPrint("[Note] Hyper2 item [%s] from property '%s' hasn't been loaded yet, will append.\n", uid.String, p->Identifier);*/ }
                                     }
                                     if(!Instance) Instance = memAcquireHyperNoAppend(RealSize);
                                     memMarkClean(Instance);
@@ -3301,7 +3320,7 @@ int laExtractUDF(laUDF *udf, laManagedUDF* mUDF, int Mode, laListHandle *Parent)
             la_ReadString(udf, buf);
             LastOffset = strlen(buf) - 1;
             buf[LastOffset] = buf[LastOffset] == L'.' ? 0 : buf[LastOffset];
-            logPrint("    Prop Segment \"%s\" ...", buf);
+            logPrint("    Prop Segment \"%s\" ...\n", buf);
             la_GetPropFromPath(&SubPP, 0, buf, 0);
             la_StepPropPack(&SubPP);
             if (Parent){
@@ -3317,7 +3336,7 @@ int laExtractUDF(laUDF *udf, laManagedUDF* mUDF, int Mode, laListHandle *Parent)
             result = la_ExtractProp(udf, mUDF, &SubPP, dbi, Mode, ucni);
             EStatus = result ? result : EStatus;
             laNotifyUsersPP(&SubPP);
-            logPrint("[Done]\n", buf);
+            logPrint("    [Done]\n", buf);
             la_FreePropStepCache(SubPP.Go);
             SubPP.Go = 0;
         }
@@ -3436,9 +3455,8 @@ void la_ReadOwnHyperItems(laUDF *udf, laUDFRegistry* r){
         la_ReadString(udf, name);
         Seek=la_ReadPointer(udf);
         laPropContainer* pc = la_ContainerLookup(name);
-        if(!laFindHyperItem(pc, uid.String)){
-            ohi = memAcquireSimple(sizeof(laUDFOwnHyperItem));
-            if(pc){ lstAppendItem(&pc->ResourceRegistry, ohi); }
+        if(!laFindHyperResource(uid.String)){
+            ohi = laNewHyperResource(uid.String);
             ohi->Registry = r;
             ohi->Seek = Seek;
             strcpy(ohi->NUID.String, uid.String);
@@ -3531,13 +3549,16 @@ void laCloseUDF(laUDF *udf){
     if(!udf->Managed){ strSafeDestroy(&udf->FileName); memFree(udf); }
 }
 
-laUDFOwnHyperItem* laFindHyperItem(laPropContainer* pc, char* uid){
-    if(!pc) return 0;
-    for(laUDFOwnHyperItem* ohi=pc->ResourceRegistry.pFirst;ohi;ohi=ohi->Item.pNext){
+laUDFOwnHyperItem* laFindHyperResource(char* uid){
+    for(laUDFOwnHyperItem* ohi=MAIN.UDFResources.pFirst;ohi;ohi=ohi->Item.pNext){
         if(!strcmp(uid, ohi->NUID.String)) return ohi;
     }
     return 0;
 }
+laUDFOwnHyperItem* laNewHyperResource(char* uid){
+    laUDFOwnHyperItem* ohi = memAcquireSimple(sizeof(laUDFOwnHyperItem));
+    lstAppendItem(&MAIN.UDFResources, ohi); return ohi;
+}
 laUDFRegistry* laFindUDFRegistry(char* Path){
     for(laUDFRegistry* r=MAIN.ResourceRegistries.pFirst;r;r=r->Item.pNext){
         if(r->Path && !strcmp(Path, r->Path->Ptr)) return r;
@@ -3551,75 +3572,69 @@ laUDFRegistry* laCreateUDFRegistry(char* Path){
     lstAppendItem(&MAIN.ResourceRegistries, r);
     return r;
 }
+void laRequestAdditionalRegistry(laUDFRegistry* r){
+    if(la_FindManagedUDF(r->Path->Ptr)) return;
+    if(lstHasPointer(&MAIN.PendingResourceRequests, r)) return;
+    logPrint("[INFO] Request additional resources in: %s\n", r->Path->Ptr);
+    lstAppendPointer(&MAIN.PendingResourceRequests,r);
+}
 
 void laClearUDFRegistries(){
     laUDFOwnHyperItem* ohi; laUDFRegistry* r;
-    for(laPropContainer* pc=MAIN.PropContainers.pFirst;pc;pc=pc->Item.pNext){
-        while(ohi=lstPopItem(&pc->ResourceRegistry)) memFree(ohi);
-    }
+    while(ohi=lstPopItem(&MAIN.UDFResources)) memFree(ohi);
     while(r=lstPopItem(&MAIN.ResourceRegistries)){
         strSafeDestroy(&r->Path); memFree(r);
     }
 }
+void laGetSubResourceDirectories(char* rootpath_with_slash, laListHandle* out){
+    laSafeString*s=0; strSafePrint(&s, "%sUDFExtra/", rootpath_with_slash); lstAppendPointer(out,s); 
+    char Final[1024];
+    sprintf(Final, "%s.udfextra",rootpath_with_slash);
+    FILE* f=fopen(Final, "r"); if(!f){ return; }
+    char dir[1024];
+    while(fgets(dir,1024,f)){ laSafeString*s=0; strSafePrint(&s, "%s%s/", rootpath_with_slash, dir); lstAppendPointer(out,s); }
+    fclose(f);
+}
+void laRefreshUDFResourcesIn(char* rootpath){
+    char Final[1024];
+    int len=strlen(rootpath);
+    if (rootpath[len - 1] != '/') strcat(rootpath, "/");
+
+    struct dirent **NameList;
+    int NumFiles=scandir(rootpath,&NameList,0,alphasort);
+
+    for(int i=0;i<NumFiles;i++){
+        struct dirent* d = NameList[i]; int dlen;
+        if((dlen=strlen(d->d_name))<=4 || strcmp(&d->d_name[dlen-4], ".udf")){continue;}
+        struct stat s;
+        sprintf(Final, "%s%s",rootpath,d->d_name);
+        stat(Final, &s);
+        if (!S_ISDIR(s.st_mode)){
+            if(!laFindUDFRegistry(Final)){
+                laUDFRegistry* r = laCreateUDFRegistry(Final);
+                laUDF* udf = laOpenUDF(Final, 0, r, 0);
+                if(udf) laCloseUDF(udf);
+            }
+        }
+    }
+    for (int i=0;i<NumFiles;i++){ free(NameList[i]); }
+
+    if(NumFiles>=0){
+        laListHandle additionals={0}; laSafeString* s;
+        laGetSubResourceDirectories(rootpath, &additionals);
+        while(s=lstPopPointer(&additionals)){ laRefreshUDFResourcesIn(s->Ptr); strSafeDestroy(&s); }
+    }
+}
 void laRefreshUDFRegistries(){
     laClearUDFRegistries();
-    char LookupM[1024],Final[1024];
+    char LookupM[1024];
     for(laResourceFolder* rf = MAIN.ResourceFolders.pFirst;rf;rf=rf->Item.pNext){
         if(!rf->Path) continue;
         realpath(rf->Path->Ptr, LookupM);
-        int len=strlen(LookupM);
-        if (LookupM[len - 1] != '/') strcat(LookupM, "/");
-
-        struct dirent **NameList;
-        int NumFiles=scandir(LookupM,&NameList,0,alphasort);
-
-        for(int i=0;i<NumFiles;i++){
-            struct dirent* d = NameList[i]; int dlen;
-            if((dlen=strlen(d->d_name))<=4 || strcmp(&d->d_name[dlen-4], ".udf")){continue;}
-            struct stat s;
-            sprintf(Final, "%s%s",LookupM,d->d_name);
-            stat(Final, &s);
-            if (!S_ISDIR(s.st_mode)){
-                if(!laFindUDFRegistry(Final)){
-                    laUDFRegistry* r = laCreateUDFRegistry(Final);
-                    laUDF* udf = laOpenUDF(Final, 0, r, 0);
-                    if(udf) laCloseUDF(udf);
-                }
-            }
-        }        
-        for (int i=0;i<NumFiles;i++){ free(NameList[i]); }
+        laRefreshUDFResourcesIn(LookupM);
     }
 }
 
-void la_FindAndExtractUDFContentNode(laUDF *udf, laManagedUDF* mUDF, int Mode, laUDFContentNode *ContentNode){
-    laUDFContentNode *ucn, *ucn2;
-    laUDFContentInstance *uci;
-    laDBInst *dbi = 0;
-
-    if (!udf || !ContentNode) return 0;
-
-    ucn = ContentNode;
-    la_StepPropPack(&ucn->PP);
-
-    la_Seek(udf, ucn->FileSeek);
-    dbi = ucn->PP.EndInstance; //la_GetWriteDBInst(ucn->PP.EndInstance);
-    la_ExtractProp(udf, mUDF, &ucn->PP, dbi, Mode, 0);
-    
-}
-int laExtractUDFContent(laUDF *udf, laManagedUDF* mUDF, int Mode, laListHandle *ContentNodes){
-    laUDFContentNode *ucn;
-    laUDFContentInstance *uci;
-    if (!udf || !ContentNodes) return 0;
-
-    for (ucn = ContentNodes->pFirst; ucn; ucn = ucn->Item.pNext){
-        la_FindAndExtractUDFContentNode(udf, mUDF, Mode, ucn);
-    }
-
-    la_RematchPointers(Mode);
-
-    return 1;
-}
-
 void laStopManageUDF(laManagedUDF* m){
     if(!m) return;
     lstRemoveItem(&MAIN.ManagedUDFs,m);
@@ -3676,12 +3691,13 @@ void laPushDifferences(char* Description, u64bit hint){
 }
 
 void la_FreeInstance(void* inst, laPropContainer* pc, int no_free);
-void la_FreeDBInst(laDBInst* dbi);
+void la_FreeDBInst(laDBInst* dbi, int no_freeinst);
 void la_FreeDBProp(laDBProp* dbp){
     if(dbp->p->PropertyType==LA_PROP_SUB){
-        if((((laSubProp*)dbp->p)->ListHandleOffset||dbp->p->UDFNoCreate||dbp->p->UDFIsSingle)){
+        if((((laSubProp*)dbp->p)->ListHandleOffset||dbp->p->UDFNoCreate||dbp->p->UDFIsSingle)&&(!dbp->p->UDFIsRefer)){
             laDBSubProp* dsp=dbp; laDBInst* si;
-            while(si=lstPopItem(&dsp->Instances)){ la_FreeDBInst(si); }
+            //printf("fdbp %s %x\n",dbp->p->Identifier,dsp->Instances.pFirst);
+            while(si=lstPopItem(&dsp->Instances)){ la_FreeDBInst(si,dbp->p->UDFNoCreate||(!dbp->p->OffsetIsPointer)); }
         } // prevent freeing the data;
     }elif(dbp->p->PropertyType==LA_PROP_STRING && ((laStringProp*)dbp->p)->IsSafeString){
         strSafeSet(&dbp->Data,0);
@@ -3691,16 +3707,17 @@ void la_FreeDBProp(laDBProp* dbp){
     }
     memFree(dbp);
 }
-void la_FreeDBInst(laDBInst* dbi){
+void la_FreeDBInst(laDBInst* dbi, int no_freeinst){
     laListHandle* l=hsh65536DoHashLongPtr(MAIN.DBInstLink,dbi->OriginalInstance); lstRemoveItem(l, &dbi->Item2);
     laDBProp* dbp; while(dbp=lstPopItem(&dbi->Props)){ la_FreeDBProp(dbp); }
-    if(dbi->OriginalInstance) la_FreeInstance(dbi->OriginalInstance, dbi->pc, 0);
+    if(dbi->OriginalInstance) la_FreeInstance(dbi->OriginalInstance, dbi->pc, no_freeinst);
     memFree(dbi);
 }
 void la_FreeDiffCommand(laDiffCommand* dc, laDiff* d){
-    if(dc->p->PropertyType==LA_PROP_SUB && (((laSubProp*)dc->p)->ListHandleOffset||dc->p->UDFNoCreate||dc->p->UDFIsSingle)){
+    printf("freedc %s\n",dc->p->Identifier);
+    if(dc->p->PropertyType==LA_PROP_SUB && (((laSubProp*)dc->p)->ListHandleOffset||dc->p->UDFNoCreate||dc->p->UDFIsSingle) && (!dc->p->UDFIsRefer)){
         laDiffCommandInst* dci; laDiffCommandSub* dcs=dc;
-        while(dci=lstPopItem(&dcs->AddedInst)){ la_FreeDBInst(dci->DBInst); memFree(dci); }
+        while(dci=lstPopItem(&dcs->AddedInst)){ la_FreeDBInst(dci->DBInst,(dc->p->UDFNoCreate||(!dc->p->OffsetIsPointer))); memFree(dci); }
         while(dci=lstPopItem(&dcs->MovedInst)){ memFree(dci); }
         while(dci=lstPopItem(&dcs->RemovedInst)){ dci->DBInst->DeletedDiff = 0; memFree(dci); }
     }elif(dc->p->PropertyType==LA_PROP_STRING && ((laStringProp*)dc->p)->IsSafeString){
@@ -3731,7 +3748,8 @@ void la_FreeAllDifferences(){
 }
 void la_NoLongerRecordUndo(){
     la_FreeAllDifferences();
-    laDBProp*dbp; while(dbp=lstPopItem(&MAIN.RootDBInst.Props)){ la_FreeDBProp(dbp); }
+    // XXX we need to have la_FreeOlderDifferences() before this that way the DBInst tree is consistent and then we won't have double free.
+    //laDBProp*dbp; while(dbp=lstPopItem(&MAIN.RootDBInst.Props)){ la_FreeDBProp(dbp); }
     laDBRecordedProp* p; while(p=lstPopItem(&MAIN.DBRecordedProps)){ strSafeDestroy(&p->OriginalPath); memFree(p); }
     hshFree(&MAIN.DBInstLink);
 }
@@ -4084,23 +4102,26 @@ void la_FreeInstance(void* inst, laPropContainer* pc, int no_free){
     //if(p->PropertyType!=LA_PROP_SUB) return;
     //if(!p->SubProp || ((laSubProp*)p)->TargetID) p->SubProp=la_ContainerLookup(((laSubProp*)p)->TargetID);
     //laPropContainer* pc=p->SubProp; if(((laSubProp*)p)->GetType) pc=((laSubProp*)p)->GetType(inst);
+    printf("freeinst %s %x\n",pc->Name,inst);
     if(pc->BeforeFree) pc->BeforeFree(inst);
     laPropStep SubPS = {0}; laPropPack SubPP = {0}; laPropIterator pi={0}; SubPP.LastPs=&SubPS; 
     for(laProp* p=pc->Props.pFirst;p;p=p->Item.pNext){
         if(p->PropertyType==LA_PROP_STRING && ((laStringProp*)p)->IsSafeString){ SubPS.p=p; SubPS.UseInstance=inst; laSetString(&SubPP, 0); continue; }
-        if(p->PropertyType!=LA_PROP_SUB || p->UDFIsRefer) continue;
-        void* si = laGetInstance(p, SubPP.LastPs->UseInstance, &pi); SubPP.EndInstance = si; void* NextSi=0;
-        while (si){
-            NextSi = laGetNextInstance(p, si, &pi);
-            if(!p->UDFNoCreate){ laSubProp* sp=p;
-                if(!sp->ListHandleOffset){ logPrint("[WARN] prop '%s' UDFNoCreate==0 and no ListHandleOffset. Node not removed.\n", p->Identifier); }
-                else{ lstRemoveItem(inst + sp->ListHandleOffset, si); }
-            }
-            la_FreeInstance(si, p, p->UDFNoCreate);
-            si=NextSi; SubPP.EndInstance = si;
-        }
-    }
-    if(!no_free) memFree(inst);
+        //if(p->PropertyType!=LA_PROP_SUB || p->UDFIsRefer) continue;
+        //void* si = laGetInstance(p, SubPP.LastPs->UseInstance, &pi); SubPP.EndInstance = si; void* NextSi=0;
+        //printf("freeinst p %s\n",p->Name);
+        //while (si){
+        //    printf("%x --inst %x\n",SubPP.LastPs->UseInstance,si);
+        //    NextSi = laGetNextInstance(p, si, &pi);
+        //    if(!p->UDFNoCreate){ laSubProp* sp=p;
+        //        if(!sp->ListHandleOffset){ logPrint("[WARN] prop '%s' UDFNoCreate==0 and no ListHandleOffset. Node not removed.\n", p->Identifier); }
+        //        else{ lstRemoveItem(inst + sp->ListHandleOffset, si); }
+        //    }
+        //    la_FreeInstance(si, p, p->UDFNoCreate||(!p->OffsetIsPointer));
+        //    si=NextSi; SubPP.EndInstance = si;
+        //}
+    }
+    if(!no_free && !pc->OtherAlloc) memFree(inst);
 }
 void la_ResetInstance(void* inst, laPropContainer* pc){ memset(inst,0,pc->NodeSize); }
 

+ 0 - 2
source/lagui/la_data.h

@@ -131,7 +131,6 @@ STRUCTURE(laPropContainer){
     laListHandle FailedNodes;
     laListHandle TrashBin;
     laListHandle LocalUsers;
-    laListHandle ResourceRegistry;
 
     int validated;
 };
@@ -855,7 +854,6 @@ int laRegisterModifications(int ReturnIfAnyMod, int ReturnIfAnyEmpty, int* rempt
 laUDF *laOpenUDF(char *FileName, int ReadToMemory, laUDFRegistry* ReadRegistryRef, laManagedUDF** UseManaged);
 void laCloseUDF(laUDF *udf);
 int laExtractUDF(laUDF *udf, laManagedUDF* mUDF, int Mode, laListHandle *Parent);
-int laExtractUDFContent(laUDF *udf, laManagedUDF* mUDF, int Mode, laListHandle *ContentNodes);
 
 laUDFOwnHyperItem* laFindHyperItem(laPropContainer* pc, char* uid);
 laUDFRegistry* laFindUDFRegistry(char* Path);

+ 4 - 1
source/lagui/la_interface.h

@@ -296,13 +296,16 @@ STRUCTURE(LA){
     laHash16M DBInst2;
     laHash16M DBInst1;
     laHash16M PtrSync;
-    laListHandle PtrSyncCommandList;
+    laListHandle PtrSyncAddressCommands;
+    laListHandle PtrSyncHyper2Commands;
     laListHandle PostReadNodes;
     laListHandle RenewHyper2s;
     laListHandle SharedTypePointerSync;
 
+    laListHandle PendingResourceRequests;
     laListHandle ResourceFolders;
     laListHandle ResourceRegistries;
+    laListHandle UDFResources;
     laListHandle ManagedUDFs;
     laListHandle ManagedSaveProps;
     laManagedUDF* DummyManageUDF;

+ 9 - 8
source/lagui/la_kernel.c

@@ -2154,7 +2154,7 @@ void laDestroySinglePanel(laPanel *p){
 
     if (p->PropLinkPP.LastPs->p->SubProp->Props.pFirst){
         for(laProp* prop=p->PropLinkPP.LastPs->p->SubProp->Props.pFirst;prop;prop=prop->Item.pNext){
-            la_StopUsingPropPack(&prop->DetachedPP);
+            { /* la_StopUsingPropPack(&prop->DetachedPP); */ }
             //laStopUsingDataBlock(prop->DetachedPP.LastPs->UseInstance, prop->DetachedPP.LastPs->p,MAIN.PropMatcherContextP);
         }
     }
@@ -3778,10 +3778,10 @@ void la_DestroyUiItem(laUiItem *ui, int RemoveUsers){
         la_DestroyUiList(uil, 0, RemoveUsers, 0);
     }
     la_StopUiOperatorService(ui);
-    strSafeDestroy(&ui->ExtraInstructions);
+    strSafeDestroy(&ui->ExtraInstructions);strDestroyStringSplitor(&ui->Instructions);
     strSafeDestroy(&ui->Display);
     if (RemoveUsers && ui->PP.LastPs && ui->PP.LastPs->p->Container->Hyper)
-        la_StopUsingPropPack(&ui->PP);
+        { /*la_StopUsingPropPack(&ui->PP);*/ }
         //laStopUsingDataBlock(ui->PP.LastPs->UseInstance,ui->PP.LastPs->p,MAIN.PropMatcherContextP);
     la_FreePropStepCache(ui->PP.Go); //-------[Up Here], instance already been freed.XXXXXXXXXXXX!!!!!!!!!!1
     if (ui->Type->Destroy) ui->Type->Destroy(ui);
@@ -3795,7 +3795,7 @@ void la_DestroyUiList(laUiList *uil, int NoFree, int RemoveUsers, int OnlyRemove
         NextUi = ui->Item.pNext;
         if(OnlyRemoveUser && RemoveUsers){
             if (ui->PP.LastPs && ui->PP.LastPs->p->Container->Hyper)
-                la_StopUsingPropPack(&ui->PP);
+                { /*la_StopUsingPropPack(&ui->PP);*/ }
                 //laStopUsingDataBlock(ui->PP.LastPs->UseInstance,ui->PP.LastPs->p,MAIN.PropMatcherContextP);
             continue;
         }
@@ -4993,7 +4993,8 @@ laUiItem *la_DetectUiItemRecursive(laUiList *uil, int x, int y, int LimB, laList
 
         //printf("%s > ",ui->Type->Identifier?ui->Type->Identifier:"-");
 
-        if (ui->Type != _LA_UI_COLLECTION && ui->Type != _LA_UI_FIXED_GROUP && ui->Type != _LA_UI_TAB && ui->Type != _LA_UI_CANVAS && laIsInUiItem(ui, x, y)){
+        if (ui->Type != _LA_UI_COLLECTION && ui->Type != _LA_UI_COLLECTION_SINGLE &&
+            ui->Type != _LA_UI_FIXED_GROUP && ui->Type != _LA_UI_TAB && ui->Type != _LA_UI_CANVAS && laIsInUiItem(ui, x, y)){
             int Add=1; if(ui->Type==_LA_UI_COLUMN_ADJUSTER){
                 if(!la_DetectSplit(ui->C, x)) Add=0;
             }
@@ -5012,7 +5013,7 @@ laUiItem *la_DetectUiItemRecursive(laUiList *uil, int x, int y, int LimB, laList
                 lstAppendPointer(LocalBuf, uil);return ui;
             }
         }
-        if (ui->Type == _LA_UI_COLLECTION){
+        if (ui->Type == _LA_UI_COLLECTION || ui->Type==_LA_UI_COLLECTION_SINGLE){
             if (laIsInUiItem(ui, x, y)){
                 lstAppendPointer(LocalBuf, uil);
                 if (ui->Subs.pFirst) ((laUiList *)ui->Subs.pFirst)->HeightCoeff = LimB;
@@ -5052,7 +5053,7 @@ laUiItem *la_DetectSocketRecursive(laUiList* uil, int x, int y, int LimB, laProp
     laListHandle Locals={0};
     laUiItem* ui=la_DetectUiItemRecursive(uil, x,y,LimB,&Locals, 1);
     while(lstPopPointer(&Locals));
-    //printf("%s\n", ui?ui->Type->Identifier:"?");
+    printf("%s\n", ui?ui->Type->Identifier:"?");
     if(ui && ui->Type==_LA_UI_NODE_SOCKET){
         laProp* p=ui->PP.LastPs->p; laPropContainer* pc=la_EnsureSubTarget(p,0);
         if(pc==PCInOrOut) return ui;
@@ -5443,7 +5444,7 @@ laOperator *la_CreateOperator(laOperatorType *at){
 
     if (at->PC && at->PC->Props.pFirst){
         a->PP.LastPs = memAcquireSimple(sizeof(laPropStep));
-        a->PP.LastPs->p = memAcquire(sizeof(laProp));
+        a->PP.LastPs->p = memAcquire(sizeof(laSubProp));
         a->PP.LastPs->p->SubProp = at->PC;
         a->PP.LastPs->p->PropertyType = LA_PROP_SUB;
         a->PP.LastPs->p->Identifier = at->PC->Identifier;

+ 1 - 1
source/lagui/la_resource.c

@@ -80,7 +80,7 @@ void la_RegisterMainUiTypes(){
 
 void la_RegisterWindowKeys(){
     laKeyMapper* km=&MAIN.KeyMap;
-    laAssignNewKey(km, 0, "LA_udf_append", 0, LA_KEY_CTRL, LA_KEY_DOWN, 'o', 0);
+    laAssignNewKey(km, 0, "LA_udf_read", 0, LA_KEY_CTRL, LA_KEY_DOWN, 'o', 0);
     laAssignNewKey(km, 0, "LA_managed_save", 0, LA_KEY_CTRL, LA_KEY_DOWN, 's', "quiet=true;");
     laAssignNewKey(km, 0, "LA_managed_save", 0, LA_KEY_CTRL|LA_KEY_SHIFT, LA_KEY_DOWN, 's', 0);
     laAssignNewKey(km, 0, "LA_manage_udf", 0, LA_KEY_SHIFT, LA_KEY_DOWN, 'r', 0);

+ 5 - 1
source/lagui/la_tns.h

@@ -276,6 +276,7 @@ struct _tnsTexture
     int Multisample;
     int Width;
     int Height;
+    int Slices;
 
     void *DrawData;
 
@@ -838,6 +839,7 @@ STRUCTURE(tnsEdgeHash){
 void tnsSetuptnsFontManager();
 
 tnsShader *tnsNewShaderProgram(int VertexShaderID, int FragmentShaderID, int GeometryShaderID);
+int tnsNewGeometryShader(char *Content);
 int tnsNewFragmentShader(char *Content);
 int tnsNewVertexShader(char *Content);
 void tnsDeleteShaderProgram(tnsShader* s);
@@ -1119,7 +1121,9 @@ int tnsGetTextureMemoryComponetCount(tnsTexture *t);
 
 int tnsInit2DTexture(tnsTexture *t, GLint glInternalFormat, int w, int h, int Multisample);
 tnsTexture *tnsCreate2DTexture(GLint glInternalFormat, int w, int h, int Multisample);
-void tnsConfigureTexture(tnsTexture *t);
+tnsTexture *tnsCreate3DTexture(GLint glInternalFormat, int w, int h, int slices);
+void tnsConfigure2DTexture(tnsTexture *t);
+void tnsConfigure3DTexture(tnsTexture *t);
 void tnsReconfigureTextureParameters(int Multisample);
 tnsOffscreen *tnsCreate2DOffscreen(int glInternalFormat, int w, int h, int Multisample, int WithDepth);
 void tnsCopyScreenTo2DTexture(tnsTexture *target, int x_lower_left, int y_lower_left, int w, int h);

+ 39 - 9
source/lagui/la_tns_kernel.c

@@ -1702,7 +1702,7 @@ int tnsInit2DTexture(tnsTexture *t, GLint glInternalFormat, int w, int h, int Mu
         t->Multisample = Multisample;
         glGenRenderbuffers(1, &t->GLTexHandle);
         
-        tnsConfigureTexture(t);
+        tnsConfigure2DTexture(t);
     }else{
         t->Width = w;
         t->Height = h;
@@ -1711,13 +1711,23 @@ int tnsInit2DTexture(tnsTexture *t, GLint glInternalFormat, int w, int h, int Mu
         t->Multisample = Multisample;
         glGenTextures(1, &t->GLTexHandle);
 
-        tnsConfigureTexture(t);
+        tnsConfigure2DTexture(t);
     }
 
     return 1;
 }
+int tnsInit3DTexture(tnsTexture *t, GLint glInternalFormat, int w, int h, int slices){
+    if (!t) return 0;
+    t->Width = w;
+    t->Height = h;
+    t->GLTexBitsType = glInternalFormat;
+    t->GLTexType = GL_TEXTURE_3D;
+    glGenTextures(1, &t->GLTexHandle);
+    tnsConfigure3DTexture(t);
+    return 1;
+}
 
-void tnsConfigureTexture(tnsTexture *t){
+void tnsConfigure2DTexture(tnsTexture *t){
     tnsBindTexture(t);
     if(t->GLTexType==GL_RENDERBUFFER){
         if(t->Multisample){ glRenderbufferStorageMultisample(GL_RENDERBUFFER, t->Multisample, t->GLTexBitsType, t->Width, t->Height); }
@@ -1737,6 +1747,17 @@ void tnsConfigureTexture(tnsTexture *t){
     }
     tnsUnbindTexture(t);
 }
+void tnsConfigure3DTexture(tnsTexture *t){
+    tnsBindTexture(t);
+    glTexImage3D(GL_TEXTURE_3D, 0, t->GLTexBitsType, t->Width, t->Height, t->Slices, 0, GL_RGBA, GL_FLOAT, 0);
+        glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP);
+        glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP);
+        glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP);
+        glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+        glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+        //glTexEnvi(GL_TEXTURE_2D, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+    tnsUnbindTexture(t);
+}
 
 void tnsReconfigureTextureParameters(int Multisample){
     laListHandle* l = tKnlGetTextureList();
@@ -1752,13 +1773,13 @@ void tnsReconfigureTextureParameters(int Multisample){
                 glGenTextures(1, &t->GLTexHandle);
                 T->TexColor=0;
             }
-            tnsConfigureTexture(t);
+            tnsConfigure2DTexture(t);
             tnsAttach2DOffscreenBuffer(o, GL_COLOR_ATTACHMENT0, t);
         }
         t=o->pDepth;
         if(t){
             t->Multisample = Multisample;
-            tnsConfigureTexture(t);
+            tnsConfigure2DTexture(t);
             tnsAttach2DOffscreenBuffer(o, GL_DEPTH_ATTACHMENT, t);
         }
     }
@@ -1771,6 +1792,13 @@ tnsTexture *tnsCreate2DTexture(GLint glInternalFormat, int w, int h, int Multisa
     lstAppendItem(tKnlGetTextureList(), tex);
     return tex;
 };
+tnsTexture *tnsCreate3DTexture(GLint glInternalFormat, int w, int h, int slices){
+    tnsTexture *tex = CreateNew(tnsTexture);
+    tnsInit3DTexture(tex, glInternalFormat, w, h, slices);
+    laNotifyUsers("tns.texture_list");
+    lstAppendItem(tKnlGetTextureList(), tex);
+    return tex;
+};
 void tnsCopyScreenTo2DTexture(tnsTexture *target, int x_lower_left, int y_lower_left, int w, int h){
     if(target->GLTexType!=GL_TEXTURE_2D) return;
     tnsBindTexture(target);
@@ -1802,14 +1830,16 @@ void tnsActiveTexture(GLenum tex){
 void tnsBindTexture(tnsTexture *t){
     if (!t || T->TexColor==t) return;
     if(t->GLTexType == GL_TEXTURE_2D){ tnsActiveTexture(GL_TEXTURE0); glBindTexture(t->GLTexType, t->GLTexHandle); T->TexColor=t;}
-    else if(t->GLTexType == GL_TEXTURE_2D_MULTISAMPLE){ tnsActiveTexture(GL_TEXTURE1); glBindTexture(t->GLTexType, t->GLTexHandle); T->TexColor=t;}
-    else if(t->GLTexType == GL_RENDERBUFFER){ glBindRenderbufferEXT(GL_RENDERBUFFER, t->GLTexHandle); T->TexRenderbuffer = t;}
+    elif(t->GLTexType == GL_TEXTURE_2D_MULTISAMPLE){ tnsActiveTexture(GL_TEXTURE1); glBindTexture(t->GLTexType, t->GLTexHandle); T->TexColor=t;}
+    elif(t->GLTexType == GL_RENDERBUFFER){ glBindRenderbufferEXT(GL_RENDERBUFFER, t->GLTexHandle); T->TexRenderbuffer = t;}
+    elif(t->GLTexType == GL_TEXTURE_3D){ tnsActiveTexture(GL_TEXTURE0); glBindTexture(t->GLTexType, t->GLTexHandle); T->TexColor=t;}
 }
 void tnsUnbindTexture(){
     if(T->TexRenderbuffer){ if(T->TexRenderbuffer->GLTexType == GL_RENDERBUFFER){ glBindRenderbufferEXT(GL_RENDERBUFFER, 0); T->TexRenderbuffer=0;}}
     if(T->TexColor){
         if(T->TexColor->GLTexType == GL_TEXTURE_2D){tnsActiveTexture(GL_TEXTURE0);}
         else if(T->TexColor->GLTexType == GL_TEXTURE_2D_MULTISAMPLE){tnsActiveTexture(GL_TEXTURE1);}
+        else if(T->TexColor->GLTexType == GL_TEXTURE_3D){tnsActiveTexture(GL_TEXTURE0);}
         glBindTexture(T->TexColor->GLTexType, 0); T->TexColor=0;
     }
 }
@@ -2439,10 +2469,10 @@ tnsOffscreen *tnsCreate2DOffscreen(int glInternalFormat, int w, int h, int Multi
 
 void tnsConfigureOffscreen(tnsOffscreen *off, int w, int h){
     tnsTexture* t=off->pColor[0];
-    t->Width = w; t->Height = h; tnsConfigureTexture(t);
+    t->Width = w; t->Height = h; tnsConfigure2DTexture(t);
     t=off->pDepth;
     if(t){
-        t->Width = w; t->Height = h; tnsConfigureTexture(t);
+        t->Width = w; t->Height = h; tnsConfigure2DTexture(t);
     }
 }
 

+ 3 - 3
source/lagui/la_util.c

@@ -71,7 +71,7 @@ void laSetAuthorInfo(char *Name, char *CopyrightString){
 }
 
 void memCreateNUID(laMemNodeHyper* hi){
-    sprintf(hi->NUID.String, "%hd%02hd%02hd%02hd%02hd%02hd%08X", LA_HYPER_CREATED_TIME(hi), hi);
+    sprintf(hi->NUID.String, "%08X-%hd%02hd%02hd%02hd%02hd%02hd", hi, LA_HYPER_CREATED_TIME(hi));
 }
 
 void memHyperInfo(laPropPack* pp, char* buf){
@@ -1168,7 +1168,7 @@ void *memStaticDestroy(laStaticMemoryPool *smp){
 }
 
 void la_ReferencedBlockDeleted(void* This, laItemUserLinker* iul){
-    void** user=iul->Pointer.p; (*user)=0;
+    void** user=iul->Pointer.p; (*user)=0; laStopUsingDataBlock(iul->Additional, 0, This);
 }
 void la_ReferrerDeleted(void* This, laItemUserLinker* iul){
     void* instance=iul->Pointer.p; if(instance!=This){ laStopUsingDataBlock(instance, 0, This); }
@@ -1177,7 +1177,7 @@ void memAssignRef(void* This, void** ptr, void* instance){
     laItemUserLinker* iul;
     if(!This||!ptr) return;
     if(instance){
-        laUseDataBlock(instance, 0, 0, ptr, la_ReferencedBlockDeleted, 0);
+        laUseDataBlock(instance, 0, 0, ptr, la_ReferencedBlockDeleted, 0)->Additional=This;
         laUseDataBlock(This, 0, 0, instance, la_ReferrerDeleted, 0);
     }else{
         laStopUsingDataBlock(instance, 0, This);

+ 1 - 0
source/lagui/la_util.h

@@ -125,6 +125,7 @@ struct _laItemUserLinker {
 	laListItemPointer Pointer;
 	laUserRemoveFunc  Remove;
 	laProp*           Which;
+	void*             Additional;
 	unsigned int      FrameDistinguish;
 	int               ForceRecalc;
 };

+ 2 - 13
source/lagui/resources/la_operators.c

@@ -378,23 +378,12 @@ int OPINV_UDFAppend(laOperator *a, laEvent *e){
 }
 int OPMOD_UDFAppend(laOperator *a, laEvent *e){
     laUDFPreviewExtra *upe = a->CustomData;
-    //if (upe->UDF){
-    //    if (!a->OperatorPanel){
-    //        printf("Execute!\n");
-    //        laExtractUDFContent(upe->UDF, 0, &upe->ContentNodes);
-    //        laCloseUDF(upe->UDF);
-    //        return LA_FINISHED;
-    //    }
-    //    return LA_RUNNING;
-    //}
     if (a->ConfirmData){
         if (a->ConfirmData->StrData){
             laManagedUDF* m;
             upe->UDF = laOpenUDF(a->ConfirmData->StrData, 1, 0, &m);
             if (upe->UDF){
-                laExtractUDF(upe->UDF, m, 0, 0);
-                //laExtractUDFContent(upe->UDF, 0, &upe->ContentNodes);
-                //laEnableOperatorPanel(a, 0, 30, 100, 500, 500, 10000, 10000, 300, 200, 20, 20, 30, 20, e);
+                laExtractUDF(upe->UDF, m, LA_UDF_MODE_OVERWRITE, 0);
                 laCloseUDF(upe->UDF);
                 laRecordEverythingAndPush();
                 return LA_FINISHED;
@@ -1976,7 +1965,7 @@ void la_RegisterBuiltinOperators(){
         }
     }
 
-    at = laCreateOperatorType("LA_udf_append", "Append", "Append A UDF Data Block", 0, 0, OPEXT_UDFOperation, OPINV_UDFAppend, OPMOD_UDFAppend, L'📑', LA_ACTUATOR_SYSTEM);
+    at = laCreateOperatorType("LA_udf_read", "Read", "Read a UDF file", 0, 0, OPEXT_UDFOperation, OPINV_UDFAppend, OPMOD_UDFAppend, L'📑', LA_ACTUATOR_SYSTEM);
     pc = laDefineOperatorProps(at, 0);
     at->UiDefine = laui_LinkerPanel;
     laAddSubGroup(pc, "root_nodes", "UDF Nodes", "List Of All Linkable/Appendable Nodes In The File", "udf_content_node",0, 0, laui_LinkerSelectionProp, -1, 0, 0, 0, 0, 0, 0, offsetof(laUDFPreviewExtra, ContentNodes), 0);

+ 1 - 1
source/lagui/resources/la_templates.c

@@ -480,7 +480,7 @@ void laui_DefaultMenuBarActual(laUiList *uil, laPropPack *pp, laPropPack *actins
             laShowLabel(muil, mc, "Function Test", 0, 0);
             laShowItem(muil, mc, 0, "LA_pure_yes_no");
             laShowItem(muil, mc, 0, "LA_file_dialog");
-            laShowItem(muil, mc, 0, "LA_udf_append");
+            laShowItem(muil, mc, 0, "LA_udf_read");
             laShowItem(muil, mc, 0, "LA_managed_save");
             laShowItem(muil, mc, 0, "LA_manage_udf");
 

+ 537 - 0
source/lagui/resources/la_tns_als.c

@@ -0,0 +1,537 @@
+#include "la_5.h"
+
+
+const int TRANSMITTANCE_TEXTURE_WIDTH = 256;
+const int TRANSMITTANCE_TEXTURE_HEIGHT = 64;
+
+const int SCATTERING_TEXTURE_R_SIZE = 32;
+const int SCATTERING_TEXTURE_MU_SIZE = 128;
+const int SCATTERING_TEXTURE_MU_S_SIZE = 32;
+const int SCATTERING_TEXTURE_NU_SIZE = 8;
+
+const int SCATTERING_TEXTURE_WIDTH =
+    SCATTERING_TEXTURE_NU_SIZE * SCATTERING_TEXTURE_MU_S_SIZE;
+const int SCATTERING_TEXTURE_HEIGHT = SCATTERING_TEXTURE_MU_SIZE;
+const int SCATTERING_TEXTURE_DEPTH = SCATTERING_TEXTURE_R_SIZE;
+
+const int IRRADIANCE_TEXTURE_WIDTH = 64;
+const int IRRADIANCE_TEXTURE_HEIGHT = 16;
+
+// The conversion factor between watts and lumens.
+const double MAX_LUMINOUS_EFFICACY = 683.0;
+
+// Values from "CIE (1931) 2-deg color matching functions", see
+// "http://web.archive.org/web/20081228084047/
+//    http://www.cvrl.org/database/data/cmfs/ciexyz31.txt".
+const double CIE_2_DEG_COLOR_MATCHING_FUNCTIONS[380] = {
+  360, 0.000129900000, 0.000003917000, 0.000606100000,
+  365, 0.000232100000, 0.000006965000, 0.001086000000,
+  370, 0.000414900000, 0.000012390000, 0.001946000000,
+  375, 0.000741600000, 0.000022020000, 0.003486000000,
+  380, 0.001368000000, 0.000039000000, 0.006450001000,
+  385, 0.002236000000, 0.000064000000, 0.010549990000,
+  390, 0.004243000000, 0.000120000000, 0.020050010000,
+  395, 0.007650000000, 0.000217000000, 0.036210000000,
+  400, 0.014310000000, 0.000396000000, 0.067850010000,
+  405, 0.023190000000, 0.000640000000, 0.110200000000,
+  410, 0.043510000000, 0.001210000000, 0.207400000000,
+  415, 0.077630000000, 0.002180000000, 0.371300000000,
+  420, 0.134380000000, 0.004000000000, 0.645600000000,
+  425, 0.214770000000, 0.007300000000, 1.039050100000,
+  430, 0.283900000000, 0.011600000000, 1.385600000000,
+  435, 0.328500000000, 0.016840000000, 1.622960000000,
+  440, 0.348280000000, 0.023000000000, 1.747060000000,
+  445, 0.348060000000, 0.029800000000, 1.782600000000,
+  450, 0.336200000000, 0.038000000000, 1.772110000000,
+  455, 0.318700000000, 0.048000000000, 1.744100000000,
+  460, 0.290800000000, 0.060000000000, 1.669200000000,
+  465, 0.251100000000, 0.073900000000, 1.528100000000,
+  470, 0.195360000000, 0.090980000000, 1.287640000000,
+  475, 0.142100000000, 0.112600000000, 1.041900000000,
+  480, 0.095640000000, 0.139020000000, 0.812950100000,
+  485, 0.057950010000, 0.169300000000, 0.616200000000,
+  490, 0.032010000000, 0.208020000000, 0.465180000000,
+  495, 0.014700000000, 0.258600000000, 0.353300000000,
+  500, 0.004900000000, 0.323000000000, 0.272000000000,
+  505, 0.002400000000, 0.407300000000, 0.212300000000,
+  510, 0.009300000000, 0.503000000000, 0.158200000000,
+  515, 0.029100000000, 0.608200000000, 0.111700000000,
+  520, 0.063270000000, 0.710000000000, 0.078249990000,
+  525, 0.109600000000, 0.793200000000, 0.057250010000,
+  530, 0.165500000000, 0.862000000000, 0.042160000000,
+  535, 0.225749900000, 0.914850100000, 0.029840000000,
+  540, 0.290400000000, 0.954000000000, 0.020300000000,
+  545, 0.359700000000, 0.980300000000, 0.013400000000,
+  550, 0.433449900000, 0.994950100000, 0.008749999000,
+  555, 0.512050100000, 1.000000000000, 0.005749999000,
+  560, 0.594500000000, 0.995000000000, 0.003900000000,
+  565, 0.678400000000, 0.978600000000, 0.002749999000,
+  570, 0.762100000000, 0.952000000000, 0.002100000000,
+  575, 0.842500000000, 0.915400000000, 0.001800000000,
+  580, 0.916300000000, 0.870000000000, 0.001650001000,
+  585, 0.978600000000, 0.816300000000, 0.001400000000,
+  590, 1.026300000000, 0.757000000000, 0.001100000000,
+  595, 1.056700000000, 0.694900000000, 0.001000000000,
+  600, 1.062200000000, 0.631000000000, 0.000800000000,
+  605, 1.045600000000, 0.566800000000, 0.000600000000,
+  610, 1.002600000000, 0.503000000000, 0.000340000000,
+  615, 0.938400000000, 0.441200000000, 0.000240000000,
+  620, 0.854449900000, 0.381000000000, 0.000190000000,
+  625, 0.751400000000, 0.321000000000, 0.000100000000,
+  630, 0.642400000000, 0.265000000000, 0.000049999990,
+  635, 0.541900000000, 0.217000000000, 0.000030000000,
+  640, 0.447900000000, 0.175000000000, 0.000020000000,
+  645, 0.360800000000, 0.138200000000, 0.000010000000,
+  650, 0.283500000000, 0.107000000000, 0.000000000000,
+  655, 0.218700000000, 0.081600000000, 0.000000000000,
+  660, 0.164900000000, 0.061000000000, 0.000000000000,
+  665, 0.121200000000, 0.044580000000, 0.000000000000,
+  670, 0.087400000000, 0.032000000000, 0.000000000000,
+  675, 0.063600000000, 0.023200000000, 0.000000000000,
+  680, 0.046770000000, 0.017000000000, 0.000000000000,
+  685, 0.032900000000, 0.011920000000, 0.000000000000,
+  690, 0.022700000000, 0.008210000000, 0.000000000000,
+  695, 0.015840000000, 0.005723000000, 0.000000000000,
+  700, 0.011359160000, 0.004102000000, 0.000000000000,
+  705, 0.008110916000, 0.002929000000, 0.000000000000,
+  710, 0.005790346000, 0.002091000000, 0.000000000000,
+  715, 0.004109457000, 0.001484000000, 0.000000000000,
+  720, 0.002899327000, 0.001047000000, 0.000000000000,
+  725, 0.002049190000, 0.000740000000, 0.000000000000,
+  730, 0.001439971000, 0.000520000000, 0.000000000000,
+  735, 0.000999949300, 0.000361100000, 0.000000000000,
+  740, 0.000690078600, 0.000249200000, 0.000000000000,
+  745, 0.000476021300, 0.000171900000, 0.000000000000,
+  750, 0.000332301100, 0.000120000000, 0.000000000000,
+  755, 0.000234826100, 0.000084800000, 0.000000000000,
+  760, 0.000166150500, 0.000060000000, 0.000000000000,
+  765, 0.000117413000, 0.000042400000, 0.000000000000,
+  770, 0.000083075270, 0.000030000000, 0.000000000000,
+  775, 0.000058706520, 0.000021200000, 0.000000000000,
+  780, 0.000041509940, 0.000014990000, 0.000000000000,
+  785, 0.000029353260, 0.000010600000, 0.000000000000,
+  790, 0.000020673830, 0.000007465700, 0.000000000000,
+  795, 0.000014559770, 0.000005257800, 0.000000000000,
+  800, 0.000010253980, 0.000003702900, 0.000000000000,
+  805, 0.000007221456, 0.000002607800, 0.000000000000,
+  810, 0.000005085868, 0.000001836600, 0.000000000000,
+  815, 0.000003581652, 0.000001293400, 0.000000000000,
+  820, 0.000002522525, 0.000000910930, 0.000000000000,
+  825, 0.000001776509, 0.000000641530, 0.000000000000,
+  830, 0.000001251141, 0.000000451810, 0.000000000000,
+};
+
+// The conversion matrix from XYZ to linear sRGB color spaces.
+// Values from https://en.wikipedia.org/wiki/SRGB.
+const double XYZ_TO_SRGB[9] = {
+  +3.2406, -1.5372, -0.4986,
+  -0.9689, +1.8758, +0.0415,
+  +0.0557, -0.2040, +1.0570
+};
+
+const char kVertexShader[] = "\n\
+#version 330\n\
+layout(location = 0) in vec2 vertex;\n\
+void main() {\n\
+    gl_Position = vec4(vertex, 0.0, 1.0);\n\
+}";
+
+const char kGeometryShader[] = "\n\
+#version 330\n\
+layout(triangles) in;\n\
+layout(triangle_strip, max_vertices = 3) out;\n\
+uniform int layer;\n\
+void main() {\n\
+    gl_Position = gl_in[0].gl_Position;\n\
+    gl_Layer = layer;\n\
+    EmitVertex();\n\
+    gl_Position = gl_in[1].gl_Position;\n\
+    gl_Layer = layer;\n\
+    EmitVertex();\n\
+    gl_Position = gl_in[2].gl_Position;\n\
+    gl_Layer = layer;\n\
+    EmitVertex();\n\
+    EndPrimitive();\n\
+}";
+
+const char kComputeTransmittanceShader[] = "\n\
+    layout(location = 0) out vec3 transmittance;\n\
+    void main() {\n\
+      transmittance = ComputeTransmittanceToTopAtmosphereBoundaryTexture(\n\
+          ATMOSPHERE, gl_FragCoord.xy);\n\
+    }";
+
+const char kComputeDirectIrradianceShader[] = "\n\
+    layout(location = 0) out vec3 delta_irradiance;\n\
+    layout(location = 1) out vec3 irradiance;\n\
+    uniform sampler2D transmittance_texture;\n\
+    void main() {\n\
+      delta_irradiance = ComputeDirectIrradianceTexture(\n\
+          ATMOSPHERE, transmittance_texture, gl_FragCoord.xy);\n\
+      irradiance = vec3(0.0);\n\
+    }";
+
+const char kComputeSingleScatteringShader[] = "\n\
+    layout(location = 0) out vec3 delta_rayleigh;\n\
+    layout(location = 1) out vec3 delta_mie;\n\
+    layout(location = 2) out vec4 scattering;\n\
+    layout(location = 3) out vec3 single_mie_scattering;\n\
+    uniform mat3 luminance_from_radiance;\n\
+    uniform sampler2D transmittance_texture;\n\
+    uniform int layer;\n\
+    void main() {\n\
+      ComputeSingleScatteringTexture(\n\
+          ATMOSPHERE, transmittance_texture, vec3(gl_FragCoord.xy, layer + 0.5),\n\
+          delta_rayleigh, delta_mie);\n\
+      scattering = vec4(luminance_from_radiance * delta_rayleigh.rgb,\n\
+          (luminance_from_radiance * delta_mie).r);\n\
+      single_mie_scattering = luminance_from_radiance * delta_mie;\n\
+    }";
+
+const char kComputeScatteringDensityShader[] = "\n\
+    layout(location = 0) out vec3 scattering_density;\n\
+    uniform sampler2D transmittance_texture;\n\
+    uniform sampler3D single_rayleigh_scattering_texture;\n\
+    uniform sampler3D single_mie_scattering_texture;\n\
+    uniform sampler3D multiple_scattering_texture;\n\
+    uniform sampler2D irradiance_texture;\n\
+    uniform int scattering_order;\n\
+    uniform int layer;\n\
+    void main() {\n\
+      scattering_density = ComputeScatteringDensityTexture(\n\
+          ATMOSPHERE, transmittance_texture, single_rayleigh_scattering_texture,\n\
+          single_mie_scattering_texture, multiple_scattering_texture,\n\
+          irradiance_texture, vec3(gl_FragCoord.xy, layer + 0.5),\n\
+          scattering_order);\n\
+    }";
+
+const char kComputeIndirectIrradianceShader[] = "\n\
+    layout(location = 0) out vec3 delta_irradiance;\n\
+    layout(location = 1) out vec3 irradiance;\n\
+    uniform mat3 luminance_from_radiance;\n\
+    uniform sampler3D single_rayleigh_scattering_texture;\n\
+    uniform sampler3D single_mie_scattering_texture;\n\
+    uniform sampler3D multiple_scattering_texture;\n\
+    uniform int scattering_order;\n\
+    void main() {\n\
+      delta_irradiance = ComputeIndirectIrradianceTexture(\n\
+          ATMOSPHERE, single_rayleigh_scattering_texture,\n\
+          single_mie_scattering_texture, multiple_scattering_texture,\n\
+          gl_FragCoord.xy, scattering_order);\n\
+      irradiance = luminance_from_radiance * delta_irradiance;\n\
+    }";
+
+const char kComputeMultipleScatteringShader[] = "\n\
+    layout(location = 0) out vec3 delta_multiple_scattering;\n\
+    layout(location = 1) out vec4 scattering;\n\
+    uniform mat3 luminance_from_radiance;\n\
+    uniform sampler2D transmittance_texture;\n\
+    uniform sampler3D scattering_density_texture;\n\
+    uniform int layer;\n\
+    void main() {\n\
+      float nu;\n\
+      delta_multiple_scattering = ComputeMultipleScatteringTexture(\n\
+          ATMOSPHERE, transmittance_texture, scattering_density_texture,\n\
+          vec3(gl_FragCoord.xy, layer + 0.5), nu);\n\
+      scattering = vec4(\n\
+          luminance_from_radiance *\n\
+              delta_multiple_scattering.rgb / RayleighPhaseFunction(nu),\n\
+          0.0);\n\
+    }";
+
+const char kAtmosphereShader[] = "\n\
+    uniform sampler2D transmittance_texture;\n\
+    uniform sampler3D scattering_texture;\n\
+    uniform sampler3D single_mie_scattering_texture;\n\
+    uniform sampler2D irradiance_texture;\n\
+    #ifdef RADIANCE_API_ENABLED\n\
+    RadianceSpectrum GetSolarRadiance() {\n\
+      return ATMOSPHERE.solar_irradiance /\n\
+          (PI * ATMOSPHERE.sun_angular_radius * ATMOSPHERE.sun_angular_radius);\n\
+    }\n\
+    RadianceSpectrum GetSkyRadiance(\n\
+        Position camera, Direction view_ray, Length shadow_length,\n\
+        Direction sun_direction, out DimensionlessSpectrum transmittance) {\n\
+      return GetSkyRadiance(ATMOSPHERE, transmittance_texture,\n\
+          scattering_texture, single_mie_scattering_texture,\n\
+          camera, view_ray, shadow_length, sun_direction, transmittance);\n\
+    }\n\
+    RadianceSpectrum GetSkyRadianceToPoint(\n\
+        Position camera, Position point, Length shadow_length,\n\
+        Direction sun_direction, out DimensionlessSpectrum transmittance) {\n\
+      return GetSkyRadianceToPoint(ATMOSPHERE, transmittance_texture,\n\
+          scattering_texture, single_mie_scattering_texture,\n\
+          camera, point, shadow_length, sun_direction, transmittance);\n\
+    }\n\
+    IrradianceSpectrum GetSunAndSkyIrradiance(\n\
+       Position p, Direction normal, Direction sun_direction,\n\
+       out IrradianceSpectrum sky_irradiance) {\n\
+      return GetSunAndSkyIrradiance(ATMOSPHERE, transmittance_texture,\n\
+          irradiance_texture, p, normal, sun_direction, sky_irradiance);\n\
+    }\n\
+    #endif\n\
+    Luminance3 GetSolarLuminance() {\n\
+      return ATMOSPHERE.solar_irradiance /\n\
+          (PI * ATMOSPHERE.sun_angular_radius * ATMOSPHERE.sun_angular_radius) *\n\
+          SUN_SPECTRAL_RADIANCE_TO_LUMINANCE;\n\
+    }\n\
+    Luminance3 GetSkyLuminance(\n\
+        Position camera, Direction view_ray, Length shadow_length,\n\
+        Direction sun_direction, out DimensionlessSpectrum transmittance) {\n\
+      return GetSkyRadiance(ATMOSPHERE, transmittance_texture,\n\
+          scattering_texture, single_mie_scattering_texture,\n\
+          camera, view_ray, shadow_length, sun_direction, transmittance) *\n\
+          SKY_SPECTRAL_RADIANCE_TO_LUMINANCE;\n\
+    }\n\
+    Luminance3 GetSkyLuminanceToPoint(\n\
+        Position camera, Position point, Length shadow_length,\n\
+        Direction sun_direction, out DimensionlessSpectrum transmittance) {\n\
+      return GetSkyRadianceToPoint(ATMOSPHERE, transmittance_texture,\n\
+          scattering_texture, single_mie_scattering_texture,\n\
+          camera, point, shadow_length, sun_direction, transmittance) *\n\
+          SKY_SPECTRAL_RADIANCE_TO_LUMINANCE;\n\
+    }\n\
+    Illuminance3 GetSunAndSkyIlluminance(\n\
+       Position p, Direction normal, Direction sun_direction,\n\
+       out IrradianceSpectrum sky_irradiance) {\n\
+      IrradianceSpectrum sun_irradiance = GetSunAndSkyIrradiance(\n\
+          ATMOSPHERE, transmittance_texture, irradiance_texture, p, normal,\n\
+          sun_direction, sky_irradiance);\n\
+      sky_irradiance *= SKY_SPECTRAL_RADIANCE_TO_LUMINANCE;\n\
+      return sun_irradiance * SUN_SPECTRAL_RADIANCE_TO_LUMINANCE;\n\
+    }";
+
+const char header[]="#version 330\n\
+#define IN(x) const in x\n\
+#define OUT(x) out x\n\
+#define TEMPLATE(x)\n\
+#define TEMPLATE_ARGUMENT(x)\n\
+#define assert(x)\n\
+const int TRANSMITTANCE_TEXTURE_WIDTH = 256;\n\
+const int TRANSMITTANCE_TEXTURE_HEIGHT = 64;\n\
+const int SCATTERING_TEXTURE_R_SIZE = 32;\n\
+const int SCATTERING_TEXTURE_MU_SIZE = 128;\n\
+const int SCATTERING_TEXTURE_MU_S_SIZE = 32;\n\
+const int SCATTERING_TEXTURE_NU_SIZE = 8;\n\
+const int IRRADIANCE_TEXTURE_WIDTH = 64;\n\
+const int IRRADIANCE_TEXTURE_HEIGHT = 16;\n\
+#define COMBINED_SCATTERING_TEXTURES\n\
+\n\
+#define Length float\n\
+#define Wavelength float\n\
+#define Angle float\n\
+#define SolidAngle float\n\
+#define Power float\n\
+#define LuminousPower float\n\
+#define Number float\n\
+#define InverseLength float\n\
+#define Area float\n\
+#define Volume float\n\
+#define NumberDensity float\n\
+#define Irradiance float\n\
+#define Radiance float\n\
+#define SpectralPower float\n\
+#define SpectralIrradiance float\n\
+#define SpectralRadiance float\n\
+#define SpectralRadianceDensity float\n\
+#define ScatteringCoefficient float\n\
+#define InverseSolidAngle float\n\
+#define LuminousIntensity float\n\
+#define Luminance float\n\
+#define Illuminance float\n\
+#define AbstractSpectrum vec3\n\
+#define DimensionlessSpectrum vec3\n\
+#define PowerSpectrum vec3\n\
+#define IrradianceSpectrum vec3\n\
+#define RadianceSpectrum vec3\n\
+#define RadianceDensitySpectrum vec3\n\
+#define ScatteringSpectrum vec3\n\
+#define Position vec3\n\
+#define Direction vec3\n\
+#define Luminance3 vec3\n\
+#define Illuminance3 vec3\n\
+#define TransmittanceTexture sampler2D\n\
+#define AbstractScatteringTexture sampler3D\n\
+#define ReducedScatteringTexture sampler3D\n\
+#define ScatteringTexture sampler3D\n\
+#define ScatteringDensityTexture sampler3D\n\
+#define IrradianceTexture sampler2D\n\
+const Length m = 1.0;\n\
+const Wavelength nm = 1.0;\n\
+const Angle rad = 1.0;\n\
+const SolidAngle sr = 1.0;\n\
+const Power watt = 1.0;\n\
+const LuminousPower lm = 1.0;\n\
+const float PI = 3.14159265358979323846;\n\
+const Length km = 1000.0 * m;\n\
+const Area m2 = m * m;\n\
+const Volume m3 = m * m * m;\n\
+const Angle pi = PI * rad;\n\
+const Angle deg = pi / 180.0;\n\
+const Irradiance watt_per_square_meter = watt / m2;\n\
+const Radiance watt_per_square_meter_per_sr = watt / (m2 * sr);\n\
+const SpectralIrradiance watt_per_square_meter_per_nm = watt / (m2 * nm);\n\
+const SpectralRadiance watt_per_square_meter_per_sr_per_nm =\n\
+    watt / (m2 * sr * nm);\n\
+const SpectralRadianceDensity watt_per_cubic_meter_per_sr_per_nm =\n\
+    watt / (m3 * sr * nm);\n\
+const LuminousIntensity cd = lm / sr;\n\
+const LuminousIntensity kcd = 1000.0 * cd;\n\
+const Luminance cd_per_square_meter = cd / m2;\n\
+const Luminance kcd_per_square_meter = kcd / m2;\n\
+struct DensityProfileLayer {\n\
+  Length width;\n\
+  Number exp_term;\n\
+  InverseLength exp_scale;\n\
+  InverseLength linear_term;\n\
+  Number constant_term;\n\
+};\n\
+struct DensityProfile {\n\
+  DensityProfileLayer layers[2];\n\
+};\n\
+struct AtmosphereParameters {\n\
+  IrradianceSpectrum solar_irradiance;\n\
+  Angle sun_angular_radius;\n\
+  Length bottom_radius;\n\
+  Length top_radius;\n\
+  DensityProfile rayleigh_density;\n\
+  ScatteringSpectrum rayleigh_scattering;\n\
+  DensityProfile mie_density;\n\
+  ScatteringSpectrum mie_scattering;\n\
+  ScatteringSpectrum mie_extinction;\n\
+  Number mie_phase_function_g;\n\
+  DensityProfile absorption_density;\n\
+  ScatteringSpectrum absorption_extinction;\n\
+  DimensionlessSpectrum ground_albedo;\n\
+  Number mu_s_min;\n\
+};\n\
+const AtmosphereParameters ATMOSPHERE = AtmosphereParameters(\n\
+vec3(1.474000,1.850400,1.911980),\n\
+0.004675,\n\
+6360.000000,\n\
+6420.000000,\n\
+DensityProfile(DensityProfileLayer[2](DensityProfileLayer(0.000000,0.000000,0.000000,0.000000,0.000000),DensityProfileLayer(0.000000,1.000000,-0.125000,0.000000,0.000000))),\n\
+vec3(0.005802,0.013558,0.033100),\n\
+DensityProfile(DensityProfileLayer[2](DensityProfileLayer(0.000000,0.000000,0.000000,0.000000,0.000000),DensityProfileLayer(0.000000,1.000000,-0.833333,0.000000,0.000000))),\n\
+vec3(0.003996,0.003996,0.003996),\n\
+vec3(0.004440,0.004440,0.004440),\n\
+0.800000,\n\
+DensityProfile(DensityProfileLayer[2](DensityProfileLayer(25.000000,0.000000,0.000000,0.066667,-0.666667),DensityProfileLayer(0.000000,0.000000,0.000000,-0.066667,2.666667))),\n\
+vec3(0.000650,0.001881,0.000085),\n\
+vec3(0.100000,0.100000,0.100000),\n\
+-0.207912);\n\
+const vec3 SKY_SPECTRAL_RADIANCE_TO_LUMINANCE = vec3(683.000000,683.000000,683.000000);\n\
+const vec3 SUN_SPECTRAL_RADIANCE_TO_LUMINANCE = vec3(98242.786222,69954.398112,66475.012354);\n\
+";
+
+void tns_InitAtmosphere(){
+    laSafeString* ss=0;
+
+    tnsTexture* transmittance_texture_ = tnsCreate2DTexture(GL_RGBA32F, TRANSMITTANCE_TEXTURE_WIDTH, TRANSMITTANCE_TEXTURE_HEIGHT, 0);
+    tnsTexture* scattering_texture_ = tnsCreate3DTexture(GL_RGBA16F, SCATTERING_TEXTURE_WIDTH, SCATTERING_TEXTURE_HEIGHT,SCATTERING_TEXTURE_DEPTH);
+    tnsTexture* irradiance_texture_ = tnsCreate2DTexture(GL_RGBA32F, IRRADIANCE_TEXTURE_WIDTH, IRRADIANCE_TEXTURE_HEIGHT, 0);
+    
+    tnsTexture* delta_irradiance_texture = tnsCreate2DTexture(GL_RGBA32F, IRRADIANCE_TEXTURE_WIDTH, IRRADIANCE_TEXTURE_HEIGHT, 0);
+    tnsTexture* delta_rayleigh_scattering_texture = tnsCreate3DTexture(GL_RGBA16F, SCATTERING_TEXTURE_WIDTH, SCATTERING_TEXTURE_HEIGHT,SCATTERING_TEXTURE_DEPTH);
+    tnsTexture* delta_mie_scattering_texture = tnsCreate3DTexture(GL_RGBA16F, SCATTERING_TEXTURE_WIDTH, SCATTERING_TEXTURE_HEIGHT,SCATTERING_TEXTURE_DEPTH);
+    tnsTexture* delta_scattering_density_texture =tnsCreate3DTexture(GL_RGBA16F, SCATTERING_TEXTURE_WIDTH, SCATTERING_TEXTURE_HEIGHT,SCATTERING_TEXTURE_DEPTH);
+    tnsTexture* delta_multiple_scattering_texture = delta_rayleigh_scattering_texture;
+
+    GLuint fbo;
+    glGenFramebuffers(1, &fbo);
+    glBindFramebuffer(GL_FRAMEBUFFER, fbo);
+
+    // The actual precomputations depend on whether we want to store precomputed
+    // irradiance or illuminance values.
+    //if (num_precomputed_wavelengths_ <= 3) {
+    //    vec3 lambdas{kLambdaR, kLambdaG, kLambdaB};
+    //    mat3 luminance_from_radiance{1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0};
+    //    Precompute(fbo, delta_irradiance_texture, delta_rayleigh_scattering_texture,
+    //        delta_mie_scattering_texture, delta_scattering_density_texture,
+    //        delta_multiple_scattering_texture, lambdas, luminance_from_radiance,
+    //        false /* blend */, num_scattering_orders);
+    //} else {
+    //    constexpr double kLambdaMin = 360.0;
+    //    constexpr double kLambdaMax = 830.0;
+    //    int num_iterations = (num_precomputed_wavelengths_ + 2) / 3;
+    //    double dlambda = (kLambdaMax - kLambdaMin) / (3 * num_iterations);
+    //    for (int i = 0; i < num_iterations; ++i) {
+    //    vec3 lambdas{
+    //        kLambdaMin + (3 * i + 0.5) * dlambda,
+    //        kLambdaMin + (3 * i + 1.5) * dlambda,
+    //        kLambdaMin + (3 * i + 2.5) * dlambda
+    //    };
+    //    auto coeff = [dlambda](double lambda, int component) {
+    //        // Note that we don't include MAX_LUMINOUS_EFFICACY here, to avoid
+    //        // artefacts due to too large values when using half precision on GPU.
+    //        // We add this term back in kAtmosphereShader, via
+    //        // SKY_SPECTRAL_RADIANCE_TO_LUMINANCE (see also the comments in the
+    //        // Model constructor).
+    //        double x = CieColorMatchingFunctionTableValue(lambda, 1);
+    //        double y = CieColorMatchingFunctionTableValue(lambda, 2);
+    //        double z = CieColorMatchingFunctionTableValue(lambda, 3);
+    //        return static_cast<float>((
+    //            XYZ_TO_SRGB[component * 3] * x +
+    //            XYZ_TO_SRGB[component * 3 + 1] * y +
+    //            XYZ_TO_SRGB[component * 3 + 2] * z) * dlambda);
+    //    };
+    //    mat3 luminance_from_radiance{
+    //        coeff(lambdas[0], 0), coeff(lambdas[1], 0), coeff(lambdas[2], 0),
+    //        coeff(lambdas[0], 1), coeff(lambdas[1], 1), coeff(lambdas[2], 1),
+    //        coeff(lambdas[0], 2), coeff(lambdas[1], 2), coeff(lambdas[2], 2)
+    //    };
+    //    Precompute(fbo, delta_irradiance_texture,
+    //        delta_rayleigh_scattering_texture, delta_mie_scattering_texture,
+    //        delta_scattering_density_texture, delta_multiple_scattering_texture,
+    //        lambdas, luminance_from_radiance, i > 0 /* blend */,
+    //        num_scattering_orders);
+    //    }
+//
+    //    // After the above iterations, the transmittance texture contains the
+    //    // transmittance for the 3 wavelengths used at the last iteration. But we
+    //    // want the transmittance at kLambdaR, kLambdaG, kLambdaB instead, so we
+    //    // must recompute it here for these 3 wavelengths:
+    //    std::string header = glsl_header_factory_({kLambdaR, kLambdaG, kLambdaB});
+    //    Program compute_transmittance(
+    //        kVertexShader, header + kComputeTransmittanceShader);
+    //    glFramebufferTexture(
+    //        GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, transmittance_texture_, 0);
+    //    glDrawBuffer(GL_COLOR_ATTACHMENT0);
+    //    glViewport(0, 0, TRANSMITTANCE_TEXTURE_WIDTH, TRANSMITTANCE_TEXTURE_HEIGHT);
+    //    compute_transmittance.Use();
+    //    DrawQuad({}, full_screen_quad_vao_);
+    //}
+
+    // Delete the temporary resources allocated at the begining of this method.
+    glUseProgram(0);
+    glBindFramebuffer(GL_FRAMEBUFFER, 0);
+    glDeleteFramebuffers(1, &fbo);
+    glDeleteTextures(1, &delta_scattering_density_texture);
+    glDeleteTextures(1, &delta_mie_scattering_texture);
+    glDeleteTextures(1, &delta_rayleigh_scattering_texture);
+    glDeleteTextures(1, &delta_irradiance_texture);
+    assert(glGetError() == 0);
+
+    strSafeDestroy(&ss);  strSafePrint(&ss,"%s%s",header,kComputeTransmittanceShader);
+    tnsShader* compute_transmittance=tnsNewShaderProgram(tnsNewVertexShader(kVertexShader),tnsNewFragmentShader(ss->Ptr),-1);
+    strSafeDestroy(&ss); strSafePrint(&ss,"%s%s",header,kComputeDirectIrradianceShader);
+    tnsShader* compute_direct_irradiance=tnsNewShaderProgram(tnsNewVertexShader(kVertexShader),tnsNewFragmentShader(ss->Ptr),-1);
+    strSafeDestroy(&ss); strSafePrint(&ss,"%s%s",header,kComputeSingleScatteringShader);
+    tnsShader* compute_single_scattering=tnsNewShaderProgram(tnsNewVertexShader(kVertexShader),tnsNewFragmentShader(ss->Ptr),tnsNewGeometryShader(kGeometryShader));
+    strSafeDestroy(&ss); strSafePrint(&ss,"%s%s",header,kComputeScatteringDensityShader);
+    tnsShader* compute_scattering_density=tnsNewShaderProgram(tnsNewVertexShader(kVertexShader),tnsNewFragmentShader(ss->Ptr),tnsNewGeometryShader(kGeometryShader));
+    strSafeDestroy(&ss); strSafePrint(&ss,"%s%s",header,kComputeIndirectIrradianceShader);
+    tnsShader* compute_indirect_irradiance=tnsNewShaderProgram(tnsNewVertexShader(kVertexShader),tnsNewFragmentShader(ss->Ptr),-1);
+    strSafeDestroy(&ss); strSafePrint(&ss,"%s%s",header,kComputeMultipleScatteringShader);
+    tnsShader* compute_multiple_scattering=tnsNewShaderProgram(tnsNewVertexShader(kVertexShader),tnsNewFragmentShader(ss->Ptr),tnsNewGeometryShader(kGeometryShader));
+
+    const GLuint kDrawBuffers[4] = {
+        GL_COLOR_ATTACHMENT0,
+        GL_COLOR_ATTACHMENT1,
+        GL_COLOR_ATTACHMENT2,
+        GL_COLOR_ATTACHMENT3
+    };
+    glBlendEquationSeparate(GL_FUNC_ADD, GL_FUNC_ADD);
+    glBlendFuncSeparate(GL_ONE, GL_ONE, GL_ONE, GL_ONE);;
+
+}

+ 2 - 2
source/lagui/resources/la_widgets.c

@@ -1451,7 +1451,7 @@ void la_RegisterUiTypesBasic(){
 
     LA_WIDGET_CONDITION_TOGGLE->Type=
     _LA_UI_CONDITION_TOGGLE = la_RegisterUiType("LA_condition_toggle_default", LA_PROP_SELF_CONDITION, "LA_condition_toggle_operator",
-                        &_LA_THEME_BUTTON, la_ConditionToggleDraw, 0, 0, 0);
+                        &_LA_THEME_BUTTON, la_ConditionToggleDraw, 0, 0, la_ConditionUiDestroy);
 
     LA_WIDGET_STRING->Type=LA_WIDGET_STRING_PLAIN->Type=LA_WIDGET_STRING_MONO_PLAIN->Type=
     _LA_UI_STRING = la_RegisterUiType("LA_string_default", LA_PROP_STRING, "LA_string_operator",
@@ -1492,7 +1492,7 @@ void la_RegisterUiTypesBasic(){
 
     _LA_UI_CONDITION_ELSE.Theme = &_LA_THEME_BUTTON;
     la_UDFAppendSharedTypePointer("LA_condition_else", &_LA_UI_CONDITION_ELSE);
-    _LA_UI_CONDITION.Destroy = la_ConditionUiDestroy;
+    _LA_UI_CONDITION.Destroy = _LA_UI_CONDITION_ELSE.Destroy = _LA_UI_CONDITION_END.Destroy =la_ConditionUiDestroy; 
     _LA_UI_CONDITION.Theme = &_LA_THEME_BUTTON;
     la_UDFAppendSharedTypePointer("LA_condition", &_LA_UI_CONDITION);
     _LA_UI_CONDITION_END.Theme = &_LA_THEME_BUTTON;