*/}}
Browse Source

Use display layer/list to draw the scene

YimingWu 1 year ago
parent
commit
16920f30f5
8 changed files with 200 additions and 159 deletions
  1. 4 0
      la_interface.h
  2. 40 22
      la_tns.h
  3. 106 103
      la_tns_kernel.c
  4. 35 27
      la_tns_mesh.c
  5. 3 2
      resources/la_modelling.c
  6. 1 1
      resources/la_nodes_basic.c
  7. 1 0
      resources/la_properties.c
  8. 10 4
      resources/la_widgets_viewers.c

+ 4 - 0
la_interface.h

@@ -840,6 +840,10 @@ STRUCTURE(laMultiStringExtra){
 
 NEED_STRUCTURE(laCanvasExtra);
 
+STRUCTURE(la3DObjectDrawExtra){
+    int MeshEditType;
+};
+
 typedef void(*laCanvasDrawFunc)(laBoxedTheme* bt, void* DataInstance, laCanvasExtra* Extra);
 typedef int (*laModalFunc)(laOperator *, laEvent *);
 

+ 40 - 22
la_tns.h

@@ -565,6 +565,33 @@ NEED_STRUCTURE(tnsRenderVert);
 
 NEED_STRUCTURE(tnsBatch)
 
+#define TNS_EVAL_LAYER_SOLID (1<<0)
+#define TNS_EVAL_LAYER_OVERLAY (1<<1)
+#define TNS_EVAL_LAYER_OUTLINE (1<<2)
+#define TNS_EVAL_LAYER_SELECTION (1<<3)
+
+NEED_STRUCTURE(tnsEvaluatedInstance);
+typedef void (*tnsDrawEvaluatedInstanceF)(tnsEvaluatedInstance* ei, void* CustomData);
+STRUCTURE(tnsEvaluatedInstance){
+    tnsObject *Object;
+    tnsMatrix44d Mat;
+    int IsActive;
+    int MeshSelectionType;
+    int InstanceSelectionID;
+    tnsDrawEvaluatedInstanceF Draw;
+};
+STRUCTURE(tnsEvaluateData){
+    int Done;
+    tnsObject *Active;
+    int FillOutline;
+    int FillSelectionID;
+    int OverrideID;
+    tnsEvaluatedInstance* Commands; int NextCommand, MaxCommand;
+    tnsEvaluatedInstance* Outlines; int NextOutline, MaxOutline;
+    tnsEvaluatedInstance* Overlays; int NextOverlay, MaxOverlay;
+    tnsEvaluatedInstance* Selections; int NextSelection, MaxSelection;
+};
+
 typedef struct _tnsObject tnsObject;
 struct _tnsObject
 {
@@ -611,6 +638,8 @@ struct _tnsObject
     laListHandle Drivers; // rack
 
     laListHandle Actions;
+
+    tnsEvaluateData Evaluated; // runtime
 };
 
 NEED_STRUCTURE(laNodeInSocket);
@@ -690,19 +719,6 @@ struct _tnsLight
     tnsMaterial *Material;
 };
 
-STRUCTURE(tnsGroup){
-    laListItem Item;
-
-    laListHandle ObjectLinks;
-
-    laSafeString *Name;
-
-    tnsVector4d Color1;
-    tnsVector4d Color2;
-
-    int ExcludeFromCalculation;
-};
-
 #define TNS_MESH_FLAG_SELECTED (1<<0)
 #define TNS_MESH_FLAG_PICKED   (1<<1)
 #define TNS_MESH_FLAG_LOOP_REVERSE (1<<2)
@@ -1248,9 +1264,7 @@ int tnsMMeshMergeVerts(tnsMeshObject* mo, tnsMVert* into, tnsMVert* mv);
 void tnsInvalidateMeshBatch(tnsMeshObject* mo);
 void tnsRegenerateMeshBatch(tnsMeshObject* mo);
 void tnsEnsureMeshBatch(tnsMeshObject* mo);
-void tnsDrawMeshObject(tnsMeshObject* mo, int DrawAsObjectSelection, int MeshSelectionMode, tnsMeshObject* Active,
-    int ViewMode, int SelectThrough, laListHandle* XRayCommands);
-void tnsDrawMeshObjectXRay(tnsMeshObject* mo, int MeshSelectionMode, int ViewMode, int SelectThrough);
+void tnsEvaluateMeshObject(tnsMeshObject* mo, tnsEvaluateData* ed);
 
 void la_RegisterModellingOperators();
 
