*/}}
Browse Source

Instancer related stuff

YimingWu 1 year ago
parent
commit
49b48617d6
11 changed files with 391 additions and 298 deletions
  1. 10 9
      la_interface.h
  2. 34 18
      la_kernel.c
  3. 1 0
      la_resource.c
  4. 24 20
      la_tns.h
  5. 83 74
      la_tns_kernel.c
  6. 1 3
      la_tns_mesh.c
  7. 30 9
      resources/la_modelling.c
  8. 20 10
      resources/la_properties.c
  9. 78 69
      resources/la_templates.c
  10. 1 0
      resources/la_widgets.c
  11. 109 86
      resources/la_widgets_viewers.c

+ 10 - 9
la_interface.h

@@ -913,7 +913,7 @@ STRUCTURE(laCanvasExtra){
     int LW,ShowLegend,UiMode;
 
     int HeightCoeff;
-    //int        SnapBottom;
+    int ShowDetails;
 
     int ImageDrawAlpha;
     int ImageDrawBorder;
@@ -943,8 +943,6 @@ STRUCTURE(laCanvasExtra){
     int DisplayMode;
 
     int ShowFloorGrid;
-    int GridSize;
-    int GridSpan;
     int ShowAxis[3];
 
     int LineDrawingMode;
@@ -986,7 +984,6 @@ STRUCTURE(laUiItem){
     laPropStep FakePs;
     laGeneralUiExtraData *Extra;
 
-    //char          NoRefresh;
     short Expand;
     short SymbolID;
     laPropPack PP;
@@ -1697,10 +1694,6 @@ void laui_LayoutListItem(laUiList *uil, laPropPack *Base, laPropPack *UNUSED_Thi
 void laui_PanelListItem(laUiList *uil, laPropPack *Base, laPropPack *UNUSED_This, laColumn *UNUSED_Colums, int context);
 void laui_InputSocketItem(laUiList *uil, laPropPack *Base, laPropPack *UNUSED_This, laColumn *UNUSED_Colums, int context);
 void laui_OutputSocketItem(laUiList *uil, laPropPack *Base, laPropPack *UNUSED_This, laColumn *UNUSED_Colums, int context);
-void tnsui_GroupItem(laUiList *uil, laPropPack *Base, laPropPack *UNUSED_This, laColumn *UNUSED_Colums, int context);
-void tnsui_ObjectGroupItem(laUiList *uil, laPropPack *Base, laPropPack *UNUSED_This, laColumn *UNUSED_Colums, int context);
-void tnsui_GroupObjectItem(laUiList *uil, laPropPack *Base, laPropPack *UNUSED_This, laColumn *UNUSED_Colums, int context);
-void tnsui_MaterialItem(laUiList *uil, laPropPack *Base, laPropPack *UNUSED_This, laColumn *UNUSED_Colums, int context);
 void laui_FileBrowserFileItem(laUiList *uil, laPropPack *This, laPropPack *OP_UNUSED, laColumn *Extra, int context);
 void laui_FileBrowserDiskItem(laUiList *uil, laPropPack *This, laPropPack *OP_UNUSED, laColumn *Extra, int context);
 void laui_LinkerPanel(laUiList *uil, laPropPack *Base, laPropPack *OperatorInst, laColumn *ExtraColumns, int context);
@@ -1715,6 +1708,12 @@ void laui_ResourceFolderItem(laUiList *uil, laPropPack *Base, laPropPack *Operat
 void laui_LogItem(laUiList *uil, laPropPack *Base, laPropPack *OperatorInst, laColumn *ExtraColumns, int context);
 void laui_NodeCategory(laUiList *uil, laPropPack *This, laPropPack *Extra, laColumn *UNUSED, int context);
 
+void tnsui_CameraObjectProperties(laUiList *uil, laPropPack *This, laPropPack *UNUSED_Extra, laColumn *UNUSED_Colums, int context);
+void tnsui_LightObjectProperties(laUiList *uil, laPropPack *This, laPropPack *UNUSED_Extra, laColumn *UNUSED_Colums, int context);
+void tnsui_MeshObjectProperties(laUiList *uil, laPropPack *This, laPropPack *UNUSED_Extra, laColumn *UNUSED_Colums, int context);
+void tnsui_InstancerObjectProperties(laUiList *uil, laPropPack *This, laPropPack *UNUSED_Extra, laColumn *UNUSED_Colums, int context);
+void tnsui_BaseObjectProperties(laUiList *uil, laPropPack *This, laPropPack *UNUSED_Extra, laColumn *UNUSED_Colums, int context);
+
 int OPINV_UiItem(laOperator *a, laEvent *e);
 int OPEXT_UiItem(laOperator *a, int ExitCode);
 
@@ -1968,6 +1967,7 @@ laUiConditionNode *laLessEqual(laUiConditionNode *Expression1, laUiConditionNode
 laUiItem *laShowLabel(laUiList *uil, laColumn *c, const char *Content, laUiDefineFunc Template, laWidget* Widget);
 laUiItem *laShowLabelDynamic(laUiList *uil, laColumn *c, const char *Content, laUiDefineFunc Template, laWidget* Widget);
 laUiItem *laShowIcon(laUiList *uil, laColumn *c, laPropPack *Base, const char *Path, laWidget* Widget);
+laUiItem *laShowInvisibleItem(laUiList *uil, laColumn *c, laPropPack *Base, const char *Path);
 laUiItem *laShowItem(laUiList *uil, laColumn *c, laPropPack *Base, const char *Path);
 laUiItem *laShowItemFull(laUiList *uil, laColumn *c, laPropPack *Base, const char *Path, laWidget* Widget, char* instructions, laUiDefineFunc Template, int TemplateContext);
 laUiItem *laShowImage(laUiList *uil, laColumn *c, tnsImage* Image, int Height);
@@ -1975,7 +1975,7 @@ laUiItem *laShowNodeSocket(laUiList *uil, laColumn *c, laPropPack *Base, const c
 laUiItem *laShowHeightAdjuster(laUiList *uil, laColumn *c, laPropPack *Base, const char *Path, char* instructions);
 laUiItem *laShowDetachedItem(laPanel *p, laUiList *uil, laColumn *c, laPropPack *Base, const char *Path, const char *Rename, laUiDefineFunc Template, laWidget* Widget);
 laUiItem *laShowCanvas(laUiList *uil, laColumn *c, laPropPack *Base, const char *Path, const char *id2DTemplate, int Height);
-laUiItem *laShow3DCanvasCombo(laUiList *uil, laColumn *c, laPropPack *Base, const char *Path, int Height);
+laUiItem *laShow3DCanvasCombo(laUiList *uil, laColumn *c, laPropPack *Base, const char *Path, int Height, laPropPack* Detached);
 laUiItem *laShow2DContainerItem(laUiList *uil, laColumn *c, laPropPack *Base, const char *Path, int Height);
 void laDefault3DViewOverlay(laUiItem *ui);
 void laDefault2DViewOverlayRight(laUiItem *ui);
@@ -2147,6 +2147,7 @@ extern laUiType _LA_UI_CONDITION_END;  //NO PTR
 extern laUiType _LA_UI_CONDITION_ELSE; //NO PTR
 extern laUiType _LA_UI_ROW_BEGIN;      //NO PTR
 extern laUiType _LA_UI_ROW_END;        //NO PTR
+extern laUiType _LA_UI_INVISIBLE;      //NO PTR
 extern laUiType *_LA_UI_COLLECTION;
 extern laUiType *_LA_UI_COLLECTION_ITEM;
 extern laUiType *_LA_UI_COLLECTION_SELECTOR;

+ 34 - 18
la_kernel.c

@@ -2177,7 +2177,6 @@ void la_WindowDefDraw(laWindow *w, laBoxedTheme *bt){
     if (l->Draw) l->Draw(w, l);
 
     tnsResetModelMatrix();tnsResetProjectionMatrix();tnsResetViewMatrix();
-    //tnsShadeMode(GL_SMOOTH);
 
     glEnable(GL_BLEND);
     //lBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
@@ -2210,6 +2209,7 @@ void la_WindowDefDraw(laWindow *w, laBoxedTheme *bt){
             }
         }
         if (DrawState_){ p->Refresh = LA_TAG_RECALC; laRefreshWindow(); }
+        la_AttachedPanelDefDraw(w,p,*p->BT);
     }else{
         laBlock* RootBlock= w->MaximizedBlock?w->MaximizedBlock:l->FirstBlock;
         la_BlockDefDrawRecursive(w, bt, RootBlock);
@@ -3741,6 +3741,9 @@ laUiItem *laShowIcon(laUiList *uil, laColumn *c, laPropPack *Base, const char *P
 
     return ui;
 }
+laUiItem *laShowInvisibleItem(laUiList *uil, laColumn *c, laPropPack *Base, const char *Path){
+    laWidget wg={&_LA_UI_INVISIBLE, 0}; return laShowItemFull(uil,c,Base,Path,&wg,0,0,0);
+}
 laUiItem *laShowItem(laUiList *uil, laColumn *c, laPropPack *Base, const char *Path){
     return laShowItemFull(uil,c,Base,Path,0,0,0,0);
 }
@@ -3799,16 +3802,27 @@ laUiItem *laShowCanvas(laUiList *uil, laColumn *c, laPropPack *Base, const char
 
     return ui;
 }
-laUiItem *laShow3DCanvasCombo(laUiList *uil, laColumn *c, laPropPack *Base, const char *Path, int Height){
-    laUiItem* ui=laShowCanvas(uil,c,Base,Path,0,Height-1);
-    laDefault3DViewOverlay(ui);
-
-    laUiItem* b=laBeginRow(uil,c,0,0);
-    laShowItem(uil,c,&ui->ExtraPP,"select_mode")->Flags|=LA_UI_FLAGS_EXPAND;
-    laShowItem(uil,c,&ui->ExtraPP,"select_through");
-    laShowSeparator(uil,c)->Expand=1;
-    laShowItem(uil,c,&ui->ExtraPP,"delta_mode")->Flags|=LA_UI_FLAGS_CYCLE|LA_UI_FLAGS_HIGHLIGHT;
-    laEndRow(uil,b);
+laUiItem *laShow3DCanvasCombo(laUiList *uil, laColumn *c, laPropPack *Base, const char *Path, int Height, laPropPack* Detached){
+    laUiItem* ui=0;
+    if(Detached){
+        laColumn* cl,*cll,*clr,*cr;
+        laSplitColumn(uil,c,0.35); cl=laLeftColumn(c,7); cr=laRightColumn(c,0);
+        laSplitColumn(uil,cl,0.4); cll=laLeftColumn(cl,1); clr=laRightColumn(cl,0);
+        laShowItemFull(uil,cll,Detached,"detached",0,0,0,0)->Flags|=LA_UI_FLAGS_HIGHLIGHT|LA_UI_FLAGS_ICON;
+        laUiItem* rb=laShowItemFull(uil,clr,Detached,"root_object",LA_WIDGET_COLLECTION_SELECTOR,0,laui_IdentifierOnly,0);
+        laUiItem* b2=laOnConditionThat(uil,c,laPropExpression(&rb->PP,"active"));{
+            laUiItem* b=laBeginRow(uil,cr,0,0);
+            laShowLabel(uil,cr,"⯈",0,0); laShowItem(uil,cr,&rb->PP,"active.name")->Flags|=LA_UI_FLAGS_NO_DECAL;
+            laEndRow(uil,b);
+        }laEndCondition(uil,b2);
+        b2=laOnConditionThat(uil,c,laPropExpression(Detached,"detached"));{
+            ui=laShowCanvas(uil,c,Detached,"root_object",0,Height); laDefault3DViewOverlay(ui);
+        }laElse(uil,b2);{
+            ui=laShowCanvas(uil,c,0,"tns.world.root_objects",0,Height); laDefault3DViewOverlay(ui);
+        }laEndCondition(uil,b2);
+    }else{
+        ui=laShowCanvas(uil,c,Base,Path,0,Height); laDefault3DViewOverlay(ui);
+    }
 }
 laUiItem *laShowColumnAdjuster(laUiList *uil, laColumn *c){
     laUiItem *ui = memAcquireSimple(sizeof(laUiItem));
@@ -4851,11 +4865,11 @@ int la_UpdateUiListRecursive(laUiList *uil, int U, int L, int R, int B, int Fast
             }
         }
 
-        if (/*!ui->NoRefresh && */ ui->PP.LastPs){
-            la_StepPropPack(&ui->PP);
-        }
-
+        if (ui->PP.LastPs){ la_StepPropPack(&ui->PP); }
         la_UsePropPack(&ui->PP, 0);
+
+        if(ui->Type==&_LA_UI_INVISIBLE){ ui=ui->Item.pNext; continue; }
+
         //if (ui->PP.LastPs && (HyperValue = ui->PP.LastPs->p->Container ? ui->PP.LastPs->p->Container->Hyper : 0)){
         //    laUseDataBlock(ui->PP.Go ? ui->PP.LastPs->UseInstance : ui->PP.RawThis->LastPs->UseInstance, ui->PP.LastPs->p, MAIN.PropMatcherContextP->FrameDistinguish, MAIN.PropMatcherContextP, la_PropPanelUserRemover, 0);
         //}
@@ -5098,7 +5112,7 @@ int la_UpdateUiListRecursive(laUiList *uil, int U, int L, int R, int B, int Fast
                         la_CalcUiTopInfluence(&uil->Columns, ui);
                         laMakeUiListFromTemplate(ui->Page, Template, &ParentPanel->PP, &ParentPanel->PropLinkPP, &ui->PP, 0, &uil->Columns, ui->TemplateContext);
                         SubB = la_UpdateUiListRecursive(ui->Page, ui->TB+(NoDecal?0:bt->TM), ui->TL+(NoDecal?0:bt->LM), ui->TR-(NoDecal?0:bt->RM)-EraseWidth, B, Fast, ParentPanel);
-                        ui->TB = SubB + (NoDecal?0:bt->TM);
+                        ui->TB = SubB + (NoDecal?0:bt->BM);
                     }else if (ui->Subs.pFirst){
                         if (!TInstance || TInstance != ui->Page->Instance){
                             la_DestroyTabPage(ui, ui->Subs.pFirst, 0);
@@ -5113,10 +5127,12 @@ int la_UpdateUiListRecursive(laUiList *uil, int U, int L, int R, int B, int Fast
                                 ui->TB = ui->TU + LA_RH + bt->BM;
                         }else{
                             SubB = la_UpdateUiListRecursive(ui->Page, ui->TB+(NoDecal?0:bt->TM), ui->TL+(NoDecal?0:bt->LM), ui->TR-(NoDecal?0:bt->RM)-EraseWidth, B, Fast, ParentPanel);
-                            ui->TB = SubB + (NoDecal?0:bt->TM);
+                            ui->TB = SubB + (NoDecal?0:bt->BM);
                         }
                     }
-
+                    if(ui->Type == _LA_UI_COLLECTION_SELECTOR && (ui->TB>(ui->TU+LA_RH*0.9))&&(ui->TB<ui->TU+(LA_RH*1.1))){
+                        ui->TB=ui->TU+LA_RH;
+                    }
                 }
                 if (ui->TB-ui->TU<LA_RH) ui->TB = ui->TU + LA_RH;
                 if (!WaitAnimation){

+ 1 - 0
la_resource.c

@@ -29,6 +29,7 @@ laUiType _LA_UI_CONDITION_END;  //NO PTR
 laUiType _LA_UI_CONDITION_ELSE; //NO PTR
 laUiType _LA_UI_ROW_BEGIN;      //NO PTR
 laUiType _LA_UI_ROW_END;        //NO PTR
+laUiType _LA_UI_INVISIBLE;      //NO PTR
 laUiType *_LA_UI_COLLECTION;
 laUiType *_LA_UI_COLLECTION_ITEM;
 laUiType *_LA_UI_COLLECTION_SELECTOR;

+ 24 - 20
la_tns.h

@@ -109,9 +109,8 @@ struct _tnsShader{
     int uViewDir,uViewPos,uFOV,uNear,uFar;
 };
 typedef struct _tnsTexture tnsTexture;
-typedef struct _tnsCommand tnsCommand;
-struct _tnsCommand
-{
+
+STRUCTURE(tnsCommand){
     GLenum Mode;
     short Dimensions; // 2 or 3
     short UVDimensions; // 2 or 3
@@ -141,6 +140,8 @@ struct _tnsCommand
     tnsTexture *ColorTexture;
     int TextureMode;
     int MultiplyColor;
+
+    GLfloat LineWidth,PointSize;
 };
 typedef struct _tnsMain tnsMain;
 typedef struct _tnsWorld tnsWorld;
@@ -245,8 +246,6 @@ struct _tnsMain {
     tnsTexture *TexRenderbuffer;
 
     // For commands
-    GLenum StateShadeMode;
-    GLenum StatePolyMode;
     tnsTexture *StateTexColor;
     int StateTextureMode;
     int StateMultiplyColor;
@@ -256,6 +255,8 @@ struct _tnsMain {
     tnsShader* StateShader;
 
     GLfloat StateColor[4];
+    GLfloat StateLineWidth,SetLineWidth;
+    GLfloat StatePointSize,SetPointSize;
 
     GLfloat* Vert;
     GLuint VertBufObject;
@@ -547,7 +548,7 @@ typedef struct _tnsObject tnsObject;
 #define TNS_ROTATION_QUATERNION 6
 
 #define TNS_OBJECT_ROOT   0
-#define TNS_OBJECT_EMPTY  (1<<0)
+#define TNS_OBJECT_INSTANCER  (1<<0)
 #define TNS_OBJECT_CAMERA (1<<1)
 #define TNS_OBJECT_LIGHT  (1<<2)
 #define TNS_OBJECT_MESH   (1<<3)
@@ -590,6 +591,7 @@ STRUCTURE(tnsEvaluateData){
     tnsEvaluatedInstance* Outlines; int NextOutline, MaxOutline;
     tnsEvaluatedInstance* Overlays; int NextOverlay, MaxOverlay;
     tnsEvaluatedInstance* Selections; int NextSelection, MaxSelection;
+    tnsMatrix44d* MatArr; int NextMat, MaxMat;
 };
 
 NEED_STRUCTURE(laRackPageCollection);
@@ -657,9 +659,8 @@ STRUCTURE(tnsMakeTransformNode){
     tnsMatrix44d Mat; tnsVector3d UseLoc; tnsVector3d UseRot; real UseSca; real UseAngle;
 };
 
-#define TNS_PRESPECTIVE_CAMERA 0
-#define TNS_ORTHOGRAPHICAL_CAMERA 1
-#define TNS_FISHEYE_CAMERA 2
+#define TNS_CAMERA_PERSP 0
+#define TNS_CAMERA_ORTHO 1
 
 #define TNS_ID_TO_COLOR(color, i) \
     {color[0]=(real)((i & 0x000000FF)>>0)/255.0; color[1]=(real)((i & 0x0000FF00)>>8)/255.0; color[2]=(real)((i & 0x00FF0000)>>16)/255.0;}
@@ -693,9 +694,14 @@ struct _tnsMaterial
 #define TNS_CAMERA_ORTHO 1
 #define TNS_CAMERA_FISHEYE 2
 
-typedef struct _tnsCamera tnsCamera;
-struct _tnsCamera
-{
+STRUCTURE(tnsInstancer){
+    tnsObject Base;
+    
+    tnsObject* DefaultInstance;
+    tnsObject* RuntimeInstance;
+};
+
+STRUCTURE(tnsCamera){
     tnsObject Base;
 
     int CameraType;
@@ -707,9 +713,7 @@ struct _tnsCamera
     tnsVector3d RenderViewDir;
 };
 
-typedef struct _tnsLight tnsLight;
-struct _tnsLight
-{
+STRUCTURE(tnsLight){
     tnsObject Base;
 
     int LightType;
@@ -799,6 +803,7 @@ STRUCTURE(tnsBatch){
 #define TNS_MESH_EDIT_MODE   1
 
 extern laPropContainer* TNS_PC_OBJECT_GENERIC;
+extern laPropContainer* TNS_PC_OBJECT_INSTANCER;
 extern laPropContainer* TNS_PC_OBJECT_CAMERA;
 extern laPropContainer* TNS_PC_OBJECT_LIGHT;
 extern laPropContainer* TNS_PC_OBJECT_MESH;
@@ -1003,9 +1008,8 @@ void tnsPreScale3d(real x, real y, real z);
 
 void tnsColor4d(real r, real g, real b, real a);
 void tnsColor4dv(real *rgba);
-
-void tnsPolygonMode(GLenum PolyMode);
-void tnsShadeMode(GLenum ShadeMode);
+void tnsLineWidth(real Width);
+void tnsPointSize(real PointSize);
 
 tnsBatch *tnsCreateBatch(u32bit NumVert, int Dimension, float *Data, int NormalDimension, float *Normal, int ColorDimension, float *Colors);
 tnsBatch *tnsCreateBatchi(u32bit NumVert, int Dimension, int *Data);
@@ -1196,7 +1200,7 @@ tnsCamera *tnsCreateCamera(tnsObject *under, char *Name, real FOV,
                               real AtX, real AtY, real AtZ,
                               real RotX, real RotY, real RotZ,
                               real FocusDistance);
-tnsObject *tnsCreateEmpty(tnsObject *under, char *Name, real AtX, real AtY, real AtZ);
+tnsObject *tnsCreateInstancer(tnsObject *under, char *Name, real AtX, real AtY, real AtZ);
 tnsLight *tnsCreateLight(tnsObject *under, char *Name, real AtX, real AtY, real AtZ, real Strength, int UniDirectional);
 tnsMeshObject *tnsCreateMeshEmpty(tnsObject *under, char *Name, real AtX, real AtY, real AtZ);
 tnsMeshObject *tnsCreateMeshPlane(tnsObject *under, char *Name, real AtX, real AtY, real AtZ, real size);
@@ -1281,7 +1285,7 @@ void tnsInvalidateEvaluation(tnsObject* o);
 void tnsFreeEvaluatedArray(tnsEvaluateData* ed);
 void tnsEvaluateThisObject(tnsObject *o, tnsEvaluateData* ed);
 void tnsSetObjectTreeEvaluationArgs(tnsObject* from, tnsObject* Active, int FillOutline, int FillSelectionID);
-void tnsEvaluateObjectTree(tnsObject* from);
+void tnsEvaluateObjectTree(tnsObject* from, tnsEvaluateData* UseED);
 void tnsAddEvaluatedInstance(tnsEvaluateData* ed, tnsObject* ob, tnsDrawEvaluatedInstanceF Draw, int Layer, 
     int IsActive, int MeshSelectionType, int InstanceSelectionID);
 void tnsDrawLayer(tnsEvaluateData* ed,int Layer,void* CustomData);

+ 83 - 74
la_tns_kernel.c

@@ -1281,6 +1281,8 @@ void tnsInitRenderKernel(int matrixStackLevel){
     T->BindedShader = -1;
     tnsInitFirstLevel(&T->stack);
 
+    T->StateLineWidth=T->SetLineWidth=1; T->StatePointSize=T->SetPointSize=1;
+
     /* Needed for gl3.3+ */
     glGenVertexArrays(1,&T->GlobalVAO);
     glBindVertexArray(T->GlobalVAO);
@@ -2027,25 +2029,15 @@ void tnsStopUsingImage(tnsImage* im){
 //====================================================[NEW RENDER KERNEL]
 //=================[Immediate-style api]
 
-void tnsColor4d(real r, real g, real b, real a){
-    T->StateColor[0] = r;
-    T->StateColor[1] = g;
-    T->StateColor[2] = b;
-    T->StateColor[3] = a;
+void tnsColor4d(real r, real g, real b, real a){ tnsVectorSet4(T->StateColor,r,g,b,a); }
+void tnsColor4dv(real *rgba){ tnsVectorSet4v(T->StateColor,rgba); }
+void tnsLineWidth(real Width){ if(TNS_FLOAT_CLOSE_ENOUGH_WIDER(Width,T->StateLineWidth)) return;
+    T->StateLineWidth=Width;
 }
-void tnsColor4dv(real *rgba){
-    T->StateColor[0] = rgba[0];
-    T->StateColor[1] = rgba[1];
-    T->StateColor[2] = rgba[2];
-    T->StateColor[3] = rgba[3];
+void tnsPointSize(real PointSize){ if(TNS_FLOAT_CLOSE_ENOUGH_WIDER(PointSize,T->StatePointSize)) return;
+    T->StatePointSize=PointSize;
 }
 
-void tnsPolygonMode(GLenum PolyMode){
-    T->StatePolyMode = PolyMode;
-}
-void tnsShadeMode(GLenum ShadeMode){
-    T->StateShadeMode = ShadeMode;
-}
 void tnsVertex3d(real x, real y, real z){
     tnsCommand *c = &T->DrawingCommand[T->NextCommand];
     int vend = c->VertEnd;
@@ -2270,11 +2262,11 @@ void tnsPackAs(GLenum Mode){
     //if (Mode == GL_QUADS) Mode=GL_TRIANGLE_STRIP;
     c->Mode = Mode;
     c->ReplaceShader = T->StateShader;
-    c->PolyMode = T->StatePolyMode;
-    c->Shade = T->StateShadeMode;
     c->ColorTexture = T->StateTexColor;
     c->TextureMode = T->StateTextureMode;
     c->MultiplyColor = T->StateMultiplyColor;
+    c->LineWidth=T->StateLineWidth;
+    c->PointSize=T->StatePointSize;
 
     memset(nc, 0, sizeof(tnsCommand));
     nc->VertBegin = nc->VertEnd = c->VertEnd;
@@ -2292,35 +2284,24 @@ void tnsFlush(){
 
     if (!c || !cs) return;
 
-    if (T->NextVert){
-        glBindBuffer(GL_ARRAY_BUFFER, T->VertBufObject);
-        //glEnableVertexAttribArray(cs->iVertex);
+    if (T->NextVert){ glBindBuffer(GL_ARRAY_BUFFER, T->VertBufObject);
         glBufferSubData(GL_ARRAY_BUFFER, 0, T->NextVert * sizeof(GLfloat), T->Vert);
     }
-    if (T->NextColor){
-        glBindBuffer(GL_ARRAY_BUFFER, T->ColorBufObject);
-        //glEnableVertexAttribArray(cs->iColor);
+    if (T->NextColor){ glBindBuffer(GL_ARRAY_BUFFER, T->ColorBufObject);
         glBufferSubData(GL_ARRAY_BUFFER, 0, T->NextColor * sizeof(GLfloat), T->Color);
     }
-    if (T->NextNormal){
-        glBindBuffer(GL_ARRAY_BUFFER, T->NormalBufObject);
-        //glEnableVertexAttribArray(cs->iColor);
+    if (T->NextNormal){ glBindBuffer(GL_ARRAY_BUFFER, T->NormalBufObject);
         glBufferSubData(GL_ARRAY_BUFFER, 0, T->NextNormal * sizeof(GLfloat), T->Normal);
     }
-    if (T->NextTexCoord){
-        glBindBuffer(GL_ARRAY_BUFFER, T->TexCoordBufObject);
-        //glEnableVertexAttribArray(cs->iColor);
+    if (T->NextTexCoord){ glBindBuffer(GL_ARRAY_BUFFER, T->TexCoordBufObject);
         glBufferSubData(GL_ARRAY_BUFFER, 0, T->NextTexCoord * sizeof(GLfloat), T->TexCoord);
     }
 
-    for (int i=0;i<T->NextCommand;i++){
-        c=&T->DrawingCommand[i];
-
-        if (c->PolyMode != T->StatePolyMode){glPolygonMode(GL_FRONT_AND_BACK, c->PolyMode); T->StatePolyMode=c->PolyMode;}
-        if (c->Shade != T->StateShadeMode){glShadeModel(c->Shade); T->StateShadeMode=c->Shade;}
+    for (int i=0;i<T->NextCommand;i++){ c=&T->DrawingCommand[i];
+        if (c->LineWidth!=T->SetLineWidth){ glLineWidth(c->LineWidth); T->SetLineWidth=c->LineWidth; }
+        if (c->PointSize!=T->SetPointSize){ glLineWidth(c->PointSize); T->SetPointSize=c->PointSize; }
         if (c->ReplaceShader && c->ReplaceShader != T->CurrentShader){
-            tnsEnableShaderv(c->ReplaceShader);
-            cs = c->ReplaceShader;
+            tnsEnableShaderv(c->ReplaceShader); cs = c->ReplaceShader;
             if (!cs) continue;
         }
 
@@ -3561,7 +3542,7 @@ void tnsDestroyRootObject(tnsObject *root){
     tnsFreeEvaluatedArray(&root->Evaluated);
 
     //XXX: destroy rack page; and then release memory;
-    o->Drivers=0; memLeave(o->Drivers); 
+    root->Drivers=0; memLeave(root->Drivers); 
 
     lstRemoveItem(&w->RootObjects, root);
     while (lstPopPointerLeave(&root->ChildObjects));
@@ -3578,7 +3559,10 @@ void tnsDestroyObject(tnsObject *o){
 
     lstRemoveItem(&T->World.AllObjects, o);
 
-    if(o->InRoot){ lstRemovePointerLeave(&o->InRoot->ChildObjects, o); }
+    if(o->InRoot){ lstRemovePointerLeave(&o->InRoot->ChildObjects, o);
+        tnsInvalidateEvaluation(o);
+        if(o->InRoot->Active==o){ memAssignRef(o->InRoot,&o->InRoot->Active,0); }
+    }
 
     if(o->Type==TNS_OBJECT_MESH){ tnsMeshObject* mo=o;
         if(mo->v) arrFree(&mo->v, &mo->maxv); if(mo->e) arrFree(&mo->e, &mo->maxe);
@@ -3599,7 +3583,7 @@ tnsCamera *tnsCreateCamera(tnsObject *under, char *Name, real FOV,
     c = memAcquireHyper(sizeof(tnsCamera));
     tnsInitObjectBase(&c->Base, under, Name, TNS_OBJECT_CAMERA, AtX, AtY, AtZ, RotX, RotY, RotZ, 1.0f, TNS_ROTATION_XYZ_EULER, 1.0f);
     c->FOV = FOV;
-    c->CameraType = TNS_PRESPECTIVE_CAMERA;
+    c->CameraType = TNS_CAMERA_PERSP;
     c->ZMin = 0.1f;
     c->ZMax = 1000.0f;
     c->FocusDistance = FocusDistance;
@@ -3607,11 +3591,11 @@ tnsCamera *tnsCreateCamera(tnsObject *under, char *Name, real FOV,
 
     return c;
 }
-tnsObject *tnsCreateEmpty(tnsObject *under, char *Name, real AtX, real AtY, real AtZ){
+tnsObject *tnsCreateInstancer(tnsObject *under, char *Name, real AtX, real AtY, real AtZ){
     tnsObject *o; tnsWorld *w = &T->World; if (!under) return 0;
 
-    o = memAcquireHyper(sizeof(tnsObject));
-    tnsInitObjectBase(o, under, Name, TNS_OBJECT_EMPTY, AtX, AtY, AtZ, 0, 0, 0, 1.0f, TNS_ROTATION_XYZ_EULER, 1.0f);
+    o = memAcquireHyper(sizeof(tnsInstancer));
+    tnsInitObjectBase(o, under, Name, TNS_OBJECT_INSTANCER, AtX, AtY, AtZ, 0, 0, 0, 1.0f, TNS_ROTATION_XYZ_EULER, 1.0f);
 
     return o;
 }
@@ -3640,6 +3624,7 @@ void tnsDeselectAllObjects(tnsObject *root){
     for(laListItemPointer* lip=root->ChildObjects.pFirst;lip;lip=lip->pNext){ tnsObject* o=lip->p; o->Flags&=(~TNS_OBJECT_FLAGS_SELECTED);
         if(o->ChildObjects.pFirst)tnsDeselectAllObjects(o);
     }
+    memAssignRef(root,&root->Active,0);
     tnsInvalidateEvaluation(root);
 }
 void tnsSelectAllObjects(tnsObject *root){
@@ -3744,23 +3729,13 @@ void tnsLookAt(tnsObject *o, tnsVector3d Target, tnsVector3d Up){
 void tnsDrawCamera(tnsObject *o){
     tnsCamera *c = o;
     real fov_2 = c->FOV / 2;
-    real ex, ey, ez;
-    ey = 10 * sin(fov_2);
-    ex = ey;
-    ez = 10 * cos(fov_2);
-
-    //if (T->CurrentShader != T->uiShader) tnsEnableShaderv(T->uiShader);
+    real ex, ey, ez; ey = 10 * sin(fov_2); ex = ey; ez = 10 * cos(fov_2);
 
     tnsColor4d(1, 1, 1, 1);
 
-    tnsVertex3d(ex, ey, -ez);
-    tnsVertex3d(ex, -ey, -ez);
-    tnsVertex3d(0.0, 0.0, 0.0);
-    tnsVertex3d(ex, ey, -ez);
-    tnsVertex3d(-ex, ey, -ez);
-    tnsVertex3d(0.0, 0.0, 0.0);
-    tnsVertex3d(-ex, -ey, -ez);
-    tnsVertex3d(-ex, ey, -ez);
+    tnsVertex3d(ex, ey, -ez); tnsVertex3d(ex, -ey, -ez); tnsVertex3d(0.0, 0.0, 0.0);
+    tnsVertex3d(ex, ey, -ez); tnsVertex3d(-ex, ey, -ez); tnsVertex3d(0.0, 0.0, 0.0);
+    tnsVertex3d(-ex, -ey, -ez); tnsVertex3d(-ex, ey, -ez);
 
     tnsPackAs(GL_LINE_STRIP);
     tnsFlush();
@@ -3784,19 +3759,51 @@ void tnsDrawPlaceholder(tnsObject* o, tnsEvaluateData* ed){
     tnsPackAs(GL_LINES);
     tnsFlush();
 }
+
+void tnsDrawEmptySelectionID(tnsEvaluatedInstance* ei, void* unused){
+    int i=ei->InstanceSelectionID; real color[4]={0,0,0,1}; TNS_ID_TO_COLOR(color,i); tnsColor4dv(color);
+    tnsDrawCross(0,0,0,-1,5,-1,5,-1,5); tnsPackAs(GL_LINES); tnsFlush();
+}
+void tnsDrawEmptyOutline(tnsEvaluatedInstance* ei, void* unused){
+    real* color=(ei->IsActive)?laAccentColor(LA_BT_TEXT):laAccentColor(LA_BT_NORMAL); tnsColor4dv(color);
+    tnsDrawCross(0,0,0,-1,5,-1,5,-1,5); tnsLineWidth(3);tnsPackAs(GL_LINES); tnsLineWidth(1); tnsFlush();
+}
+void tnsDrawEmptyObject(tnsEvaluatedInstance* ei, void* unused){
+    tnsColor4dv(laThemeColor(_LA_THEME_3D_VIEW,LA_BT_BORDER));
+    tnsDrawCross(0,0,0,-1,5,-1,5,-1,5);tnsLineWidth(3); tnsPackAs(GL_LINES); tnsLineWidth(1); tnsFlush();
+}
+void tnsEvaluateEmptyObject(tnsObject* o, tnsEvaluateData* ed){
+    tnsAddEvaluatedInstance(ed,o,tnsDrawEmptyObject,TNS_EVAL_LAYER_SOLID,0,0,0);
+    if(ed->FillOutline && o->Flags&TNS_OBJECT_FLAGS_SELECTED){
+        tnsAddEvaluatedInstance(ed,o,tnsDrawEmptyOutline,TNS_EVAL_LAYER_OUTLINE,ed->Active==o,0,0);
+    }
+    if(ed->FillSelectionID){
+        tnsAddEvaluatedInstance(ed,o,tnsDrawEmptySelectionID,TNS_EVAL_LAYER_SELECTION,0,1,o->SelectID);
+    }
+}
+void tnsPushEvaluateMatrixWith(tnsEvaluateData* ed, tnsMatrix44d mat){
+    arrEnsureLength(&ed->MatArr,ed->NextMat,&ed->MaxMat,sizeof(tnsMatrix44d)); if(ed->NextMat<1) return;
+    real* new=ed->MatArr[ed->NextMat]; ed->NextMat++;
+    tnsMultiply44d(new, ed->MatArr[ed->NextMat-1], mat);
+}
+void tnsPopEvaluateMatrix(tnsEvaluateData* ed){ ed->NextMat--; }
+void tnsEvaluateInstancerObject(tnsInstancer* o, tnsEvaluateData* ed){
+    int origid=ed->OverrideID; ed->OverrideID = o->Base.SelectID;
+    tnsEvaluateEmptyObject(o,ed);
+    if(o->DefaultInstance){
+        tnsPushEvaluateMatrixWith(ed,o->Base.GlobalTransform);
+        tnsEvaluateObjectTree(o->DefaultInstance, ed);
+        tnsPopEvaluateMatrix(ed);
+    }
+    ed->OverrideID=origid;
+}
 void tnsEvaluateThisObject(tnsObject *o, tnsEvaluateData* ed){
     if (!o->Show) return;
     switch (o->Type){
-    case TNS_OBJECT_MESH:
-        tnsEvaluateMeshObject(o, ed);
-        break;
-    case TNS_OBJECT_CAMERA:
-        tnsDrawCamera(o);
-        break;
-    case TNS_OBJECT_EMPTY:
-    default:
-        tnsDrawPlaceholder(o,ed);
-        break;
+    case TNS_OBJECT_MESH: tnsEvaluateMeshObject(o, ed); break;
+    case TNS_OBJECT_INSTANCER: tnsEvaluateInstancerObject(o,ed); break;
+    case TNS_OBJECT_CAMERA: tnsDrawCamera(o); break;
+    default: tnsEvaluateEmptyObject(o,ed); break;
     }
 }
 
@@ -3816,9 +3823,10 @@ void tnsAddEvaluatedInstance(tnsEvaluateData* ed, tnsObject* ob, tnsDrawEvaluate
         arrEnsureLength(&ed->Selections,ed->NextSelection,&ed->MaxSelection,sizeof(tnsEvaluatedInstance));
         ei=&ed->Selections[ed->NextSelection]; ed->NextSelection++;
     }else{ return; }
-    ei->IsActive=IsActive; ei->MeshSelectionType=MeshSelectionType; ei->InstanceSelectionID=InstanceSelectionID;
+    ei->IsActive=IsActive; ei->MeshSelectionType=MeshSelectionType;
+    ei->InstanceSelectionID=ed->OverrideID?ed->OverrideID:InstanceSelectionID;
     ei->Draw=Draw; ei->Object=ob;
-    tnsCopyMatrix44d(ob->GlobalTransform,ei->Mat);
+    tnsMultiply44d(ei->Mat,ed->MatArr[ed->NextMat-1],ob->GlobalTransform);
 }
 void tnsFreeEvaluatedArray(tnsEvaluateData* ed){
     ed->Done=0;
@@ -3837,22 +3845,23 @@ void tnsSetObjectTreeEvaluationArgs(tnsObject* from, tnsObject* Active, int Fill
     SETARG(Active); SETARG(FillOutline); SETARG(FillSelectionID);
     if(set) ed->Done=0;
 }
-void tnsEvaluateObjectTree(tnsObject* from){
+void tnsEvaluateObjectTree(tnsObject* from, tnsEvaluateData* UseED){
     if(!from) return;
-    tnsEvaluateData* ed=&from->Evaluated;
+    tnsEvaluateData* ed=UseED?UseED:(from->InRoot?(&from->InRoot->Evaluated):(&from->Evaluated));
     if(ed->Done) return;
-    else{ ed->NextCommand=ed->NextOverlay=ed->NextSelection=ed->NextOutline=0;
+    else{ ed->NextCommand=ed->NextOverlay=ed->NextSelection=ed->NextOutline=ed->NextMat=0;
         if(!ed->Commands) arrInitLength(&ed->Commands,16,&ed->MaxCommand,sizeof(tnsEvaluatedInstance));
         if(!ed->Outlines) arrInitLength(&ed->Outlines,16,&ed->MaxOutline,sizeof(tnsEvaluatedInstance));
         if(!ed->Overlays) arrInitLength(&ed->Overlays,16,&ed->MaxOverlay,sizeof(tnsEvaluatedInstance));
         if(!ed->Selections) arrInitLength(&ed->Selections,16,&ed->MaxSelection,sizeof(tnsEvaluatedInstance));
+        if(!ed->MatArr) arrInitLength(&ed->MatArr,8,&ed->MaxMat,sizeof(tnsMatrix44d));
     }
-
+    tnsLoadIdentity44d(ed->MatArr[0]); ed->NextMat=1;
     for (laListItemPointer* lip=from->ChildObjects.pFirst;lip;lip=lip->pNext){
         tnsObject *o=lip->p;
         tnsEvaluateThisObject(o, ed);
         if (o->ChildObjects.pFirst){
-            tnsEvaluateObjectTree(o);
+            tnsEvaluateObjectTree(o,ed);
         }
     }
 

+ 1 - 3
la_tns_mesh.c

@@ -321,13 +321,11 @@ void tnsEvaluateMeshObject(tnsMeshObject* mo, tnsEvaluateData* ed){
         }
     }
     if(ed->FillSelectionID){
-        int i=ed->OverrideID?ed->OverrideID:mo->Base.SelectID;
-        tnsAddEvaluatedInstance(ed,mo,tnsDrawMeshObjectSelectionID,TNS_EVAL_LAYER_SELECTION,0,1,i);
+        tnsAddEvaluatedInstance(ed,mo,tnsDrawMeshObjectSelectionID,TNS_EVAL_LAYER_SELECTION,0,1,mo->Base.SelectID);
     }
     if(mo->Mode==TNS_MESH_EDIT_MODE){
         tnsAddEvaluatedInstance(ed,mo,tnsDrawMeshObjectOverlay,TNS_EVAL_LAYER_OVERLAY,0,0,0);
     }
-    
 }
 
 tnsMFace* tnsMMeshNewFace(tnsMeshObject* mo){ tnsMFace* mf=memAcquireSimple(sizeof(tnsMFace)); mf->i=mo->totmf; mo->totmf++; lstAppendItem(&mo->mf,mf); return mf; }

+ 30 - 9
resources/la_modelling.c

@@ -118,9 +118,10 @@ void la_PopulateSelectDataObjects(MSelectData* sd, tnsObject* root, tnsCamera* c
     tnsApplyCameraView(w,h,camera);
     glClearColor(0,0,0,0); glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
     glEnable(GL_DEPTH_TEST);
-    tnsInvalidateEvaluation(root); tnsSetObjectTreeEvaluationArgs(root,root->Active,1,1); tnsEvaluateObjectTree(root);
+    tnsInvalidateEvaluation(root); tnsSetObjectTreeEvaluationArgs(root,root->Active,1,1); tnsEvaluateObjectTree(root,0);
     tnsDrawObjectTree(root,TNS_EVAL_LAYER_SELECTION,0);
     glDisable(GL_DEPTH_TEST);
+    tnsEnableShaderv(T->immShader);
 }
 void la_PopulateSelectVerts(MSelectData* sd, tnsMeshObject* mo){
     arrEnsureLength(&sd->RefsV,0,&sd->maxV,sizeof(tnsMVert*));
@@ -453,7 +454,7 @@ void la_GetTransformInitialScale(MTransformData* td, laUiItem* ui, int x, int y)
 void la_GetTransformInitialRotation(MTransformData* td, laUiItem* ui, int x, int y){ td->Initial=atan2(y-ui->U-td->CenterY,x-ui->L-td->CenterX); }
 void la_GetTransformCenter2D(MTransformData* td){
     tnsVector4d vp; tnsApplyTransform44d(vp,td->ViewProjection,td->TCenter);
-    if(td->c->CameraType==TNS_PRESPECTIVE_CAMERA){ tnsVectorMultiSelf3d(vp, 1/vp[3]); }
+    if(td->c->CameraType==TNS_CAMERA_PERSP){ tnsVectorMultiSelf3d(vp, 1/vp[3]); }
     td->CenterX = (vp[0]/2+0.5f)*td->w; td->CenterY=(-vp[1]/2+0.5f)*td->h;
     if(td->CenterX<0||td->CenterY<0) { td->CenterX=td->w/2; td->CenterY=td->h/2; }
 }
@@ -1038,7 +1039,7 @@ int OPINV_Delete(laOperator *a, laEvent *e){
     if(!a->This || !a->This->EndInstance){ return 0; }
     laCanvasExtra* ex=a->This->EndInstance; tnsCamera*c=ex->ViewingCamera; laUiItem* ui=ex->ParentUi;
     tnsObject*root=ui?ui->PP.EndInstance:0; if(!root) return 0;
-    tnsMeshObject* mo=root->Active;
+    tnsMeshObject* mo=root->Active; if(!mo) return 0;
     
     if(mo->Base.Type!=TNS_OBJECT_MESH || mo->Mode!=TNS_MESH_EDIT_MODE){
         if(la_DeleteSelectedObjectsRecursive(root)){
@@ -1227,19 +1228,28 @@ int OPINV_Subdiv(laOperator *a, laEvent *e){
     return LA_FINISHED;
 }
 
+#define LA_ADD_CTX_OBJECT 0
+#define LA_ADD_CTX_MESH   1
+STRUCTURE(laObjectAddData){
+    int Context;
+};
 int OPINV_Add(laOperator *a, laEvent *e){
     if(!a->This || !a->This->EndInstance){ return 0; }
     laCanvasExtra* ex=a->This->EndInstance; tnsCamera*c=ex->ViewingCamera; laUiItem* ui=ex->ParentUi;
     tnsObject*root=ui?ui->PP.EndInstance:0; if(!root) return 0;
     tnsMeshObject* mo=root->Active; int ran=0; tnsObject* no=0;
-    
-    if((!mo) || mo->Base.Type!=TNS_OBJECT_MESH || mo->Mode!=TNS_MESH_EDIT_MODE){
-        if(strSame(strGetArgumentString(a->ExtraInstructionsP, "mode"),"PLANE")){ tnsDeselectAllObjects(root); 
+    laObjectAddData *ad=memAcquire(sizeof(laObjectAddData));a->CustomData=ad;
+    char* str=strGetArgumentString(a->ExtraInstructionsP, "mode");
+
+    if((!mo) || mo->Base.Type!=TNS_OBJECT_MESH || mo->Mode!=TNS_MESH_EDIT_MODE){ ad->Context=LA_ADD_CTX_OBJECT;
+        if(strSame(str,"PLANE")){ tnsDeselectAllObjects(root); 
             no=tnsCreateMeshPlane(root, "Plane",0,0,0,10); no->Flags|=TNS_OBJECT_FLAGS_SELECTED; memAssignRef(root,&root->Active,no); ran=1; }
+        elif(strSame(str,"INSTANCER")){ tnsDeselectAllObjects(root);
+            no=tnsCreateInstancer(root, "Instancer",0,0,0); no->Flags|=TNS_OBJECT_FLAGS_SELECTED; memAssignRef(root,&root->Active,no); ran=1; }
         else{ laEnableOperatorPanel(a,a->This,e->x,e->y,200,200,0,0,0,0,0,0,0,0,e); return LA_RUNNING; }
         if(ran){ laRecordAndPush(0,"tns.world","Add object",TNS_HINT_GEOMETRY); laNotifyUsers("tns.world"); }
-    }else{
-        if(strSame(strGetArgumentString(a->ExtraInstructionsP, "mode"),"PLANE")){
+    }else{ ad->Context=LA_ADD_CTX_MESH;
+        if(strSame(str,"PLANE")){
             tnsMMeshDeselectAll(mo); tnsAddMMeshPlane(mo, 10); tnsMMeshEnsureSelection(mo,ex->SelectMode); ran=1;
         }else{ laEnableOperatorPanel(a,a->This,e->x,e->y,200,200,0,0,0,0,0,0,0,0,e); return LA_RUNNING; }
         if(ran){
@@ -1251,6 +1261,13 @@ int OPINV_Add(laOperator *a, laEvent *e){
 }
 void laui_Add(laUiList *uil, laPropPack *pp, laPropPack *actinst, laColumn *extracol, int context){
     laColumn* c=laFirstColumn(uil);
+
+    laUiItem* b=laOnConditionThat(uil,c,laEqual(laPropExpression(actinst,"context"),laIntExpression(LA_ADD_CTX_OBJECT)));{
+        laShowLabel(uil,c,"Empty",0,0)->Flags|=LA_TEXT_MONO|LA_UI_FLAGS_DISABLED;
+        laShowItemFull(uil,c,pp,"_this_M_add",0,"mode=INSTANCER;text=Instancer",0,0);
+    }laEndCondition(uil,b);
+
+    laShowLabel(uil,c,"Primitives",0,0)->Flags|=LA_TEXT_MONO|LA_UI_FLAGS_DISABLED;
     laShowItemFull(uil,c,pp,"_this_M_add",0,"mode=PLANE;text=Plane",0,0);
 }
 
@@ -1611,7 +1628,11 @@ void la_RegisterModellingOperators(){
     laCreateOperatorType("M_make", "Make", "Make mesh primitive from selected ones", 0, 0, 0, OPINV_Make, 0, 0, 0);
     laCreateOperatorType("M_subdiv", "Subdiv", "Subdivide edges", 0, 0, 0, OPINV_Subdiv, 0, 0, 0);
     at=laCreateOperatorType("M_add", "Add", "Add mesh or primitives", 0, 0, 0, OPINV_Add, OPMOD_FinishOnData, 0, 0);
-    at->UiDefine=laui_Add;
+    at->UiDefine=laui_Add; pc = laDefineOperatorProps(at, 2);
+    p=laAddEnumProperty(pc,"context","Context","Context of adding",0,0,0,0,0,offsetof(laObjectAddData,Context),0,0,0,0,0,0,0,0,0,0);
+    laAddEnumItemAs(p,"OBJECT","Object","Object context",LA_ADD_CTX_OBJECT,0);
+    laAddEnumItemAs(p,"MESH","Mesh","Mesh context",LA_ADD_CTX_MESH,0);
+
     laCreateOperatorType("M_separate", "Separate", "Separate mesh parts", 0, 0, 0, OPINV_Separate, 0, 0, 0);
     laCreateOperatorType("M_combine", "Combine", "Combine mesh objects", 0, 0, 0, OPINV_Combine, 0, 0, 0);
     laCreateOperatorType("M_duplicate", "Duplicate", "Duplicate objects", 0, 0, 0, OPINV_Duplicate, OPMOD_Transformation, 0, 0);

+ 20 - 10
resources/la_properties.c

@@ -823,10 +823,11 @@ void tnsset_MeshObjectFaceRaw(tnsMeshObject* o, int* data, int s){
 
 laPropContainer* tnsget_ObjectType(tnsObject* o){
     switch(o->Type){
-    case TNS_OBJECT_EMPTY: default: return TNS_PC_OBJECT_GENERIC;
-    case TNS_OBJECT_CAMERA: return TNS_PC_OBJECT_CAMERA;
-    case TNS_OBJECT_MESH:   return TNS_PC_OBJECT_MESH;
-    case TNS_OBJECT_LIGHT:  return TNS_PC_OBJECT_LIGHT;
+    case TNS_OBJECT_INSTANCER: return TNS_PC_OBJECT_INSTANCER;
+    case TNS_OBJECT_CAMERA:    return TNS_PC_OBJECT_CAMERA;
+    case TNS_OBJECT_MESH:      return TNS_PC_OBJECT_MESH;
+    case TNS_OBJECT_LIGHT:     return TNS_PC_OBJECT_LIGHT;
+    default: return TNS_PC_OBJECT_GENERIC;
     }
 }
 
@@ -855,6 +856,7 @@ laPropContainer* LA_PROP_SOCKET_SOURCE;
 laPropContainer* LA_PROP_SOCKET_OUT;
 laPropContainer* LA_PC_MAPPER;
 laPropContainer* TNS_PC_OBJECT_GENERIC;
+laPropContainer* TNS_PC_OBJECT_INSTANCER;
 laPropContainer* TNS_PC_OBJECT_CAMERA;
 laPropContainer* TNS_PC_OBJECT_LIGHT;
 laPropContainer* TNS_PC_OBJECT_MESH;
@@ -1538,7 +1540,7 @@ void la_RegisterInternalProps(){
         laAddSubGroup(p, "object", "Object", "Object link", "tns_object",tnsget_ObjectType, 0,0,offsetof(laListItemPointer, p), 0,0,0,0,0,0,0,LA_UDF_REFER);
     }
 
-    p = laAddPropertyContainer("tns_object", "Object", "3D Object Item", 0,0,sizeof(tnsObject), tnspost_Object, 0,2);{
+    p = laAddPropertyContainer("tns_object", "Object", "3D Object Item", 0,tnsui_BaseObjectProperties,sizeof(tnsObject), tnspost_Object, 0,2);{
         laPropContainerExtraFunctions(p,0,0,0,tnspropagate_Object,0);
         laContainerAnimationFunctions(p,laaction_VerifyRootObject);
         TNS_PC_OBJECT_GENERIC=p;
@@ -1553,7 +1555,7 @@ void la_RegisterInternalProps(){
             laAddEnumItem(ep, "true", "IsTrue", "IsTrue", U'📷');
         }
         ep = laAddEnumProperty(p, "type", "Type", "Object Type Like Mesh,Camera And Lamp", 0,0,0,0,0,offsetof(tnsObject, Type), 0,0,0,0,0,0,0,0,0,LA_READ_ONLY);{
-            laAddEnumItemAs(ep, "EMPTY", "Empty", "Empty object, not rendered", 0,U'➕');
+            laAddEnumItemAs(ep, "INSTANCER", "Instancer", "Instancer object", TNS_OBJECT_INSTANCER, 0);
             laAddEnumItemAs(ep, "CAMERA", "Camera", "Camera object, to render a scene", TNS_OBJECT_CAMERA, U'📷');
             laAddEnumItemAs(ep, "LIGHT", "Lamp", "Lamp object, to illuminate the scene", TNS_OBJECT_LIGHT, 0);
             laAddEnumItemAs(ep, "MESH", "Mesh", "Mesh object, made of verts/edges/faces", TNS_OBJECT_MESH, 0);
@@ -1575,7 +1577,7 @@ void la_RegisterInternalProps(){
             laAddEnumItem(ep, "zxy", "ZXY", "ZXY Euler Mode", 0); laAddEnumItem(ep, "zyx", "ZYX", "ZYX Euler Mode", 0);
             laAddEnumItem(ep, "quaternion", "Quaternion", "Quaternion Mode", 0);
         }
-        laAddSubGroup(p, "active", "Active", "Active reference", "tns_object",0,0,0,offsetof(tnsObject, Active), 0,0,0,0,0,0,0,LA_UDF_REFER|LA_READ_ONLY);
+        laAddSubGroup(p, "active", "Active", "Active reference", "tns_object",tnsget_ObjectType,0,0,offsetof(tnsObject, Active), 0,0,0,0,0,0,0,LA_UDF_REFER|LA_READ_ONLY);
         laAddSubGroup(p, "in_root", "In Root", "Root object of this object", "tns_object",0,0,0,offsetof(tnsObject, InRoot), 0,0,0,0,0,0,0,LA_UDF_REFER);
         laAddSubGroup(p, "parent", "Parent", "Object parent", "tns_object",0,0,0,offsetof(tnsObject, ParentObject), 0,0,0,0,0,0,0,LA_UDF_REFER);
         laAddSubGroup(p, "children", "Children", "The Children Of This Object", "tns_child_object",0,0,0,-1, 0,0,0,0,0,0,offsetof(tnsObject, ChildObjects), 0);
@@ -1583,7 +1585,15 @@ void la_RegisterInternalProps(){
         laAddSubGroup(p, "drivers", "Drivers", "Driver page collection","la_driver_collection",0,0,0,offsetof(tnsObject,Drivers),0,0,0,0,0,0,0,LA_UDF_SINGLE);
         laAddOperatorProperty(p, "add_driver_page", "Add Page", "Add a driver page","LA_add_driver_page",'+',0);
     }
-    p = laAddPropertyContainer("tns_mesh_object", "Mesh Object", "Mesh object", 0,0,sizeof(tnsMeshObject), tnspost_Object, 0,2);{
+    p = laAddPropertyContainer("tns_instancer", "Instancer", "Instance placeholder object", U'📎', tnsui_InstancerObjectProperties,sizeof(tnsInstancer), 0,0,2);{
+        laPropContainerExtraFunctions(p,0,0,tnstouched_Object,0/*tnspropagate_Object*/,0);
+        TNS_PC_OBJECT_INSTANCER=p;
+        laAddStringProperty(p, "name", "Object Name", "The Name Of The Object", 0,0,0,0,1, offsetof(tnsObject, Name), 0,0,0,0,LA_AS_IDENTIFIER);
+        laAddSubGroup(p, "base", "Base", "Object base", "tns_object",0,0,0,0,0,0,0,0,0,0,0,LA_UDF_LOCAL);
+        laAddSubGroup(p, "default_instance", "Instance", "Default instance to be used during editing", "tns_object",0,0,0,offsetof(tnsInstancer, DefaultInstance), 0,0,0,0,0,0,0,LA_UDF_REFER);
+        laAddSubGroup(p, "runtime_instance", "Runtime Instance", "Runtime instance, not saved", "tns_object",0,0,0,offsetof(tnsInstancer, RuntimeInstance), 0,0,0,0,0,0,0,LA_UDF_REFER|LA_UDF_IGNORE);
+    }
+    p = laAddPropertyContainer("tns_mesh_object", "Mesh Object", "Mesh object", 0,tnsui_MeshObjectProperties,sizeof(tnsMeshObject), tnspost_Object, 0,2);{
         laPropContainerExtraFunctions(p,0,0,tnstouched_Object,0/*tnspropagate_Object*/,0);
         TNS_PC_OBJECT_MESH=p;
         laAddStringProperty(p, "name", "Object Name", "The Name Of The Object", 0,0,0,0,1, offsetof(tnsObject, Name), 0,0,0,0,LA_AS_IDENTIFIER);
@@ -1608,7 +1618,7 @@ void la_RegisterInternalProps(){
         //laAddIntProperty(p, "maxe", "Max Edge", "Max Edge count", 0,0,0,0,0,0,0,0,offsetof(tnsMeshObject, maxe),0,0,0,0,0,0,0,0,0,0,LA_READ_ONLY);
         //laAddIntProperty(p, "maxf", "Max Face", "Max Face count", 0,0,0,0,0,0,0,0,offsetof(tnsMeshObject, maxf),0,0,0,0,0,0,0,0,0,0,LA_READ_ONLY);
     }
-    p = laAddPropertyContainer("tns_camera", "Camera", "Camera object", U'📷', 0,sizeof(tnsCamera), 0,0,2);{
+    p = laAddPropertyContainer("tns_camera", "Camera", "Camera object", U'📷', tnsui_CameraObjectProperties,sizeof(tnsCamera), 0,0,2);{
         //laPropContainerExtraFunctions(p,0,0,0,tnspropagate_Object,0);
         TNS_PC_OBJECT_CAMERA=p;
         laAddStringProperty(p, "name", "Object Name", "The Name Of The Object", 0,0,0,0,1, offsetof(tnsObject, Name), 0,0,0,0,LA_AS_IDENTIFIER);
@@ -1623,7 +1633,7 @@ void la_RegisterInternalProps(){
         laAddFloatProperty(p, "orth_scale", "Scale", "Orthographical Camera Scale", 0,0,"^^", 1000,0.001, 0.1, 1, 0,offsetof(tnsCamera, OrthScale), 0,0,0,0,0,0,0,0,0,0,0);
         //laAddOperatorProperty(p, "set_active", "Set Active", "Set this camera as the active one", "TNS_set_active_camera", 0,0);
     }
-    p = laAddPropertyContainer("tns_light", "Light", "Light object", U'🔅', 0,sizeof(tnsLight), 0,0,2);{
+    p = laAddPropertyContainer("tns_light", "Light", "Light object", U'🔅', tnsui_LightObjectProperties,sizeof(tnsLight), 0,0,2);{
         //laPropContainerExtraFunctions(p,0,0,0,tnspropagate_Object,0);
         TNS_PC_OBJECT_LIGHT=p;
         laAddStringProperty(p, "name", "Object Name", "The Name Of The Object", 0,0,0,0,1, offsetof(tnsObject, Name), 0,0,0,0,LA_AS_IDENTIFIER);

+ 78 - 69
resources/la_templates.c

@@ -201,12 +201,8 @@ void laui_SubPropInfoDefault(laUiList *uil, laPropPack *Base, laPropPack *Operat
     char buf[LA_RAW_CSTR_MAX_LEN]={0};
 
     c = laFirstColumn(uil);
-    laSplitColumn(uil, c, 0.2);
-    cl = laLeftColumn(c, 1);
-    cr = laRightColumn(c, 0);
-    laSplitColumn(uil, cr, 0.5);
-    crrl = laLeftColumn(cr, 1*6);
-    crrr = laRightColumn(cr, 0);
+    laSplitColumn(uil, c, 0.2); cl = laLeftColumn(c, 1); cr = laRightColumn(c, 0);
+    laSplitColumn(uil, cr, 0.5); crrl = laLeftColumn(cr, 1*6); crrr = laRightColumn(cr, 0);
 
     laPropContainer* subc=Base->LastPs->p->SubProp;
     if (!((laSubProp*)Base->LastPs->p)->GetType){
@@ -245,7 +241,7 @@ void laui_SubPropInfoDefault(laUiList *uil, laPropPack *Base, laPropPack *Operat
                 sprintf(buf, "text=...%s;", p->Name);
                 strSafeSet(&b1->ExtraInstructions, buf);
                 laUiDefineFunc f=laui_SubPropInfoDefault;
-                if(!context) f=((laSubProp*)p)->GetType?0:(p->UiDefine?p->UiDefine:(p->SubProp&&p->SubProp->UiDefine?p->SubProp->UiDefine:laui_SubPropInfoDefault));
+                //if(!context) f=((laSubProp*)p)->GetType?0:(p->UiDefine?p->UiDefine:(p->SubProp&&p->SubProp->UiDefine?p->SubProp->UiDefine:laui_SubPropInfoDefault));
                 laShowItemFull(uil, cr, Base, p->Identifier, 0,0, f, context);
             }
             laEndCondition(uil, b1);
@@ -828,67 +824,6 @@ void laui_UiTemplateListItem(laUiList *uil, laPropPack *Base, laPropPack *UNUSED
     laEndCondition(uil, bracket);
 }
 
-void tnsui_GroupItem(laUiList *uil, laPropPack *Base, laPropPack *UNUSED_This, laColumn *UNUSED_Colums, int context){
-    laColumn *col, *cl, *cr, *crl, *crr;
-    laUiItem *b1;
-
-    col = laFirstColumn(uil);
-    laSplitColumn(uil, col, 0.3);
-    cl = laLeftColumn(col, 1);
-    cr = laRightColumn(col, 0);
-    laSplitColumn(uil, cr, 0.5);
-    crl = laLeftColumn(cr, 0);
-    crr = laRightColumn(cr, 0);
-
-    laShowItem(uil, cr, Base, "name");
-    b1 = laOnConditionToggle(uil, cl, 0, 0, 0, 0, 0);{
-        laShowItem(uil, cr, Base, "objects");
-    }
-    laEndCondition(uil, b1);
-}
-void tnsui_ObjectGroupItem(laUiList *uil, laPropPack *Base, laPropPack *UNUSED_This, laColumn *UNUSED_Colums, int context){
-    laColumn *col, *cl, *cr, *crl, *crr;
-    laUiItem *b1;
-
-    col = laFirstColumn(uil);
-    laSplitColumn(uil, col, 0.3);
-    cl = laLeftColumn(col, 1);
-    cr = laRightColumn(col, 0);
-    laSplitColumn(uil, cr, 0.5);
-    crl = laLeftColumn(cr, 0);
-    crr = laRightColumn(cr, 0);
-
-    laShowItem(uil, cr, Base, "group.name");
-}
-void tnsui_GroupObjectItem(laUiList *uil, laPropPack *Base, laPropPack *UNUSED_This, laColumn *UNUSED_Colums, int context){
-    laColumn *col, *cl, *cr, *crl, *crr;
-    laUiItem *b1;
-
-    col = laFirstColumn(uil);
-    laSplitColumn(uil, col, 0.3);
-    cl = laLeftColumn(col, 1);
-    cr = laRightColumn(col, 0);
-    laSplitColumn(uil, cr, 0.5);
-    crl = laLeftColumn(cr, 0);
-    crr = laRightColumn(cr, 0);
-
-    laShowItem(uil, cr, Base, "object.identifier");
-}
-void tnsui_MaterialItem(laUiList *uil, laPropPack *Base, laPropPack *UNUSED_This, laColumn *UNUSED_Colums, int context){
-    laColumn *col, *cl, *cr, *crl, *crr;
-    laUiItem *b1;
-
-    col = laFirstColumn(uil);
-    laSplitColumn(uil, col, 0.3);
-    cl = laLeftColumn(col, 1);
-    cr = laRightColumn(col, 0);
-    laSplitColumn(uil, cr, 0.5);
-    crl = laLeftColumn(cr, 0);
-    crr = laRightColumn(cr, 0);
-
-    laShowItem(uil, cr, Base, "object.identifier");
-}
-
 void laui_PlainSceneListItem(laUiList *uil, laPropPack *This, laPropPack *OP_UNUSED, laColumn *Extra, int context){
     laColumn *col = Extra, *c, *cl, *cr, *crl, *crr, *cll, *clr, *clrl, *clrr, *clrrl, *clrrr;
     laUiItem *ui;
@@ -1583,7 +1518,6 @@ void laui_Drivers(laUiList *uil, laPropPack *This, laPropPack *Extra, laColumn *
     }laEndCondition(uil,b2);
 }
 
-
 void laui_AnimationActionSimple(laUiList *uil, laPropPack *This, laPropPack *Extra, laColumn *ExtraColumns, int context){
     laColumn* c=laFirstColumn(uil);
     laUiItem* b=laBeginRow(uil,c,0,0);{
@@ -1699,7 +1633,82 @@ void laui_AnimationActionChannels(laUiList *uil, laPropPack *This, laPropPack *E
 }
 
 
+void tnsui_CameraObjectProperties(laUiList *uil, laPropPack *This, laPropPack *UNUSED_Extra, laColumn *UNUSED_Colums, int context){
+    laColumn* c=laFirstColumn(uil);
+    laShowLabel(uil,c,"Camera Object",0,0)->Flags|=LA_TEXT_ALIGN_CENTER|LA_UI_FLAGS_DISABLED; 
+}
+void tnsui_LightObjectProperties(laUiList *uil, laPropPack *This, laPropPack *UNUSED_Extra, laColumn *UNUSED_Colums, int context){
+    laColumn* c=laFirstColumn(uil);
+    laShowLabel(uil,c,"Light Object",0,0)->Flags|=LA_TEXT_ALIGN_CENTER|LA_UI_FLAGS_DISABLED; 
+}
+void tnsui_MeshObjectProperties(laUiList *uil, laPropPack *This, laPropPack *UNUSED_Extra, laColumn *UNUSED_Colums, int context){
+    laColumn* c=laFirstColumn(uil);
+    laShowLabel(uil,c,"Mesh Object",0,0)->Flags|=LA_TEXT_ALIGN_CENTER|LA_UI_FLAGS_DISABLED; 
+}
+void tnsui_InstancerObjectProperties(laUiList *uil, laPropPack *This, laPropPack *UNUSED_Extra, laColumn *UNUSED_Colums, int context){
+    laColumn* c=laFirstColumn(uil), *cl,*cr;
+    laSplitColumn(uil,c,0.5); cl=laLeftColumn(c,5); cr=laRightColumn(c,0);
+    laShowLabel(uil,cl,"Instance",0,0); laShowItemFull(uil,cr,This,"default_instance",LA_WIDGET_COLLECTION_SELECTOR,0,laui_IdentifierOnly,0);
+    laShowLabel(uil,cl,"Runtime",0,0); laShowItemFull(uil,cr,This,"runtime_instance",LA_WIDGET_COLLECTION_SELECTOR,0,laui_IdentifierOnly,0);
+}
+void tnsui_BaseObjectProperties(laUiList *uil, laPropPack *This, laPropPack *UNUSED_Extra, laColumn *UNUSED_Colums, int context){
+    laColumn* c=laFirstColumn(uil); laUiItem* g; laUiList* gu; laColumn* gc,*gcl,*gcr;
+    g=laMakeGroup(uil,c,"Object",0); gu=g->Page; gc=laFirstColumn(gu);
+
+    laUiItem* b1=laOnConditionToggle(gu,gc,0,0,0,0,0);{ strSafeSet(&b1->ExtraInstructions,"text=Transformations");
+        //b1->State=LA_UI_ACTIVE;
+        laSplitColumn(gu,gc,0.5); gcl=laLeftColumn(gc,0); gcr=laRightColumn(gc,0);
+        laShowLabel(gu,gcl,"Location",0,0); laShowItem(gu,gcl,This,"location")->Flags|=LA_UI_FLAGS_TRANSPOSE;
+        laShowLabel(gu,gcr,"Rotation",0,0); laShowItem(gu,gcr,This,"rotation")->Flags|=LA_UI_FLAGS_TRANSPOSE;
+        laShowLabel(gu,gcl,"Scale",0,0);    laShowItem(gu,gcr,This,"scale");
+        laUiItem* b=laOnConditionToggle(gu,gc,0,0,0,0,0);{ strSafeSet(&b->ExtraInstructions,"text=Delta");
+            laShowLabel(gu,gcl,"Delta Loc",0,0); laShowItem(gu,gcl,This,"dlocation")->Flags|=LA_UI_FLAGS_TRANSPOSE;
+            laShowLabel(gu,gcr,"Delta Rot",0,0); laShowItem(gu,gcr,This,"drotation")->Flags|=LA_UI_FLAGS_TRANSPOSE;
+            laShowLabel(gu,gcl,"Delta Scale",0,0);laShowItem(gu,gcr,This,"dscale");
+        }laEndCondition(gu,b);
+        laShowSeparator(gu,gc);
+    }laEndCondition(gu,b1);
+}
+
+void tnsuidetached_ObjectProperties(laPanel* p){
+    la_MakeDetachedProp(p, "la.detached_view_switch", "detached");
+    la_MakeDetachedProp(p, "tns.world.root_objects", "root_object");
+}
+void tnsui_ObjectProperties(laUiList *uil, laPropPack *This, laPropPack *Extra, laColumn *UNUSED, int context){
+    laColumn* c=laFirstColumn(uil),*cl, *cr;
+    laSplitColumn(uil,c,0.2); cl=laLeftColumn(c,1); cr=laRightColumn(c,0);
+
+    laShowItemFull(uil,cl,Extra,"detached",0,0,0,0)->Flags|=LA_UI_FLAGS_HIGHLIGHT|LA_UI_FLAGS_ICON;
+
+    laUiItem* b=laBeginRow(uil,cr,0,0);
+
+    laUiItem* rb=laShowItemFull(uil,cr,Extra,"root_object",LA_WIDGET_COLLECTION_SELECTOR,0,laui_IdentifierOnly,0);
+    rb->Flags|=LA_UI_COLLECTION_SIMPLE_SELECTOR;
+
+    laUiItem* b2=laOnConditionThat(uil,cr,laPropExpression(&rb->PP,""));{
+        laShowItem(uil,cr,&rb->PP,"name")->Flags|=LA_UI_FLAGS_NO_DECAL;
+        laUiItem* b3=laOnConditionThat(uil,cr,laPropExpression(&rb->PP,"active"));{
+            laShowLabel(uil,cr,"⯈",0,0); laShowItem(uil,cr,&rb->PP,"active.name")->Flags|=LA_UI_FLAGS_NO_DECAL;
+        }laEndCondition(uil,b3);
+    }laEndCondition(uil,b2);
+
+    laEndRow(uil,b);
+
+    laUiItem* g; laUiList* gu; laColumn* gc;
+    g=laMakeEmptyGroup(uil,c,"Object",0); gu=g->Page; gc=laFirstColumn(gu); g->Flags|=LA_UI_FLAGS_NO_DECAL;
+
+    b2=laOnConditionThat(gu,gc,laPropExpression(Extra,"detached"));{
+        laUiItem* actui=laShowItem(gu,gc,&rb->PP,"active"); actui->Flags|=LA_UI_COLLECTION_NO_HIGHLIGHT|LA_UI_FLAGS_NO_DECAL;
+        tnsui_BaseObjectProperties(gu,&actui->PP,0,0,0);
+    }laElse(gu,b2);{
+        laUiItem* actui=laShowItemFull(gu,gc,0,"tns.world.root_objects",LA_WIDGET_COLLECTION_SINGLE,0,0,0);
+        actui->Flags|=LA_UI_COLLECTION_NO_HIGHLIGHT|LA_UI_FLAGS_NO_DECAL;
+        tnsui_BaseObjectProperties(gu,&actui->PP,0,0,0);
+    }laEndCondition(gu,b2);
+}
+
 void la_RegisterBuiltinTemplates(){
+    laRegisterUiTemplate("LAUI_object_properties", "Properties", tnsui_ObjectProperties, tnsuidetached_ObjectProperties, 0, 0, 0,15,25);
     laRegisterUiTemplate("LAUI_animation_actions", "Actions", laui_AnimationActions, 0, 0, 0, 0,15,25);
     laRegisterUiTemplate("LAUI_animation_action_channels", "Action Channels", laui_AnimationActionChannels, 0, 0, 0, 0,20,15);
     laRegisterUiTemplate("LAUI_input_mapper","Input Mapper",laui_InputMapper,0,0,"Controlling",0,0,0);

+ 1 - 0
resources/la_widgets.c

@@ -1724,6 +1724,7 @@ void la_RegisterUiTypesBasic(){
     _LA_UI_IMAGE = la_RegisterUiType("LA_image_default", 0, 0, &_LA_THEME_COLLECTION_GROUP, la_ImageDraw, la_ImageGetHeight, la_ImageUiInit, la_ImageUiDestroy);
     _LA_UI_IMAGE->GetMinWidth=la_ImageGetMinWidth;
 
+    _LA_UI_INVISIBLE.Theme=&_LA_THEME_BUTTON;
     _LA_UI_ROW_BEGIN.Theme=&_LA_THEME_BUTTON;
     _LA_UI_ROW_END.Theme=&_LA_THEME_BUTTON;
 }

+ 109 - 86
resources/la_widgets_viewers.c

@@ -131,7 +131,6 @@ void la_RootObjectDraw(laBoxedTheme *bt, tnsObject *root, laUiItem* ui){
 
     }else if(e->OffScrShadow){ tnsDelete2DOffscreen(e->OffScrShadow); }
 
-
     //{
     //    tnsDrawToOffscreen(e->OffScr, 1, 0);
     //    //tnsUseShader(T->TEST_MatcapShader);
@@ -155,19 +154,20 @@ void la_RootObjectDraw(laBoxedTheme *bt, tnsObject *root, laUiItem* ui){
 
     if(root){
         tnsSetObjectTreeEvaluationArgs(root,root->Active,1,1);
-        tnsEvaluateObjectTree(root);
+        tnsEvaluateObjectTree(root, 0);
 
         glEnable(GL_DEPTH_TEST); glDisable(GL_BLEND);
 
-        tnsUseShader(T->immShader); tnsEnableShaderv(T->immShader);
+        tnsUseShader(T->immShader); tnsEnableShaderv(T->immShader); tnsUseNoTexture();
         tnsUnbindTexture(); tnsUniformUseTexture(T->immShader,0,0); tnsUseMultiplyColor(0);
         tnsDrawObjectTree(root,TNS_EVAL_LAYER_SOLID,0);
         
         glLineWidth(3); 
-        glEnable(GL_POLYGON_OFFSET_LINE); glPolygonOffset(-1,-1);
+        tnsUniformUseOffset(T->immShader,1);
         glDepthMask(GL_FALSE); glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
         tnsDrawObjectTree(root,TNS_EVAL_LAYER_OUTLINE,0);
         glDepthMask(GL_TRUE); glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+        tnsUniformUseOffset(T->immShader,0);
         glLineWidth(1);
         glDisable(GL_POLYGON_OFFSET_LINE);
     }
@@ -470,98 +470,107 @@ void la_CanvasDrawOverlay(laUiItem *ui, int h){
 int la_AnimateUiListRecursive(laUiList *uil);
 
 void laDefault3DViewOverlay(laUiItem *ui){
-    laUiList *uil, *gu;
-    laColumn *c, *cl, *cll, *clr, *cr, *crl, *crr, *gc, *gcl, *gcr;
+    laUiList *uil, *gu,*muil,*gu2;
+    laColumn *c, *cl, *cr,  *gc, *gcl, *gcr, *mc,*gc2;
     laPropPack *e = &ui->ExtraPP;
-    laUiItem *b, *g, *b1;
+    laUiItem *b, *g, *b1, *b2,*g2;
 
     if (!(uil = ui->Subs.pFirst)) uil = laAddTabPage(ui, "New Group");
 
     c = laFirstColumn(uil);
-    laSplitColumn(uil, c, 0.8);
-    cl = laLeftColumn(c, 0);
-    cr = laRightColumn(c, 0);
-    laSplitColumn(uil, cl, 0.25);
-    cll = laLeftColumn(cl, 0);
-    clr = laRightColumn(cl, 0);
+    laSplitColumn(uil, c, 0.8); cl = laLeftColumn(c, 0); cr = laRightColumn(c, 0);
 
-    laShowColumnAdjuster(uil, c);
+    b=laBeginRow(uil,c,0,0);
+    laUiItem* activeui=laShowInvisibleItem(uil,c,&ui->PP,"active");
 
-    g = laMakeFoldableGroup(uil, cll, "Tools", 0, 1, 0);{
-        gu = g->Page; gc = laFirstColumn(gu);
-        laSplitColumn(gu, gc, 0.35); gcl = laLeftColumn(gc, 0); gcr = laRightColumn(gc, 0);
-        laShowItem(gu,gc,&ui->ExtraPP,"_this_M_delete");
-        laShowItem(gu,gc,&ui->ExtraPP,"_this_M_make_parent");
-        laShowItem(gu,gc,&ui->ExtraPP,"_this_M_unparent");
-        laShowItem(gu,gc,&ui->ExtraPP,"_this_M_add");
-        laShowItem(gu,gc,&ui->ExtraPP,"_this_M_grab");
-        laShowItem(gu,gc,&ui->ExtraPP,"_this_M_scale");
-        laShowItem(gu,gc,&ui->ExtraPP,"_this_M_rotate");
-        laShowItem(gu,gc,&ui->ExtraPP,"_this_M_clear_transformations");
-        laShowItem(gu,gc,&ui->ExtraPP,"_this_M_extrude");
-        laShowItem(gu,gc,&ui->ExtraPP,"_this_M_make");
-        laShowItem(gu,gc,&ui->ExtraPP,"_this_M_knife");
-        laShowItemFull(gu,gc,&ui->ExtraPP,"_this_M_knife",0,"mode=loop_cut;text=Loop Cut",0,0);
-        laShowItem(gu,gc,&ui->ExtraPP,"_this_M_merge");
-        laShowItem(gu,gc,&ui->ExtraPP,"_this_M_subdiv");
-        laShowItem(gu,gc,&ui->ExtraPP,"_this_M_separate");
-        laShowItem(gu,gc,&ui->ExtraPP,"_this_M_combine");
-        laShowItem(gu,gc,&ui->ExtraPP,"_this_M_duplicate");
-        laShowItem(gu,gc,&ui->ExtraPP,"_this_M_recalculate_normals");
+    muil=laMakeMenuPage(uil,c,"👁"); mc=laFirstColumn(muil);{
+        laSplitColumn(muil, mc, 0.3); gcl = laLeftColumn(mc, 0); gcr = laRightColumn(mc, 0);
+        laShowLabel(muil,gcl,"Floor:",0,0); laShowLabel(muil,gcr,"Axis:",0,0);
+        laShowItem(muil,gcl,&ui->ExtraPP,"show_floor_grid")->Flags|=LA_UI_FLAGS_ICON|LA_UI_FLAGS_CYCLE;
+        laShowItem(muil,gcr,&ui->ExtraPP,"show_axis")->Flags|=LA_UI_FLAGS_TRANSPOSE|LA_UI_FLAGS_ICON;
     }
 
-    g = laMakeFoldableGroup(uil, cr, "Scene Info", 0, 1, 0);{
-        gu = g->Page;
-        gc = laFirstColumn(gu);
-        laSplitColumn(gu, gc, 0.35);
-        gcl = laLeftColumn(gc, 0);
-        gcr = laRightColumn(gc, 0);
-        laShowItemFull(gu, gc, &ui->PP, 0, LA_WIDGET_COLLECTION_SELECTOR,0,laui_IdentifierOnly,0);
-        laShowLabel(gu, gcl, "Rename:", 0, 0);
-        laShowItem(gu, gcr, &ui->PP, "name");
+    muil=laMakeMenuPage(uil,c,"Transform"); mc=laFirstColumn(muil);{
+        laShowItem(muil,mc,&ui->ExtraPP,"_this_M_grab");
+        laShowItem(muil,mc,&ui->ExtraPP,"_this_M_scale");
+        laShowItem(muil,mc,&ui->ExtraPP,"_this_M_rotate");
+        laShowSeparator(muil,mc);
+        laShowItem(muil,mc,&ui->ExtraPP,"_this_M_clear_transformations");
     }
-    g = laMakeFoldableGroup(uil, cr, "Object Info", 0, 0, 0);{
-        gu = g->Page;
-        gc = laFirstColumn(gu);
-        laSplitColumn(gu, gc, 0.5);
-        gcl = laLeftColumn(gc, 6);
-        gcr = laRightColumn(gc, 0);
 
-        b1=laOnConditionThat(gu,gc,laPropExpression(&ui->PP,"active"));{
-            laShowItem(gu, gc, &ui->PP, "active.name");
-            b=laOnConditionThat(gu,gc,laPropExpression(&ui->ExtraPP, "delta_mode"));{
-                laShowLabel(gu, gcl, "DLoc:", 0, 0);laShowItem(gu, gcr, &ui->PP, "active.dlocation")->Flags|=LA_UI_FLAGS_TRANSPOSE;
-                laShowSeparator(gu,gc);
-                laShowLabel(gu, gcl, "DRot:", 0, 0);laShowItem(gu, gcr, &ui->PP, "active.drotation")->Flags|=LA_UI_FLAGS_TRANSPOSE;
-                laShowItem(gu, gc, &ui->PP, "active.dscale");
-            }laElse(gu,b);{
-                laShowLabel(gu, gcl, "Loc:", 0, 0);laShowItem(gu, gcr, &ui->PP, "active.location")->Flags|=LA_UI_FLAGS_TRANSPOSE;
-                laShowSeparator(gu,gc);
-                laShowLabel(gu, gcl, "Rot:", 0, 0);laShowItem(gu, gcr, &ui->PP, "active.rotation")->Flags|=LA_UI_FLAGS_TRANSPOSE;
-                laShowItem(gu, gc, &ui->PP, "active.scale");
-            }laEndCondition(gu,b);
-        }laElse(gu,b1);{
-            laShowLabel(gu, gc, "No active object.", 0, 0);
-        }laEndCondition(gu,b1);
+    muil=laMakeMenuPage(uil,c,"Object"); mc=laFirstColumn(muil);{
+        laShowItem(muil,mc,&ui->ExtraPP,"_this_M_add");
+        laShowSeparator(muil,mc);
+        laShowItem(muil,mc,&ui->ExtraPP,"_this_M_make_parent");
+        laShowItem(muil,mc,&ui->ExtraPP,"_this_M_unparent");
+        laShowSeparator(muil,mc);
+        laShowItem(muil,mc,&ui->ExtraPP,"_this_M_duplicate");
+        laShowItem(muil,mc,&ui->ExtraPP,"_this_M_combine");
+        laShowSeparator(muil,mc);
+        laShowItem(muil,mc,&ui->ExtraPP,"_this_M_delete");
     }
-    g = laMakeFoldableGroup(uil, cr, "Display", 0, 1, 0);{
-        gu = g->Page;
-        gc = laFirstColumn(gu);
-        laSplitColumn(gu, gc, 0.35);
-        gcl = laLeftColumn(gc, 0);
-        gcr = laRightColumn(gc, 0);
 
-        laShowLabel(gu, gcl, "Axis:", 0, 0);
-        laWidget w={_LA_UI_ENUM_SELECTOR, LA_UI_FLAGS_ICON|LA_UI_FLAGS_CYCLE|LA_UI_FLAGS_TRANSPOSE};
-        laShowItemFull(gu, gcr, e, "show_axis",&w, "show_prefix=true;" ,0,0);
-        laShowLabel(gu, gcl, "Floor Grid:", 0, 0);
-        laShowItemFull(gu, gcr, e, "show_floor_grid", LA_WIDGET_ENUM_CYCLE, 0, 0, 0);
-        laShowItem(gu, gc, e, "grid_size");
-        laShowItem(gu, gc, e, "grid_span");
+    b1=laOnConditionThat(uil,c,laPropExpression(&activeui->PP,0));{
+        b2=laOnConditionThat(uil,c,laEqual(laPropExpression(&activeui->PP,"type"),laIntExpression(TNS_OBJECT_MESH)));{
+            muil=laMakeMenuPage(uil,c,"Mesh"); mc=laFirstColumn(muil);{
+                laShowItem(muil,mc,&ui->ExtraPP,"_this_M_extrude");
+                laShowItem(muil,mc,&ui->ExtraPP,"_this_M_make");
+                laShowItem(muil,mc,&ui->ExtraPP,"_this_M_knife");
+                laShowItemFull(muil,mc,&ui->ExtraPP,"_this_M_knife",0,"mode=loop_cut;text=Loop Cut",0,0);
+                laShowSeparator(muil,mc);
+                laShowItem(muil,mc,&ui->ExtraPP,"_this_M_duplicate");
+                laShowItem(muil,mc,&ui->ExtraPP,"_this_M_merge");
+                laShowItem(muil,mc,&ui->ExtraPP,"_this_M_separate");
+                laShowSeparator(muil,mc);
+                laShowItem(muil,mc,&ui->ExtraPP,"_this_M_subdiv");
+                laShowItem(muil,mc,&ui->ExtraPP,"_this_M_recalculate_normals");
+                laShowSeparator(muil,mc);
+                laShowItem(muil,mc,&ui->ExtraPP,"_this_M_delete");
+            }
+            laShowSeparator(uil,c);
+            laShowItem(uil,c,&ui->ExtraPP,"select_mode")->Flags|=LA_UI_FLAGS_EXPAND;
+            laShowItem(uil,c,&ui->ExtraPP,"select_through");
+        }laEndCondition(uil,b2);
+    }laEndCondition(uil,b1);
 
-        //laShowLabel(gu, gcl, "NPR:", 0, 0);
-        //laShowItemFull(gu, gcr, e, "npr_line_mode", LA_WIDGET_ENUM_CYCLE, 0, 0, 0);
-    }
+
+    laShowSeparator(uil,c)->Expand=1;
+
+    laShowItem(uil,c,&ui->ExtraPP,"delta_mode")->Flags|=LA_UI_FLAGS_CYCLE|LA_UI_FLAGS_HIGHLIGHT;
+    laShowItem(uil,c,&ui->ExtraPP,"show_details")->Flags|=LA_UI_FLAGS_ICON;
+
+    laEndRow(uil,b);
+
+    b=laOnConditionThat(uil,c,laPropExpression(&ui->ExtraPP,"show_details"));{
+        laShowColumnAdjuster(uil,c);
+
+        g2 = laMakeEmptyGroup(uil, cr, "Info", 0);{
+            gu2 = g2->Page; gc2 = laFirstColumn(gu2); gu2->HeightCoeff=-1; g2->Flags|=LA_UI_FLAGS_NO_DECAL;
+            g = laMakeGroup(gu2, gc2, "Scene Info", 0);{ gu = g->Page; gc = laFirstColumn(gu);
+            laShowLabel(gu, gcl, "Name:", 0, 0);
+                laShowItem(gu, gc, &ui->PP, "name");
+            }
+            g = laMakeGroup(gu2, gc2, "Object", 0);{ gu = g->Page; gc = laFirstColumn(gu);
+                b1=laOnConditionThat(gu,gc,laPropExpression(&ui->PP,"active"));{
+                    laShowLabel(gu, gc, "Name:", 0, 0);
+                    laShowItem(gu, gc, &ui->PP, "active.name");
+                    b=laOnConditionThat(gu,gc,laPropExpression(&ui->ExtraPP, "delta_mode"));{
+                        laShowLabel(gu, gc, "DLoc:", 0, 0);laShowItem(gu, gc, &ui->PP, "active.dlocation")->Flags|=LA_UI_FLAGS_TRANSPOSE;
+                        laShowSeparator(gu,gc);
+                        laShowLabel(gu, gc, "DRot:", 0, 0);laShowItem(gu, gc, &ui->PP, "active.drotation")->Flags|=LA_UI_FLAGS_TRANSPOSE;
+                        laShowItem(gu, gc, &ui->PP, "active.dscale");
+                    }laElse(gu,b);{
+                        laShowLabel(gu, gc, "Loc:", 0, 0);laShowItem(gu, gc, &ui->PP, "active.location")->Flags|=LA_UI_FLAGS_TRANSPOSE;
+                        laShowSeparator(gu,gc);
+                        laShowLabel(gu, gc, "Rot:", 0, 0);laShowItem(gu, gc, &ui->PP, "active.rotation")->Flags|=LA_UI_FLAGS_TRANSPOSE;
+                        laShowItem(gu, gc, &ui->PP, "active.scale");
+                    }laEndCondition(gu,b);
+                }laElse(gu,b1);{
+                    laShowLabel(gu, gc, "No active object.", 0, 0);
+                }laEndCondition(gu,b1);
+            }
+        }
+    }laEndCondition(uil,b);
 }
 void la_3DViewEnsureCamera(laCanvasExtra* e){
     if(e->ViewingCamera) return;
@@ -586,8 +595,6 @@ void la_3DViewInit(laUiItem *ui){
 
     la_3DViewEnsureCamera(e);
 
-    e->GridSize = 10;
-    e->GridSpan = 15;
     e->ShowAxis[0] = 1;
     e->ShowAxis[1] = 1;
     e->ShowFloorGrid = 1;
@@ -764,6 +771,20 @@ int OPMOD_Canvas(laOperator *a, laEvent *e){
                 }
             }
             lstClearPointer(&Locals);
+
+            if(e->Type&LA_KEY_MOUSE_SCROLL){
+                laUiItem *pui = 0; laListHandle levels={0}; int dir=(e->Type&LA_STATE_DOWN)?1:-1;
+                laUiList *duil = la_DetectUiListRecursiveDeep(subu, e->x, e->y, 10000, &pui, 0, 0, 0, 0, &levels);
+                laUiListRecord* lip=levels.pLast; laUiList* uuil=lip->uil; laUiItem* upui=lip->Item.pPrev?((laUiListRecord*)lip->Item.pPrev)->pui:0; int ran=0;
+                while (lip && upui){
+                    if((ran=laPanUiListAuto(uuil, 0, dir*MAIN.ScrollingSpeed*LA_RH,
+                        uuil->L, upui->R-(uuil->ScrollerShownV?(LA_SCROLL_W+bt->RM):0),
+                        uuil->U, upui->B-(*upui->Type->Theme)->BM-(uuil->ScrollerShownH?(LA_SCROLL_W+bt->BM):0)))) break;
+                    lip=lip->Item.pPrev; uuil=lip->uil;  upui=lip->Item.pPrev?((laUiListRecord*)lip->Item.pPrev)->pui:0; 
+                }
+                if(ran)laRedrawCurrentPanel();
+                if(ran){return LA_RUNNING;}
+            }
         }
     }
 
@@ -1039,8 +1060,6 @@ void la_RegisterUiTypesViewerWidgets(){
     ct=laRegisterCanvasTemplate("la_3DView", "tns_object", 0, la_RootObjectDraw, la_RootObjectDrawOverlay, la_3DViewInit, la_3DViewDestroy);
     pc = laCanvasHasExtraProps(ct, sizeof(laCanvasExtra), 2);{
         _LA_PROP_3D_EXTRA = pc;
-        laAddIntProperty(pc, "grid_size", "Grid Size", "Floor Grid Size Per Cell", 0, 0, "Unit", 100, 1, 1, 10, 0, offsetof(laCanvasExtra, GridSize), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
-        laAddIntProperty(pc, "grid_span", "Grid Span", "How Many Grids Are Drawn", 0, 0, 0, 25, 1, 1, 10, 0, offsetof(laCanvasExtra, GridSpan), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
         p = laAddEnumProperty(pc, "show_axis", "Show Axis", "Show Global X,Y,Z Axis", LA_WIDGET_ENUM_CYCLE, "X,Y,Z", 0, 0, 0, offsetof(laCanvasExtra, ShowAxis), 0, 0, 3, 0, 0, 0, 0, 0, 0, 0);{
             laAddEnumItem(p, "HIDDEN", "Hidden", "Current Axis Is Hidden", U'🌔');
             laAddEnumItem(p, "SHOWN", "Shown", "Current Axis Is Shown", U'🌑');
@@ -1061,6 +1080,10 @@ void la_RegisterUiTypesViewerWidgets(){
             laAddEnumItemAs(p, "NONE", "None", "Regular mode",0,0);
             laAddEnumItemAs(p, "DELTA", "Delta", "Delta mode",1,0);
         }
+        p = laAddEnumProperty(pc, "show_details", "Show Details", "Show detailed information", LA_WIDGET_ENUM_HIGHLIGHT, 0, 0, 0, 0, offsetof(laCanvasExtra, ShowDetails), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);{
+            laAddEnumItem(p, "HIDDEN", "Hidden", "Current Axis Is Hidden", U'🛈');
+            laAddEnumItem(p, "SHOWN", "Shown", "Current Axis Is Shown", U'i');
+        }
         laAddIntProperty(pc, "height_coeff", "Ui Height", "Ui Height Coefficiency Entry", 0, 0, "Rows", 100, -100, 1, 0, 0, offsetof(laCanvasExtra, HeightCoeff), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
         laAddOperatorProperty(pc, "zoom", "Zoom", "Zoom Viewing Camera", "LA_3d_view_camera_zoom", U'🔎', 0);
         laAddOperatorProperty(pc, "rotate", "Rotate", "Rotate Viewing Camera", "LA_3d_view_camera_rotate", U'🗘', 0);