*/}}
Explorar o código

brush node iteration control

YimingWu hai 1 ano
pai
achega
ed069b33fd
Modificáronse 3 ficheiros con 99 adicións e 41 borrados
  1. 51 14
      ournodes.c
  2. 36 25
      ouroperations.c
  3. 12 2
      ourpaint.h

+ 51 - 14
ournodes.c

@@ -44,6 +44,9 @@ void IDN_BrushSettingsInit(OurBrushSettingsNode* n, int NoCreate){
         n->Color=laCreateOutSocket(n,"COLOR",LA_PROP_FLOAT|LA_PROP_ARRAY);
         strSafeSet(&n->Base.Name, "Brush Settings");
     }
+    if(!n->Iteration) n->Iteration=laCreateOutSocket(n,"ITER",LA_PROP_INT);
+    if(!n->Custom1) n->Custom1=laCreateOutSocket(n,"C1",LA_PROP_FLOAT);
+    if(!n->Custom2) n->Custom2=laCreateOutSocket(n,"C2",LA_PROP_FLOAT);
     n->CanvasScale->Data=&n->rCanvasScale;
     n->Size->Data=&n->rSize;
     n->Transparency->Data=&n->rTransparency;
@@ -54,11 +57,15 @@ void IDN_BrushSettingsInit(OurBrushSettingsNode* n, int NoCreate){
     n->Slender->Data=&n->rSlender;
     n->Angle->Data=&n->rAngle;
     n->Color->Data=Our->CurrentColor; n->Color->ArrLen=3;
+    n->Iteration->Data=&n->rIteration;
+    n->Custom1->Data=&n->rCustom1;
+    n->Custom2->Data=&n->rCustom2;
 }
 void IDN_BrushSettingsDestroy(OurBrushSettingsNode* n){
     laDestroyOutSocket(n->Size); laDestroyOutSocket(n->Transparency); laDestroyOutSocket(n->Hardness); laDestroyOutSocket(n->Smudge);
     laDestroyOutSocket(n->SmudgeLength); laDestroyOutSocket(n->DabsPerSize); laDestroyOutSocket(n->Slender); laDestroyOutSocket(n->Angle);
-    laDestroyOutSocket(n->CanvasScale); strSafeDestroy(&n->Base.Name);
+    laDestroyOutSocket(n->CanvasScale); laDestroyOutSocket(n->Iteration); laDestroyOutSocket(n->Custom1); laDestroyOutSocket(n->Custom2);
+    strSafeDestroy(&n->Base.Name);
 }
 int IDN_BrushSettingsVisit(OurBrushSettingsNode* n, laListHandle* l){
     LA_GUARD_THIS_NODE(n); n->Base.Eval=LA_DAG_FLAG_PERM; lstAppendPointer(l, n);
@@ -75,6 +82,9 @@ int IDN_BrushSettingsEval(OurBrushSettingsNode* n){
     n->rDabsPerSize = Our->CurrentBrush->DabsPerSize;
     n->rSlender = Our->CurrentBrush->Slender;
     n->rAngle = Our->CurrentBrush->Angle;
+    n->rIteration = Our->CurrentBrush->Iteration;
+    n->rCustom1 = Our->CurrentBrush->Custom1;
+    n->rCustom2 = Our->CurrentBrush->Custom2;
     return 1;
 }
 void ui_BrushSettingsNode(laUiList *uil, laPropPack *This, laPropPack *Extra, laColumn *UNUSED, int context){
@@ -98,27 +108,38 @@ void ui_BrushSettingsNode(laUiList *uil, laPropPack *This, laPropPack *Extra, la
     laEndRow(uil,b);
     b=laBeginRow(uil,c,0,0); u=laShowLabel(uil,c,"Canvas Scale",0,0);u->Flags|=LA_TEXT_ALIGN_RIGHT; u->Expand=1;  laShowNodeSocket(uil,c,This,"canvas_scale",0);
         u=laShowLabel(uil,c,"Dabs Per Size",0,0);u->Flags|=LA_TEXT_ALIGN_RIGHT; u->Expand=1; laShowNodeSocket(uil,c,This,"dabs_per_size",0); laEndRow(uil,b);
+    
+    b=laBeginRow(uil,c,0,0);
+        laShowSeparator(uil,c)->Expand=1; laShowNodeSocket(uil,c,This,"iteration",0)->Flags|=LA_UI_SOCKET_LABEL_W;
+    laEndRow(uil,b);
+    b=laBeginRow(uil,c,0,0); u=laShowItem(uil,c,0,"our.tools.current_brush.c1_name");u->Flags|=LA_UI_FLAGS_PLAIN|LA_TEXT_ALIGN_RIGHT; u->Expand=1;
+        laShowNodeSocket(uil,c,This,"c1",0); laEndRow(uil,b);
+        b=laBeginRow(uil,c,0,0); u=laShowItem(uil,c,0,"our.tools.current_brush.c2_name");u->Flags|=LA_UI_FLAGS_PLAIN|LA_TEXT_ALIGN_RIGHT; u->Expand=1;
+        laShowNodeSocket(uil,c,This,"c2",0); laEndRow(uil,b);
 }
 
 void IDN_BrushOutputsInit(OurBrushOutputsNode* n, int NoCreate){
-    if(NoCreate){ return; }
-    n->Offset=laCreateInSocket("OFFSET",LA_PROP_FLOAT);
-    n->Size=laCreateInSocket("SIZE",LA_PROP_FLOAT);
-    n->Transparency=laCreateInSocket("TRANSP",LA_PROP_FLOAT);
-    n->Hardness=laCreateInSocket("HRAD",LA_PROP_FLOAT);
-    n->Smudge=laCreateInSocket("SMUDGE",LA_PROP_FLOAT);
-    n->SmudgeLength=laCreateInSocket("LENGTH",LA_PROP_FLOAT);
-    n->DabsPerSize=laCreateInSocket("Dabs Per Size",LA_PROP_FLOAT);
-    n->Slender=laCreateInSocket("SLENDER",LA_PROP_FLOAT);
-    n->Angle=laCreateInSocket("ANGLE",LA_PROP_FLOAT);
-    n->Color=laCreateInSocket("COLOR",LA_PROP_FLOAT);
+    if(!NoCreate){
+        n->Offset=laCreateInSocket("OFFSET",LA_PROP_FLOAT);
+        n->Size=laCreateInSocket("SIZE",LA_PROP_FLOAT);
+        n->Transparency=laCreateInSocket("TRANSP",LA_PROP_FLOAT);
+        n->Hardness=laCreateInSocket("HRAD",LA_PROP_FLOAT);
+        n->Smudge=laCreateInSocket("SMUDGE",LA_PROP_FLOAT);
+        n->SmudgeLength=laCreateInSocket("LENGTH",LA_PROP_FLOAT);
+        n->DabsPerSize=laCreateInSocket("Dabs Per Size",LA_PROP_FLOAT);
+        n->Slender=laCreateInSocket("SLENDER",LA_PROP_FLOAT);
+        n->Angle=laCreateInSocket("ANGLE",LA_PROP_FLOAT);
+        n->Color=laCreateInSocket("COLOR",LA_PROP_FLOAT);
+    }
+    if(!n->Repeats) n->Repeats=laCreateInSocket("REPEATS",LA_PROP_INT);
+    if(!n->Discard) n->Discard=laCreateInSocket("DISCARD",LA_PROP_INT);
     strSafeSet(&n->Base.Name, "Brush Outputs");
 }
 void IDN_BrushOutputsDestroy(OurBrushOutputsNode* n){
     laDestroyInSocket(n->Offset);
     laDestroyInSocket(n->Size); laDestroyInSocket(n->Transparency); laDestroyInSocket(n->Hardness); laDestroyInSocket(n->Smudge);
     laDestroyInSocket(n->SmudgeLength); laDestroyInSocket(n->DabsPerSize); laDestroyInSocket(n->Slender); laDestroyInSocket(n->Angle);
-    laDestroyInSocket(n->Color);
+    laDestroyInSocket(n->Color); laDestroyInSocket(n->Repeats); laDestroyInSocket(n->Discard);
     strSafeDestroy(&n->Base.Name);
 }
 int IDN_BrushOutputsVisit(OurBrushOutputsNode* n, laListHandle* l){
@@ -135,6 +156,8 @@ int IDN_BrushOutputsVisit(OurBrushOutputsNode* n, laListHandle* l){
     BRUSH_OUT_VISIT(Slender)
     BRUSH_OUT_VISIT(Angle)
     BRUSH_OUT_VISIT(Color)
+    BRUSH_OUT_VISIT(Repeats)
+    BRUSH_OUT_VISIT(Discard)
 #undef BRUSH_OUT_VISIT
     n->Base.Eval=LA_DAG_FLAG_PERM; lstAppendPointer(l, n);
     return LA_DAG_FLAG_PERM;
@@ -142,7 +165,10 @@ int IDN_BrushOutputsVisit(OurBrushOutputsNode* n, laListHandle* l){
 int IDN_BrushOutputsEval(OurBrushOutputsNode* n){
     if(!Our->CurrentBrush) return 0;
 #define BRUSH_OUT_EVAL(a) \
-    if(LA_SRC_AND_PARENT(n->a) && (n->a->Source->DataType&LA_PROP_FLOAT)){ Our->CurrentBrush->Eval##a=*((real*)n->a->Source->Data); }
+    if(LA_SRC_AND_PARENT(n->a)){ \
+        if(n->a->Source->DataType&LA_PROP_INT){ Our->CurrentBrush->Eval##a=*((int*)n->a->Source->Data); } \
+        if(n->a->Source->DataType&LA_PROP_FLOAT){ Our->CurrentBrush->Eval##a=*((real*)n->a->Source->Data); } \
+    }
     if(LA_SRC_AND_PARENT(n->Offset) && (n->Offset->Source->DataType&LA_PROP_FLOAT|LA_PROP_ARRAY) && n->Offset->Source->ArrLen>=2){
         Our->CurrentBrush->EvalOffset[0]=((real*)n->Offset->Source->Data)[0];
         Our->CurrentBrush->EvalOffset[1]=((real*)n->Offset->Source->Data)[1];
@@ -160,6 +186,8 @@ int IDN_BrushOutputsEval(OurBrushOutputsNode* n){
     BRUSH_OUT_EVAL(DabsPerSize)
     BRUSH_OUT_EVAL(Slender)
     BRUSH_OUT_EVAL(Angle)
+    BRUSH_OUT_EVAL(Repeats)
+    BRUSH_OUT_EVAL(Discard)
 #undef BRUSH_OUT_EVAL
     return 1;
 }
@@ -182,6 +210,10 @@ void ui_BrushOutputsNode(laUiList *uil, laPropPack *This, laPropPack *Extra, laC
         laShowNodeSocket(uil,c,This,"smudge_length",0)->Flags|=LA_UI_SOCKET_LABEL_E;
     laEndRow(uil,b);
     b=laBeginRow(uil,c,0,0); laShowNodeSocket(uil,c,This,"dabs_per_size",0); laShowLabel(uil,c,"Dabs Per Size",0,0); laEndRow(uil,b);
+    b=laBeginRow(uil,c,0,0);
+        laShowNodeSocket(uil,c,This,"repeats",0)->Flags|=LA_UI_SOCKET_LABEL_E;
+        laShowNodeSocket(uil,c,This,"discard",0)->Flags|=LA_UI_SOCKET_LABEL_E;
+    laEndRow(uil,b);
 }
 
 void IDN_BrushDeviceInit(OurBrushDeviceNode* n, int NoCreate){
@@ -286,6 +318,9 @@ void ourRegisterNodes(){
     laAddSubGroup(pc,"slender", "Slender","Slender","la_out_socket",0,0,0,offsetof(OurBrushSettingsNode,Slender),0,0,0,0,0,0,0,LA_UDF_SINGLE);
     laAddSubGroup(pc,"angle", "Angle","Angle","la_out_socket",0,0,0,offsetof(OurBrushSettingsNode,Angle),0,0,0,0,0,0,0,LA_UDF_SINGLE);
     laAddSubGroup(pc,"color", "Color","Color","la_out_socket",0,0,0,offsetof(OurBrushSettingsNode,Color),0,0,0,0,0,0,0,LA_UDF_SINGLE);
+    laAddSubGroup(pc,"iteration", "Iteration","Iteration","la_out_socket",0,0,0,offsetof(OurBrushSettingsNode,Iteration),0,0,0,0,0,0,0,LA_UDF_SINGLE);
+    laAddSubGroup(pc,"c1", "C1","Custom 1","la_out_socket",0,0,0,offsetof(OurBrushSettingsNode,Custom1),0,0,0,0,0,0,0,LA_UDF_SINGLE);
+    laAddSubGroup(pc,"c2", "C2","Custom 2","la_out_socket",0,0,0,offsetof(OurBrushSettingsNode,Custom2),0,0,0,0,0,0,0,LA_UDF_SINGLE);
 
     pc=laAddPropertyContainer("our_node_brush_outputs", "Brush Outputs", "Brush outputs to draw actual dabs",0,ui_BrushOutputsNode,sizeof(OurBrushOutputsNode),lapost_Node,0,1);
     OUR_PC_IDN_BRUSH_OUTPUTS=pc; laPropContainerExtraFunctions(pc,0,0,0,0,laui_DefaultNodeOperationsPropUiDefine);
@@ -300,6 +335,8 @@ void ourRegisterNodes(){
     laAddSubGroup(pc,"slender", "Slender","Slender","la_in_socket",0,0,0,offsetof(OurBrushOutputsNode,Slender),0,0,0,0,0,0,0,LA_UDF_SINGLE);
     laAddSubGroup(pc,"angle", "Angle","Angle","la_in_socket",0,0,0,offsetof(OurBrushOutputsNode,Angle),0,0,0,0,0,0,0,LA_UDF_SINGLE);
     laAddSubGroup(pc,"color", "Color","Color","la_in_socket",0,0,0,offsetof(OurBrushOutputsNode,Color),0,0,0,0,0,0,0,LA_UDF_SINGLE);
+    laAddSubGroup(pc,"repeats", "Repeats","Repeats","la_in_socket",0,0,0,offsetof(OurBrushOutputsNode,Repeats),0,0,0,0,0,0,0,LA_UDF_SINGLE);
+    laAddSubGroup(pc,"discard", "Discard","Discard","la_in_socket",0,0,0,offsetof(OurBrushOutputsNode,Discard),0,0,0,0,0,0,0,LA_UDF_SINGLE);
 
     pc=laAddPropertyContainer("our_node_brush_device", "Brush Device", "Brush device input",0,ui_BrushDeviceNode,sizeof(OurBrushDeviceNode),lapost_Node,0,1);
     OUR_PC_IDN_BRUSH_DEVICE =pc; laPropContainerExtraFunctions(pc,0,0,0,0,laui_DefaultNodeOperationsPropUiDefine);

+ 36 - 25
ouroperations.c

@@ -183,6 +183,12 @@ void ourui_ToolsPanel(laUiList *uil, laPropPack *This, laPropPack *DetachedProps
             laShowItem(uil,c,0,"our.tools.current_brush.dabs_per_size");
             laShowItem(uil,c,0,"our.tools.current_brush.smudge_resample_length");
             laShowItem(uil,c,0,"our.tools.current_brush.smoothness");
+            b2=laOnConditionThat(uil,c,laPropExpression(0,"our.tools.current_brush.use_nodes"));
+                laShowItem(uil,cl,0,"our.tools.current_brush.c1");
+                laShowItem(uil,cr,0,"our.tools.current_brush.c1_name");
+                laShowItem(uil,cl,0,"our.tools.current_brush.c2");
+                laShowItem(uil,cr,0,"our.tools.current_brush.c2_name");
+            laEndCondition(uil,b2);
             laShowItem(uil,c,0,"our.tools.current_brush.default_as_eraser");
         }laEndCondition(uil,b);
 
@@ -554,7 +560,7 @@ OurBrush* our_NewBrush(char* name, real Size, real Hardness, real DabsPerSize, r
     return b;
 }
 void our_RemoveBrush(OurBrush* b){
-    strSafeDestroy(&b->Name);
+    strSafeDestroy(&b->Name); strSafeDestroy(&b->Custom1Name); strSafeDestroy(&b->Custom2Name);
     if(Our->CurrentBrush==b){ OurBrush* nb=b->Item.pPrev?b->Item.pPrev:b->Item.pNext; memAssignRef(Our, &Our->CurrentBrush, nb); }
     lstRemoveItem(&Our->Brushes, b);
     memLeave(b->Rack); b->Rack=0;
@@ -1096,9 +1102,8 @@ real our_PaintGetDabStepDistance(real Size,real DabsPerSize){
 int our_PaintGetDabs(OurBrush* b, OurLayer* l, real x, real y, real xto, real yto,
     real last_pressure, real last_angle_x, real last_angle_y, real pressure, real angle_x, real angle_y,
     int *tl, int *tr, int* tu, int* tb, real* r_xto, real* r_yto){
-    if (isnan(x)||isnan(y)||isnan(xto)||isnan(yto)||
-        isinf(x)||isinf(y)||isinf(xto)||isinf(yto)){
-        printf("what\n"); return 0;
+    if (isnan(x)||isnan(y)||isnan(xto)||isnan(yto)||isinf(x)||isinf(y)||isinf(xto)||isinf(yto)){
+        printf("brush input coordinates has nan or inf.\n"); return 0;
     }
     Our->NextDab=0;
     if(!b->EvalDabsPerSize) b->EvalDabsPerSize=b->DabsPerSize;
@@ -1115,28 +1120,30 @@ int our_PaintGetDabs(OurBrush* b, OurLayer* l, real x, real y, real xto, real yt
     if(b->LastAngle-this_angle>TNS_PI){ this_angle+=(TNS_PI*2); }
     elif(this_angle-b->LastAngle>TNS_PI){ b->LastAngle+=(TNS_PI*2); }
 
-    while(1){
-        arrEnsureLength(&Our->Dabs,Our->NextDab,&Our->MaxDab,sizeof(OurDab)); OurDab* od=&Our->Dabs[Our->NextDab];
-        real r=tnsGetRatiod(0,len,uselen-rem); od->X=tnsInterpolate(x,xto,r); od->Y=tnsInterpolate(y,yto,r); TNS_CLAMP(r,0,1);
-        b->LastX=od->X; b->LastY=od->Y; tnsVectorSet3v(b->EvalColor, Our->CurrentColor);
-        if(b->UseNodes){
-            b->EvalPressure=tnsInterpolate(last_pressure,pressure,r); b->EvalPosition[0]=od->X; b->EvalPosition[1]=od->Y;
-            b->EvalOffset[0]=0; b->EvalOffset[1]=0; b->EvalStrokeAngle=tnsInterpolate(b->LastAngle,this_angle,r);
-            b->EvalTilt[0]=tnsInterpolate(last_angle_x,angle_x,r); b->EvalTilt[1]=tnsInterpolate(last_angle_y,angle_y,r);
-            ourEvalBrush();
-            TNS_CLAMP(b->EvalSmudge,0,1); TNS_CLAMP(b->EvalSmudgeLength,0,100000); TNS_CLAMP(b->EvalTransparency,0,1); TNS_CLAMP(b->EvalHardness,0,1);  TNS_CLAMP(b->DabsPerSize,0,100000);
-            od->X+=b->EvalOffset[0]; od->Y+=b->EvalOffset[1];
+    while(1){ int Repeat=1; OurDab* od;
+        for(b->Iteration=0;b->Iteration<Repeat;b->Iteration++){ b->EvalDiscard=0;
+            arrEnsureLength(&Our->Dabs,Our->NextDab,&Our->MaxDab,sizeof(OurDab)); od=&Our->Dabs[Our->NextDab];
+            real r=tnsGetRatiod(0,len,uselen-rem); od->X=tnsInterpolate(x,xto,r); od->Y=tnsInterpolate(y,yto,r); TNS_CLAMP(r,0,1);
+            b->LastX=od->X; b->LastY=od->Y; tnsVectorSet3v(b->EvalColor, Our->CurrentColor);
+            if(b->UseNodes){
+                b->EvalPressure=tnsInterpolate(last_pressure,pressure,r); b->EvalPosition[0]=od->X; b->EvalPosition[1]=od->Y;
+                b->EvalOffset[0]=0; b->EvalOffset[1]=0; b->EvalStrokeAngle=tnsInterpolate(b->LastAngle,this_angle,r);
+                b->EvalTilt[0]=tnsInterpolate(last_angle_x,angle_x,r); b->EvalTilt[1]=tnsInterpolate(last_angle_y,angle_y,r);
+                ourEvalBrush();  if(!b->Iteration){ Repeat=b->EvalRepeats;} if(b->EvalDiscard){ continue; }
+                TNS_CLAMP(b->EvalSmudge,0,1); TNS_CLAMP(b->EvalSmudgeLength,0,100000); TNS_CLAMP(b->EvalTransparency,0,1); TNS_CLAMP(b->EvalHardness,0,1);  TNS_CLAMP(b->DabsPerSize,0,100000);
+                od->X+=b->EvalOffset[0]; od->Y+=b->EvalOffset[1];
+            }
+            if(!b->EvalDabsPerSize) b->EvalDabsPerSize=1;
+    #define pfac(psw) (((!b->UseNodes)&&psw)?tnsInterpolate(last_pressure,pressure,r):1)
+            od->Size = b->EvalSize*pfac(b->PressureSize);       od->Hardness = b->EvalHardness*pfac(b->PressureHardness);
+            od->Smudge = b->EvalSmudge*pfac(b->PressureSmudge); od->Color[3]=pow(b->EvalTransparency*pfac(b->PressureTransparency),2.718);
+            tnsVectorSet3v(od->Color,b->EvalColor);
+    #undef pfac;
+            od->Slender = b->EvalSlender; od->Angle=b->EvalAngle;
+            xmin=TNS_MIN2(xmin, od->X-od->Size); xmax=TNS_MAX2(xmax, od->X+od->Size); 
+            ymin=TNS_MIN2(ymin, od->Y-od->Size); ymax=TNS_MAX2(ymax, od->Y+od->Size);
+            if(od->Size>1e-1 && (!b->EvalDiscard)) Our->NextDab++;
         }
-        if(!b->EvalDabsPerSize) b->EvalDabsPerSize=1;
-#define pfac(psw) (((!b->UseNodes)&&psw)?tnsInterpolate(last_pressure,pressure,r):1)
-        od->Size = b->EvalSize*pfac(b->PressureSize);       od->Hardness = b->EvalHardness*pfac(b->PressureHardness);
-        od->Smudge = b->EvalSmudge*pfac(b->PressureSmudge); od->Color[3]=pow(b->EvalTransparency*pfac(b->PressureTransparency),2.718);
-        tnsVectorSet3v(od->Color,b->EvalColor);
-#undef pfac;
-        od->Slender = b->EvalSlender; od->Angle=b->EvalAngle;
-        xmin=TNS_MIN2(xmin, od->X-od->Size); xmax=TNS_MAX2(xmax, od->X+od->Size); 
-        ymin=TNS_MIN2(ymin, od->Y-od->Size); ymax=TNS_MAX2(ymax, od->Y+od->Size);
-        if(od->Size>1e-1) Our->NextDab++;
         step=our_PaintGetDabStepDistance(od->Size, b->EvalDabsPerSize);
         b->EvalStrokeLength+=step/b->Size; b->EvalStrokeLengthAccum+=step/b->Size; if(b->EvalStrokeLengthAccum>1e6){b->EvalStrokeLengthAccum-=1e6;}
         od->ResampleSmudge=0;
@@ -1917,6 +1924,10 @@ void ourRegisterEverything(){
     laAddFloatProperty(pc,"slender","Slender","Slenderness of the brush",0,0, 0,10,0,0.1,0,0,offsetof(OurBrush,Slender),0,0,0,0,0,0,0,0,0,0,0);
     laAddFloatProperty(pc,"angle","Angle","Angle of the brush",0,0, 0,TNS_PI,-TNS_PI,0.1,0,0,offsetof(OurBrush,Angle),0,0,0,0,0,0,0,0,0,0,LA_RAD_ANGLE);
     laAddFloatProperty(pc,"smoothness","Smoothness","Smoothness of the brush",0,0, 0,1,0,0.05,0,0,offsetof(OurBrush,Smoothness),0,0,0,0,0,0,0,0,0,0,0);
+    laAddFloatProperty(pc,"c1","C1","Custom brush input 1",0,0, 0,0,0,0.05,0,0,offsetof(OurBrush,Custom1),0,0,0,0,0,0,0,0,0,0,0);
+    laAddFloatProperty(pc,"c2","C2","Custom brush input 2",0,0, 0,0,0,0.05,0,0,offsetof(OurBrush,Custom2),0,0,0,0,0,0,0,0,0,0,0);
+    laAddStringProperty(pc,"c1_name","C1 Name","Custom input 1 name",0,0,0,0,1,offsetof(OurBrush,Custom1Name),0,0,0,0,0);
+    laAddStringProperty(pc,"c2_name","C2 Name","Custom input 2 name",0,0,0,0,1,offsetof(OurBrush,Custom2Name),0,0,0,0,0);
     p=laAddEnumProperty(pc,"pressure_size","Pressure Size","Use pen pressure to control size",LA_WIDGET_ENUM_HIGHLIGHT,0,0,0,0,offsetof(OurBrush,PressureSize),0,0,0,0,0,0,0,0,0,0);
     OUR_ADD_PRESSURE_SWITCH(p);
     p=laAddEnumProperty(pc,"pressure_transparency","Pressure Transparency","Use pen pressure to control transparency",LA_WIDGET_ENUM_HIGHLIGHT,0,0,0,0,offsetof(OurBrush,PressureTransparency),0,0,0,0,0,0,0,0,0,0);

+ 12 - 2
ourpaint.h

@@ -83,7 +83,7 @@ STRUCTURE(OurTexTile){
 
 STRUCTURE(OurLayer){
     laListItem Item;
-    laSafeString Name;
+    laSafeString* Name;
     int OffsetX,OffsetY;
     real Transparency;
     int Lock;
@@ -114,6 +114,9 @@ STRUCTURE(OurBrushSettingsNode){
     laNodeOutSocket* Slender;      real rSlender;
     laNodeOutSocket* Angle;        real rAngle;
     laNodeOutSocket* Color;
+    laNodeOutSocket* Iteration;    int  rIteration;
+    laNodeOutSocket* Custom1;      real rCustom1;
+    laNodeOutSocket* Custom2;      real rCustom2;
 };
 STRUCTURE(OurBrushOutputsNode){
     laBaseNode Base;
@@ -127,6 +130,8 @@ STRUCTURE(OurBrushOutputsNode){
     laNodeInSocket* Slender;
     laNodeInSocket* Angle;
     laNodeInSocket* Color;
+    laNodeInSocket* Repeats;
+    laNodeInSocket* Discard;
 };
 STRUCTURE(OurBrushDeviceNode){
     laBaseNode Base;
@@ -142,7 +147,7 @@ STRUCTURE(OurBrushDeviceNode){
 
 STRUCTURE(OurBrush){
     laListItem Item;
-    laSafeString Name;
+    laSafeString* Name;
     real Size;
     real DabsPerSize;
     real Hardness;
@@ -153,6 +158,8 @@ STRUCTURE(OurBrush){
     real Angle;
     real Smoothness;
     real MaxStrokeLength;
+    real Custom1,Custom2; laSafeString *Custom1Name,*Custom2Name;
+    int Iteration;
     int PressureSize,PressureHardness,PressureTransparency,PressureSmudge; // the simple way
 
     int Binding,DefaultAsEraser;
@@ -181,6 +188,9 @@ STRUCTURE(OurBrush){
     real EvalTilt[2];
     real EvalStrokeAngle;
     int  EvalIsEraser;
+
+    int EvalRepeats;
+    int EvalDiscard;
 };
 STRUCTURE(OurDab){
     float X,Y;