@@ -1259,15 +1273,19 @@ void tnsGetCameraViewProjection(tnsMatrix44d* mat, int w, int h, tnsCamera* Came
 void tnsApplyCameraView(int W, int H, tnsCamera *Camera);
 void tnsApplyShadowCameraView(tnsLight *Light);
 
-void tnsApplyObjectMatrix(tnsObject *Object);
+void tnsApplyModelMatrix(tnsMatrix44d m);
 
 void tnsLookAt(tnsObject *o, tnsVector3d Target, tnsVector3d Up);
 
-void tnsDrawThisObject(tnsObject *o, tnsObject *active, int DrawAsObjectSelection, int MeshSelectionMode,
-    int ViewMode, int SelectThrough, laListHandle* XRayCommands);
-void tnsDrawObjectTree(tnsObject *from, tnsObject *active, int DrawAsObjectSelection, int MeshSelectionMode,
-    int ViewMode, int SelectThrough, laListHandle* XRayCommands);
-void tnsDrawXRay(laListHandle* XRayPasses, int MeshSelectionMode, int ViewMode, int SelectThrough);
+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 tnsAddEvaluatedInstance(tnsEvaluateData* ed, tnsObject* ob, tnsDrawEvaluatedInstanceF Draw, int Layer, 
+    int IsActive, int MeshSelectionType, int InstanceSelectionID);
+void tnsDrawLayer(tnsEvaluateData* ed,int Layer,void* CustomData);
+void tnsDrawObjectTree(tnsObject* from, int Layers,void* CustomData);
 void tnsDrawObjectOrigins(tnsObject *from, tnsObject *active, int AllOrigins);
 void tnsDrawCursor(tnsObject* root);
 void tnsDrawScene(int W, int H, tnsObject *root);

+ 106 - 103
la_tns_kernel.c

@@ -100,7 +100,6 @@ void tnsMultiply44d(tnsMatrix44d result, tnsMatrix44d l, tnsMatrix44d r);
 
 void tnsInitFirstLevel(tnsMatrixStack *tms);
 tnsMatrixStackItem *tKnlGetCurrentMatStackItem();
-tnsShader *tKnlGetActiveShader();
 
 void tnsAttach2DOffscreenBuffer(tnsOffscreen *target, GLuint attatchment, tnsTexture *use);
 void tnsDetach2DOffscreenBuffer(tnsOffscreen *target, GLuint which_attach_point);
@@ -138,7 +137,7 @@ void tnsViewportWithScissor(int x, int y, int w, int h){
     glEnable(GL_SCISSOR_TEST);
     glViewport(x, y, w, h); glScissor(x, y, w, h);
     T->vsx=x;T->vsy=y;T->vsw=w;T->vsh=h;
-    if ((current_shader = tKnlGetActiveShader())){
+    if ((current_shader = T->CurrentShader)){
         tnsResetViewMatrix();
         tnsShaderApplyView(current_shader, tnsGetViewMatrix());
         tnsResetModelMatrix();
@@ -1157,7 +1156,7 @@ void tnsOrtho(real xMin, real xMax, real yMin, real yMax, real zMin, real zMax){
 
     tnsMakeOrthoMatrix44d(mat, xMin, xMax, yMin, yMax, zMin, zMax);
 
-    if (current_shader = tKnlGetActiveShader()){
+    if (current_shader = T->CurrentShader){
         tnsShaderApplyProjection(current_shader, mat);
     }
 }
@@ -1167,7 +1166,7 @@ void tnsPerspective(real fFov_rad, real fAspect, real zMin, real zMax){
 
     tnsMakePerspectiveMatrix44d(mat, fFov_rad, fAspect, zMin, zMax);
 
-    if (current_shader = tKnlGetActiveShader()){
+    if (current_shader = T->CurrentShader){
         tnsShaderApplyProjection(current_shader, mat);
     }
 }
@@ -1181,7 +1180,7 @@ void tnsTranslate3d(real x, real y, real z){
     tnsMultiply44d(result, mat, transmat);
     memcpy(mat, result, sizeof(tnsMatrix44d));
 
-    if (current_shader = tKnlGetActiveShader()){
+    if (current_shader = T->CurrentShader){
         tnsShaderApplyModel(current_shader, result);
     }
 }
@@ -1205,7 +1204,7 @@ void tnsRotate4d(real degrees, real x, real y, real z){
     tnsMultiply44d(result, mat, rotmat);
     memcpy(mat, result, sizeof(tnsMatrix44d));
 
-    if (current_shader = tKnlGetActiveShader()){
+    if (current_shader = T->CurrentShader){
         tnsShaderApplyModel(current_shader, result);
     }
 }
@@ -1230,7 +1229,7 @@ void tnsScale3d(real x, real y, real z){
     tnsMultiply44d(result, mat, scalemat);
     memcpy(mat, result, sizeof(tnsMatrix44d));
 
-    if (current_shader = tKnlGetActiveShader()){
+    if (current_shader = T->CurrentShader){
         tnsShaderApplyModel(current_shader, result);
     }
 }
@@ -1405,9 +1404,6 @@ void tnsRestoreFromNanoVG(){
 tnsMatrixStackItem *tKnlGetCurrentMatStackItem(){
     return &T->stack.level[T->stack.current_level];
 }
-tnsShader *tKnlGetActiveShader(){
-    return T->CurrentShader;
-}
 real *tnsGetModelMatrix(){
     return tKnlGetCurrentMatStackItem()->model;
 }
@@ -1451,7 +1447,7 @@ tnsShader *tKnlFindShader1i(int CustomIndex){
 }
 void tKnlPushMatrix(){
     tnsMatrixStack *tms = &T->stack;
-    tnsShader *current_shader = tKnlGetActiveShader();
+    tnsShader *current_shader = T->CurrentShader;
 
     if (tms->current_level == tms->max_level || !current_shader) return;
 
@@ -1465,7 +1461,7 @@ void tKnlPushMatrix(){
 };
 void tKnlPopMatrix(){
     tnsMatrixStack *tms = &T->stack;
-    tnsShader *current_shader = tKnlGetActiveShader();
+    tnsShader *current_shader = T->CurrentShader;
 
     if (tms->current_level == 0 || !current_shader) return;
 
@@ -2557,39 +2553,6 @@ void tnsDrawToOffscreen(tnsOffscreen *toff, int HowMany, GLuint *AttachmentArray
     T->IsOffscreen = 1;
     T->BindedShader = 0;
 }
-//void tnsDraw_toextraColorAttachment(tnsOffscreen *toff){
-//    if (!toff) return;
-//    if (!toff->pColor[1]){
-//        tnsCreate2DOffscreenMSAttachmentExtraColor(toff);
-//    }
-//    glBindFramebuffer(GL_DRAW_FRAMEBUFFER, toff->FboHandle);
-//    glDrawBuffers(1, TNS_ATTACHMENT_ARRAY_1);
-//    T->IsOffscreen = 1;
-//    T->BindedShader = 0;
-//}
-//void tnsDraw_toextraNormalAttachment(tnsOffscreen *toff){
-//    if (!toff) return;
-//    if (!toff->pColor[2]){
-//        tnsCreate2DOffscreenMSAttachmentExtraNormal(toff);
-//    }
-//    glBindFramebuffer(GL_DRAW_FRAMEBUFFER, toff->FboHandle);
-//    glDrawBuffers(1, TNS_ATTACHMENT_ARRAY_2);
-//    T->IsOffscreen = 1;
-//    T->BindedShader = 0;
-//}
-//void tnsDrawToAllExtraAttachments(tnsOffscreen *toff){
-//    if (!toff) return;
-//    if (!toff->pColor[1]){
-//        tnsCreate2DOffscreenMSAttachmentExtraColor(toff);
-//    }
-//    if (!toff->pColor[2]){
-//        tnsCreate2DOffscreenMSAttachmentExtraNormal(toff);
-//    }
-//    glBindFramebuffer(GL_DRAW_FRAMEBUFFER, toff->FboHandle);
-//    glDrawBuffers(2, TNS_ATTACHMENT_ARRAY_1_2);
-//    T->IsOffscreen = 1;
-//    T->BindedShader = 0;
-//}
 void tnsDrawToOffscreenOnlyBind(tnsOffscreen *toff, int HowMany, GLuint *AttachmentArray){
     if (!toff) return;
     glBindFramebuffer(GL_DRAW_FRAMEBUFFER, toff->FboHandle);
@@ -3261,7 +3224,7 @@ void tnsSelfMatrixChanged(tnsObject* o, int ApplyToChild){
     }
     tnsExtractDeltaTransformValue(o);
     tnsExtractSelfTransformValue(o);
-    tnsExtractGlobalTransformValue(o);
+    tnsExtractGlobalTransformValue(o); tnsInvalidateEvaluation(o);
     if(ApplyToChild) for (laListItemPointer* li=o->ChildObjects.pFirst;li;li=li->pNext){ tnsSelfMatrixChanged(li->p,1); }
 }
 void tnsGlobalMatrixChanged(tnsObject* o, int ApplyToChild){
@@ -3273,7 +3236,7 @@ void tnsGlobalMatrixChanged(tnsObject* o, int ApplyToChild){
     tnsInverse44d(invd, o->DeltaTransform);
     tnsMultiply44d(o->SelfTransform, self, invd); 
     tnsExtractSelfTransformValue(o);
-    tnsExtractGlobalTransformValue(o);
+    tnsExtractGlobalTransformValue(o); tnsInvalidateEvaluation(o);
     if(ApplyToChild) for (laListItemPointer* li=o->ChildObjects.pFirst;li;li=li->pNext){ tnsSelfMatrixChanged(li->p,1); }
 }
 void tnsGlobalMatrixChangedForDelta(tnsObject* o, int ApplyToChild){
@@ -3285,7 +3248,7 @@ void tnsGlobalMatrixChangedForDelta(tnsObject* o, int ApplyToChild){
     tnsMultiply44d(o->DeltaTransform, tmp, o->GlobalTransform); 
     tnsExtractDeltaTransformValue(o);
     //tnsExtractSelfTransformValue(o);
-    tnsExtractGlobalTransformValue(o);
+    tnsExtractGlobalTransformValue(o); tnsInvalidateEvaluation(o);
     if(ApplyToChild) for (laListItemPointer* li=o->ChildObjects.pFirst;li;li=li->pNext){ tnsSelfMatrixChanged(li->p,1); }
 }
 void tnsSelfTransformValueChanged(tnsObject* o){
@@ -3593,6 +3556,8 @@ void tnsDestroyRootObject(tnsObject *root){
     tnsObject *o, *NextO;
     w->ActiveRoot = root->Item.pPrev ? root->Item.pPrev : root->Item.pNext ? root->Item.pNext : 0;
 
+    tnsFreeEvaluatedArray(&root->Evaluated);
+
     lstRemoveItem(&w->RootObjects, root);
     while (lstPopPointerLeave(&root->ChildObjects));
     strSafeDestroy(&root->Name);
@@ -3601,6 +3566,8 @@ void tnsDestroyRootObject(tnsObject *root){
 void tnsDestroyObject(tnsObject *o){
     if(o->Type==TNS_OBJECT_ROOT){ tnsDestroyRootObject(o); return; }
 
+    tnsFreeEvaluatedArray(&o->Evaluated);
+
     tnsUnparentObject(o,1);
     while(o->ChildObjects.pFirst){ tnsUnparentObject(((laListItemPointer*)o->ChildObjects.pFirst)->p, 1); }
 
@@ -3668,16 +3635,19 @@ 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);
     }
+    tnsInvalidateEvaluation(root);
 }
 void tnsSelectAllObjects(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)tnsSelectAllObjects(o);
     }
+    tnsInvalidateEvaluation(root);
 }
 void tnsSelectObject(tnsObject* o, int Select, int Toggle){
     if(!o) return;
     if(Toggle) tnsSelectObject(o,(o->Flags&TNS_OBJECT_FLAGS_SELECTED?0:1),0);
     elif(Select) o->Flags|=TNS_OBJECT_FLAGS_SELECTED; else o->Flags&=(~TNS_OBJECT_FLAGS_SELECTED);
+    tnsInvalidateEvaluation(o);
 }
 
 void tnsGetCameraProjection(tnsMatrix44d* mat, int w, int h, tnsCamera* Camera){
@@ -3701,7 +3671,7 @@ void tnsApplyCameraView(int W, int H, tnsCamera *Camera){
 
     mat = tnsGetProjectionMatrix();
     tnsMakePerspectiveMatrix44d(mat, Camera->FOV, (real)W / (real)H, Camera->ZMin, Camera->ZMax);
-    if (current_shader = tKnlGetActiveShader()){
+    if (current_shader = T->CurrentShader){
         tnsShaderApplyProjection(current_shader, mat);
         tnsShaderApplyProjectionInverse(current_shader, mat);
     }
@@ -3712,7 +3682,7 @@ void tnsApplyCameraView(int W, int H, tnsCamera *Camera){
     tnsMultiply44d(result, mat, inv);
     memcpy(mat, result, sizeof(tnsMatrix44d));
 
-    if (current_shader = tKnlGetActiveShader()){
+    if (current_shader = T->CurrentShader){
         tnsShaderApplyView(current_shader, result);
         if(current_shader->uViewPos>-1) glUniform3f(current_shader->uViewPos,LA_COLOR3(Camera->Base.Location));
     }
@@ -3732,29 +3702,17 @@ void tnsApplyShadowCameraView(tnsLight *Light){
     tnsMultiply44d(result, mat, inv);
     memcpy(mat, result, sizeof(tnsMatrix44d));
 
-    if (current_shader = tKnlGetActiveShader()){
+    if (current_shader = T->CurrentShader){
         tnsShaderApplyShadowMatrix(current_shader,mat);
     }
 }
 
-void tnsApplyObjectMatrix(tnsObject *Object){
-    tnsShader *current_shader = 0;
-    real *mat;
-    tnsMatrix44d result;
-
-    if (!Object) return;
-
+void tnsApplyModelMatrix(tnsMatrix44d m){
+    tnsShader *current_shader = 0; real *mat;
+    if (!m) return;
     mat = tnsGetModelMatrix();
-
-    //tnsMultiply44d(result, mat, Object->SelfTransform);
-    memcpy(mat, Object->GlobalTransform, sizeof(tnsMatrix44d));
-
-    //Actually This Works Pretty Fast,but we are currently testing its functionality;
-    //memcpy(mat, Object->GlobalTransform, sizeof(tnsMatrix44d));
-
-    if (current_shader = tKnlGetActiveShader()){
-        tnsShaderApplyModel(current_shader, mat);
-    }
+    memcpy(mat, m, sizeof(tnsMatrix44d));
+    if (current_shader = T->CurrentShader){ tnsShaderApplyModel(current_shader, mat); }
 }
 
 void tnsLookAt(tnsObject *o, tnsVector3d Target, tnsVector3d Up){
@@ -3773,7 +3731,7 @@ void tnsLookAt(tnsObject *o, tnsVector3d Target, tnsVector3d Up){
 
     tnsSelfMatrixChanged(o,1);
 
-    if (current_shader = tKnlGetActiveShader()){
+    if (current_shader = T->CurrentShader){
         tnsShaderApplyModel(current_shader, d);
     }
 }
@@ -3807,13 +3765,13 @@ void tnsDrawCross(real x,real y,real z,real x1,real x2,real y1,real y2,real z1,r
     tnsVertex3d(x+0.0,y+ y1, z+0.0); tnsVertex3d(x+0.0,y+ y2, z+0.0);
     tnsVertex3d(x+0.0,y+ 0.0,z+ z1); tnsVertex3d(x+0.0,y+ 0.0,z+ z2);
 }
-void tnsDrawPlaceholder(tnsObject* o, tnsObject *active, int DrawAsSelection){
+void tnsDrawPlaceholder(tnsObject* o, tnsEvaluateData* ed){
     if(T->BindedShader==T->SelectionShader){
         int i=o->SelectID; real color[4]={0,0,0,1}; TNS_ID_TO_COLOR(color,i); tnsColor4dv(color);
     }else{
-        if(DrawAsSelection && (!(o->Flags&TNS_OBJECT_FLAGS_SELECTED))) return;
-        if(!DrawAsSelection && (o->Flags&TNS_OBJECT_FLAGS_SELECTED)) return;
-        if(o==active){ tnsColor4dv(laAccentColor(LA_BT_TEXT_ACTIVE)); }
+        if(ed->FillOutline && (!(o->Flags&TNS_OBJECT_FLAGS_SELECTED))) return;
+        if(!ed->FillOutline && (o->Flags&TNS_OBJECT_FLAGS_SELECTED)) return;
+        if(o==ed->Active){ tnsColor4dv(laAccentColor(LA_BT_TEXT_ACTIVE)); }
         elif(o->Flags&TNS_OBJECT_FLAGS_SELECTED){ tnsColor4dv(laAccentColor(LA_BT_NORMAL)); }
         else tnsColor4dv(laThemeColor(_LA_THEME_3D_VIEW,LA_BT_BORDER));
     }
@@ -3821,57 +3779,102 @@ void tnsDrawPlaceholder(tnsObject* o, tnsObject *active, int DrawAsSelection){
     tnsPackAs(GL_LINES);
     tnsFlush();
 }
-void tnsDrawThisObject(tnsObject *o,tnsObject *active, int DrawAsObjectSelection, int MeshSelectionMode,
-                        int ViewMode, int SelectThrough, laListHandle* XRayCommands){
+void tnsEvaluateThisObject(tnsObject *o, tnsEvaluateData* ed){
     if (!o->Show) return;
     switch (o->Type){
     case TNS_OBJECT_MESH:
-        tnsDrawMeshObject(o, DrawAsObjectSelection, MeshSelectionMode, active, ViewMode, SelectThrough, XRayCommands);
+        tnsEvaluateMeshObject(o, ed);
         break;
     case TNS_OBJECT_CAMERA:
         tnsDrawCamera(o);
         break;
     case TNS_OBJECT_EMPTY:
     default:
-        tnsDrawPlaceholder(o,active,DrawAsObjectSelection);
-        break;
-    }
-}
-void tnsDrawThisObjectXRay(tnsObject *o, int MeshSelectionMode, int ViewMode, int SelectThrough){
-    if (!o->Show) return;
-    switch (o->Type){
-    case TNS_OBJECT_MESH:
-        tnsDrawMeshObjectXRay(o, MeshSelectionMode, ViewMode, SelectThrough);
-        break;
-    case TNS_OBJECT_CAMERA:
-    case TNS_OBJECT_EMPTY:
-    default:
+        tnsDrawPlaceholder(o,ed);
         break;
     }
 }
 
-void tnsDrawObjectTree(tnsObject *from, tnsObject *active, int DrawAsObjectSelection, int MeshSelectionMode,
-                       int ViewMode, int SelectThrough, laListHandle* XRayCommands){
-    tnsObject *o; if(!from) return;
+void tnsAddEvaluatedInstance(tnsEvaluateData* ed, tnsObject* ob, tnsDrawEvaluatedInstanceF Draw, int Layer, 
+    int IsActive, int MeshSelectionType, int InstanceSelectionID){
+    tnsEvaluatedInstance* ei;
+    if(Layer==TNS_EVAL_LAYER_SOLID){
+        arrEnsureLength(&ed->Commands,ed->NextCommand,&ed->MaxCommand,sizeof(tnsEvaluatedInstance));
+        ei=&ed->Commands[ed->NextCommand]; ed->NextCommand++;
+    }elif(Layer==TNS_EVAL_LAYER_OUTLINE){
+        arrEnsureLength(&ed->Outlines,ed->NextOutline,&ed->MaxOutline,sizeof(tnsEvaluatedInstance));
+        ei=&ed->Outlines[ed->NextOutline]; ed->NextOutline++;
+    }elif(Layer==TNS_EVAL_LAYER_OVERLAY){
+        arrEnsureLength(&ed->Overlays,ed->NextOverlay,&ed->MaxOverlay,sizeof(tnsEvaluatedInstance));
+        ei=&ed->Overlays[ed->NextOverlay]; ed->NextOverlay++;
+    }elif(Layer==TNS_EVAL_LAYER_SELECTION){
+        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->Draw=Draw; ei->Object=ob;
+    tnsCopyMatrix44d(ob->GlobalTransform,ei->Mat);
+}
+void tnsFreeEvaluatedArray(tnsEvaluateData* ed){
+    ed->Done=0;
+    arrFree(&ed->Commands,&ed->MaxCommand);
+    arrFree(&ed->Outlines,&ed->MaxOutline);
+    arrFree(&ed->Overlays,&ed->MaxOverlay);
+    arrFree(&ed->Selections,&ed->MaxSelection);
+}
+void tnsInvalidateEvaluation(tnsObject* o){
+    if(o->InRoot) o->InRoot->Evaluated.Done=0; else o->Evaluated.Done=0;
+}
+void tnsSetObjectTreeEvaluationArgs(tnsObject* from, tnsObject* Active, int FillOutline, int FillSelectionID){
+    tnsEvaluateData* ed=&from->Evaluated; int set=0;
+#define SETARG(a)\
+    if(ed->a==0 && a!=0){ set=1; } ed->a=a;
+    SETARG(Active); SETARG(FillOutline); SETARG(FillSelectionID);
+    if(set) ed->Done=0;
+}
+void tnsEvaluateObjectTree(tnsObject* from){
+    if(!from) return;
+    tnsEvaluateData* ed=&from->Evaluated;
+    if(ed->Done) return;
+    else{ ed->NextCommand=ed->NextOverlay=ed->NextSelection=ed->NextOutline=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));
+    }
 
     for (laListItemPointer* lip=from->ChildObjects.pFirst;lip;lip=lip->pNext){
-        o=lip->p;
-        tnsPushMatrix(); tnsApplyObjectMatrix(o);
-        tnsDrawThisObject(o, active, DrawAsObjectSelection, MeshSelectionMode, ViewMode, SelectThrough, XRayCommands);
+        tnsObject *o=lip->p;
+        tnsEvaluateThisObject(o, ed);
         if (o->ChildObjects.pFirst){
-            tnsDrawObjectTree(o, active, DrawAsObjectSelection, MeshSelectionMode, ViewMode, SelectThrough, XRayCommands);
+            tnsEvaluateObjectTree(o);
         }
-        tnsPopMatrix();
     }
-}
-void tnsDrawXRay(laListHandle* XRayPasses, int MeshSelectionMode, int ViewMode, int SelectThrough){
-    if(!XRayPasses->pFirst){ return; } tnsObject* o;
-    glClear(GL_DEPTH_BUFFER_BIT); glEnable(GL_DEPTH_TEST); glDepthMask(GL_TRUE);
-    while(o=lstPopPointer(XRayPasses)){ tnsPushMatrix(); tnsApplyObjectMatrix(o);
-        tnsDrawThisObjectXRay(o,MeshSelectionMode, ViewMode, SelectThrough);
+
+    ed->Done=1;
+}
+void tnsDrawLayer(tnsEvaluateData* ed,int Layer,void* CustomData){
+    tnsEvaluatedInstance* ei; int next=0;
+    if(Layer==TNS_EVAL_LAYER_SOLID){ ei=ed->Commands; next=ed->NextCommand; }
+    elif(Layer==TNS_EVAL_LAYER_OUTLINE){ ei=ed->Outlines; next=ed->NextOutline; }
+    elif(Layer==TNS_EVAL_LAYER_OVERLAY){ ei=ed->Overlays; next=ed->NextOverlay; }
+    elif(Layer==TNS_EVAL_LAYER_SELECTION){ ei=ed->Selections; next=ed->NextSelection; }
+    else{ return; } if(!next){ return; }
+    for(int i=0;i<next;i++){
+        tnsPushMatrix(); tnsApplyModelMatrix(ei->Mat);
+        ei->Draw(ei,CustomData);
         tnsPopMatrix();
+        ei++;
     }
 }
+void tnsDrawObjectTree(tnsObject* from, int Layers,void* CustomData){
+    tnsEvaluateData* ed=&from->Evaluated; if(!ed->Done) return;
+    if(Layers&TNS_EVAL_LAYER_SOLID){ tnsDrawLayer(ed,TNS_EVAL_LAYER_SOLID,CustomData); }
+    if(Layers&TNS_EVAL_LAYER_OUTLINE){ tnsDrawLayer(ed,TNS_EVAL_LAYER_OUTLINE,CustomData);}
+    if(Layers&TNS_EVAL_LAYER_OVERLAY){ tnsDrawLayer(ed,TNS_EVAL_LAYER_OVERLAY,CustomData);}
+    if(Layers&TNS_EVAL_LAYER_SELECTION){ tnsDrawLayer(ed,TNS_EVAL_LAYER_SELECTION,CustomData); }
+}
+
 void tnsDrawObjectOrigins(tnsObject *from, tnsObject *active, int AllOrigins){
     tnsObject *o; if(!from) return;
     tnsVector4d pos;

+ 35 - 27
la_tns_mesh.c

@@ -282,10 +282,10 @@ void tnsEnsureMeshBatch(tnsMeshObject* mo){
     if(mo->Batch) return;
     tnsRegenerateMeshBatch(mo);
 }
-void tnsDrawMeshObjectEdit(tnsMeshObject* mo, int MeshSelectionMode){
+void tnsDrawMeshObjectEdit(tnsMeshObject* mo, int MeshSelectionType){
     tnsUniformUseOffset(T->immShader,1);
     glPointSize(6); glLineWidth(3);
-    if(MeshSelectionMode==LA_CANVAS_SELECT_MODE_VERTS){
+    if(MeshSelectionType==LA_CANVAS_SELECT_MODE_VERTS){
         tnsDrawBatch(mo->Batch,"verts",0,0); tnsDrawBatch(mo->Batch,"lines",0,0);
     }else{
         tnsDrawBatch(mo->Batch,"edges",0,0);
@@ -293,36 +293,42 @@ void tnsDrawMeshObjectEdit(tnsMeshObject* mo, int MeshSelectionMode){
     glPointSize(1); glLineWidth(1);
     tnsUniformUseOffset(T->immShader,0);
 }
-void tnsDrawMeshObject(tnsMeshObject* mo, int DrawAsObjectSelection, int MeshSelectionMode, tnsMeshObject* Active, int ViewMode, int SelectThrough, laListHandle* XRayPasses){
+
+void tnsDrawMeshObjectOverlay(tnsEvaluatedInstance* ei, la3DObjectDrawExtra* de){
+    tnsEnsureMeshBatch(ei->Object);
+    tnsDrawMeshObjectEdit(ei->Object, de?de->MeshEditType:LA_CANVAS_SELECT_MODE_VERTS);
+    if(((tnsMeshObject*)ei->Object)->ExtraBatch){ tnsDrawBatch(((tnsMeshObject*)ei->Object)->ExtraBatch,0,0,0); }
+}
+void tnsDrawMeshObjectSelectionID(tnsEvaluatedInstance* ei, void* unused){
+    tnsEnsureMeshBatch(ei->Object);
+    int i=ei->InstanceSelectionID; real color[4]={0,0,0,1}; TNS_ID_TO_COLOR(color,i);
+    tnsDrawBatch(((tnsMeshObject*)ei->Object)->Batch,"body",color,0);
+}
+void tnsDrawMeshObjectOutline(tnsEvaluatedInstance* ei, void* unused){
+    real* color=(ei->IsActive)?laAccentColor(LA_BT_TEXT):laAccentColor(LA_BT_NORMAL);
+    tnsDrawBatch(((tnsMeshObject*)ei->Object)->Batch, "body", color, 0);
+}
+void tnsDrawMeshObject(tnsEvaluatedInstance* ei, void* unused){
+    tnsEnsureMeshBatch(ei->Object);
+    tnsUseNormal(1); tnsDrawBatch(((tnsMeshObject*)ei->Object)->Batch,"body",0,0); tnsUseNormal(0);
+}
+void tnsEvaluateMeshObject(tnsMeshObject* mo, tnsEvaluateData* ed){
     tnsEnsureMeshBatch(mo);
-    if(DrawAsObjectSelection){
+    tnsAddEvaluatedInstance(ed,mo,tnsDrawMeshObject,TNS_EVAL_LAYER_SOLID,0,0,0);
+    if(ed->FillOutline){
         if((mo->Base.Flags&TNS_OBJECT_FLAGS_SELECTED) && (mo->Mode!=TNS_MESH_EDIT_MODE)){
-            real* color=(Active==mo)?laAccentColor(LA_BT_TEXT):laAccentColor(LA_BT_NORMAL);
-            tnsDrawBatch(mo->Batch, "body", color, 0);
-        }
-    }else{
-        if(T->BindedShader==T->SelectionShader){
-            int i=mo->Base.SelectID; real color[4]={0,0,0,1}; TNS_ID_TO_COLOR(color,i);
-            tnsDrawBatch(mo->Batch,"body",color,0);
-        }else{
-            tnsUseNormal(1); tnsDrawBatch(mo->Batch,"body",0,0); tnsUseNormal(0);
-            if(mo->Mode==TNS_MESH_EDIT_MODE){ int xray=0;
-                if(mo->ExtraBatch){xray=1;}
-                if(SelectThrough){
-                    if(XRayPasses){xray=1;}
-                }else{
-                    tnsDrawMeshObjectEdit(mo,MeshSelectionMode);
-                }
-                if(xray){ lstAppendPointer(XRayPasses,mo); }
-            }
+            tnsAddEvaluatedInstance(ed,mo,tnsDrawMeshObjectOutline,TNS_EVAL_LAYER_OUTLINE,ed->Active==mo,0,0);
         }
     }
+    if(ed->FillSelectionID){
+        int i=ed->OverrideID?ed->OverrideID:mo->Base.SelectID;
+        tnsAddEvaluatedInstance(ed,mo,tnsDrawMeshObjectSelectionID,TNS_EVAL_LAYER_SELECTION,0,1,i);
+    }
+    if(mo->Mode==TNS_MESH_EDIT_MODE){
+        tnsAddEvaluatedInstance(ed,mo,tnsDrawMeshObjectOverlay,TNS_EVAL_LAYER_OVERLAY,0,0,0);
+    }
+    
 }
-void tnsDrawMeshObjectXRay(tnsMeshObject* mo, int MeshSelectionMode, int ViewMode, int SelectThrough){
-    if(SelectThrough){ tnsDrawMeshObjectEdit(mo, MeshSelectionMode); }
-    if(mo->ExtraBatch){ tnsDrawBatch(mo->ExtraBatch,0,0,0); }
-}
-
 
 tnsMFace* tnsMMeshNewFace(tnsMeshObject* mo){ tnsMFace* mf=memAcquireSimple(sizeof(tnsMFace)); mf->i=mo->totmf; mo->totmf++; lstAppendItem(&mo->mf,mf); return mf; }
 tnsMEdge* tnsMMeshNewEdge(tnsMeshObject* mo){ tnsMEdge* me=memAcquireSimple(sizeof(tnsMEdge)); me->i=mo->totme; mo->totme++; lstAppendItem(&mo->me,me); return me; }
@@ -622,12 +628,14 @@ void tnsMeshEnterEditMode(tnsMeshObject* mo){
     tnsMMeshFromMesh(mo);
     mo->Mode = TNS_MESH_EDIT_MODE;
     tnsInvalidateMeshBatch(mo);
+    tnsInvalidateEvaluation(mo);
 }
 void tnsMeshLeaveEditMode(tnsMeshObject* mo){
     if(mo->Mode==TNS_MESH_OBJECT_MODE) return;
     tnsMeshFromMMesh(mo);
     mo->Mode = TNS_MESH_OBJECT_MODE;
     tnsInvalidateMeshBatch(mo);
+    tnsInvalidateEvaluation(mo);
 }
 
 void tnsMMeshClearFirstLastSelection(tnsMeshObject* mo){

+ 3 - 2
resources/la_modelling.c

@@ -118,7 +118,8 @@ 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);
-    tnsDrawObjectTree(root,0,0,0,0,0,0);
+    tnsInvalidateEvaluation(root); tnsSetObjectTreeEvaluationArgs(root,root->Active,1,1); tnsEvaluateObjectTree(root);
+    tnsDrawObjectTree(root,TNS_EVAL_LAYER_SELECTION,0);
     glDisable(GL_DEPTH_TEST);
 }
 void la_PopulateSelectVerts(MSelectData* sd, tnsMeshObject* mo){
@@ -150,7 +151,7 @@ void la_PopulateSelectDataPrimitives(MSelectData* sd, tnsMeshObject* mo, tnsCame
     tnsViewportWithScissor(0,0,w,h);tnsResetViewMatrix();tnsResetModelMatrix();tnsResetProjectionMatrix();
     tnsApplyCameraView(w,h,camera);
     glClearColor(0,0,0,0); glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
-    tnsPushMatrix(); tnsApplyObjectMatrix(mo);glEnable(GL_DEPTH_TEST);
+    tnsPushMatrix(); tnsApplyModelMatrix(mo->Base.GlobalTransform);glEnable(GL_DEPTH_TEST);
     if(!SelectThrough){
         glDepthMask(GL_TRUE); glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
         tnsUniformUseOffset(T->SelectionShader,0);

+ 1 - 1
resources/la_nodes_basic.c

@@ -830,7 +830,7 @@ int IDN_LoopVisit(laLoopNode* n, laNodeVisitInfo* vi){
     if(socket->Source->DataType&(LA_PROP_INT|LA_PROP_ENUM)) var=*((int*)socket->Source->Data);}
 int IDN_LoopEval(laLoopNode* n){
     laLoopIndexNode* lin=LA_SRC_AND_PARENT(n->InIndex)?n->InIndex->Source->Parent:0;
-    if(lin->Base.Type!=LA_IDN_LOOP_INDEX){lin=0;}
+    if(lin->Base.Type!=&LA_IDN_LOOP_INDEX){lin=0;}
     int Iterations=n->Iterations;
     if(LA_SRC_AND_PARENT(n->InIterations)){ LA_GET_SRC_AS_INT(Iterations, n->InIterations); }
     for(int i=0; i<Iterations; i++){

+ 1 - 0
resources/la_properties.c

@@ -773,6 +773,7 @@ void tnstouched_Object(tnsObject *o, int hint){
     if(o->Type==TNS_OBJECT_MESH && (hint&TNS_HINT_GEOMETRY)){
         tnsInvalidateMeshBatch(o);
     }
+    tnsInvalidateEvaluation(o);
     laNotifyUsers("tns.world");
 }
 

+ 10 - 4
resources/la_widgets_viewers.c

@@ -154,16 +154,19 @@ void la_RootObjectDraw(laBoxedTheme *bt, tnsObject *root, laUiItem* ui){
     laListHandle xrays={0};
 
     if(root){
+        tnsSetObjectTreeEvaluationArgs(root,root->Active,1,1);
+        tnsEvaluateObjectTree(root);
+
         glEnable(GL_DEPTH_TEST); glDisable(GL_BLEND);
 
         tnsUseShader(T->immShader); tnsEnableShaderv(T->immShader);
         tnsUnbindTexture(); tnsUniformUseTexture(T->immShader,0,0); tnsUseMultiplyColor(0);
-        tnsDrawObjectTree(root, 0, 0, e->SelectMode, 0, e->SelectThrough,&xrays);
+        tnsDrawObjectTree(root,TNS_EVAL_LAYER_SOLID,0);
         
         glLineWidth(3); 
         glEnable(GL_POLYGON_OFFSET_LINE); glPolygonOffset(-1,-1);
         glDepthMask(GL_FALSE); glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
-        tnsDrawObjectTree(root, root->Active, 1, 0, 0, 0, 0);
+        tnsDrawObjectTree(root,TNS_EVAL_LAYER_OUTLINE,0);
         glDepthMask(GL_TRUE); glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
         glLineWidth(1);
         glDisable(GL_POLYGON_OFFSET_LINE);
@@ -176,7 +179,10 @@ void la_RootObjectDraw(laBoxedTheme *bt, tnsObject *root, laUiItem* ui){
         tnsFlush();
     }
 
-    tnsDrawXRay(&xrays,e->SelectMode,0,e->SelectThrough);
+    la3DObjectDrawExtra de={0}; de.MeshEditType=e->SelectMode;
+
+    if(e->SelectThrough){ glClear(GL_DEPTH_BUFFER_BIT); }
+    tnsDrawObjectTree(root,TNS_EVAL_LAYER_OVERLAY,&de);
 
     if(root){
         glDisable(GL_DEPTH_TEST);
@@ -190,7 +196,7 @@ void la_RootObjectDraw(laBoxedTheme *bt, tnsObject *root, laUiItem* ui){
     //laInvoke(0,"M_select",e,&ui->ExtraPP,0,0);
 
     //glColorMask(GL_FALSE, GL_FALSE,GL_FALSE,GL_FALSE);
-    //tnsDrawObjectTree(e->CurrentScene, 0);
+    //tnsEvaluateObjectTree(e->CurrentScene, 0);
 
     tnsFlush();
     //glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);