*/}}

ournodes.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308
  1. #include "ourpaint.h"
  2. extern LA MAIN;
  3. extern tnsMain* T;
  4. extern OurPaint *Our;
  5. laBaseNodeType OUR_IDN_BRUSH_SETTINGS;
  6. laBaseNodeType OUR_IDN_BRUSH_OUTPUTS;
  7. laBaseNodeType OUR_IDN_BRUSH_DEVICE;
  8. laPropContainer* OUR_PC_IDN_BRUSH_SETTINGS;
  9. laPropContainer* OUR_PC_IDN_BRUSH_OUTPUTS;
  10. laPropContainer* OUR_PC_IDN_BRUSH_DEVICE;
  11. void IDN_BrushSettingsInit(OurBrushSettingsNode* n, int NoCreate){
  12. if(!NoCreate){
  13. n->CanvasScale=laCreateOutSocket(n,"Canvas Scale",LA_PROP_FLOAT);
  14. n->Size=laCreateOutSocket(n,"SIZE",LA_PROP_FLOAT);
  15. n->Transparency=laCreateOutSocket(n,"TRANSP",LA_PROP_FLOAT);
  16. n->Hardness=laCreateOutSocket(n,"HARD",LA_PROP_FLOAT);
  17. n->Smudge=laCreateOutSocket(n,"SMUDGE",LA_PROP_FLOAT);
  18. n->SmudgeLength=laCreateOutSocket(n,"LEN",LA_PROP_FLOAT);
  19. n->DabsPerSize=laCreateOutSocket(n,"Dabs Per Size",LA_PROP_FLOAT);
  20. n->Slender=laCreateOutSocket(n,"SLENDER",LA_PROP_FLOAT);
  21. n->Angle=laCreateOutSocket(n,"ANGLE",LA_PROP_FLOAT);
  22. n->Color=laCreateOutSocket(n,"COLOR",LA_PROP_FLOAT|LA_PROP_ARRAY);
  23. strSafeSet(&n->Base.Name, "Brush Settings");
  24. }
  25. n->CanvasScale->Data=&n->rCanvasScale;
  26. n->Size->Data=&n->rSize;
  27. n->Transparency->Data=&n->rTransparency;
  28. n->Hardness->Data=&n->rHardness;
  29. n->Smudge->Data=&n->rSmudge;
  30. n->SmudgeLength->Data=&n->rSmudgeLength;
  31. n->DabsPerSize->Data=&n->rDabsPerSize;
  32. n->Slender->Data=&n->rSlender;
  33. n->Angle->Data=&n->rAngle;
  34. n->Color->Data=Our->CurrentColor; n->Color->ArrLen=3;
  35. }
  36. void IDN_BrushSettingsDestroy(OurBrushSettingsNode* n){
  37. laDestroyOutSocket(n->Size); laDestroyOutSocket(n->Transparency); laDestroyOutSocket(n->Hardness); laDestroyOutSocket(n->Smudge);
  38. laDestroyOutSocket(n->SmudgeLength); laDestroyOutSocket(n->DabsPerSize); laDestroyOutSocket(n->Slender); laDestroyOutSocket(n->Angle);
  39. laDestroyOutSocket(n->CanvasScale); strSafeDestroy(&n->Base.Name);
  40. }
  41. int IDN_BrushSettingsVisit(OurBrushSettingsNode* n, laListHandle* l){
  42. LA_GUARD_THIS_NODE(n); n->Base.Eval=LA_DAG_FLAG_PERM; lstAppendPointer(l, n);
  43. return LA_DAG_FLAG_PERM;
  44. }
  45. int IDN_BrushSettingsEval(OurBrushSettingsNode* n){
  46. if(!Our->CurrentBrush){ return 0; } // unlikely;
  47. n->rCanvasScale = Our->CurrentScale;
  48. n->rSize = Our->CurrentBrush->Size;
  49. n->rTransparency = Our->CurrentBrush->Transparency;
  50. n->rHardness = Our->CurrentBrush->Hardness;
  51. n->rSmudge = Our->CurrentBrush->Smudge;
  52. n->rSmudgeLength = Our->CurrentBrush->SmudgeResampleLength;
  53. n->rDabsPerSize = Our->CurrentBrush->DabsPerSize;
  54. n->rSlender = Our->CurrentBrush->Slender;
  55. n->rAngle = Our->CurrentBrush->Angle;
  56. return 1;
  57. }
  58. void ui_BrushSettingsNode(laUiList *uil, laPropPack *This, laPropPack *Extra, laColumn *UNUSED, int context){
  59. laColumn* c=laFirstColumn(uil); OurBrushSettingsNode*n=This->EndInstance;
  60. laUiItem* b,*u;
  61. LA_BASE_NODE_HEADER(uil,c,This);
  62. b=laBeginRow(uil,c,0,0);
  63. laShowSeparator(uil,c)->Expand=1;
  64. laShowNodeSocket(uil,c,This,"size",0)->Flags|=LA_UI_SOCKET_LABEL_N;
  65. laShowNodeSocket(uil,c,This,"transparency",0)->Flags|=LA_UI_SOCKET_LABEL_N;
  66. laShowNodeSocket(uil,c,This,"hardness",0)->Flags|=LA_UI_SOCKET_LABEL_N;
  67. laShowNodeSocket(uil,c,This,"slender",0)->Flags|=LA_UI_SOCKET_LABEL_N;
  68. laShowNodeSocket(uil,c,This,"angle",0)->Flags|=LA_UI_SOCKET_LABEL_N;
  69. laShowNodeSocket(uil,c,This,"color",0)->Flags|=LA_UI_SOCKET_LABEL_N;
  70. laEndRow(uil,b);
  71. b=laBeginRow(uil,c,0,0);
  72. laShowSeparator(uil,c)->Expand=1;
  73. laShowNodeSocket(uil,c,This,"smudge_length",0)->Flags|=LA_UI_SOCKET_LABEL_W;
  74. laShowNodeSocket(uil,c,This,"smudge",0)->Flags|=LA_UI_SOCKET_LABEL_W;
  75. laEndRow(uil,b);
  76. 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);
  77. 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);
  78. }
  79. void IDN_BrushOutputsInit(OurBrushOutputsNode* n, int NoCreate){
  80. if(NoCreate){ return; }
  81. n->Offset=laCreateInSocket("OFFSET",LA_PROP_FLOAT);
  82. n->Size=laCreateInSocket("SIZE",LA_PROP_FLOAT);
  83. n->Transparency=laCreateInSocket("TRANSP",LA_PROP_FLOAT);
  84. n->Hardness=laCreateInSocket("HRAD",LA_PROP_FLOAT);
  85. n->Smudge=laCreateInSocket("SMUDGE",LA_PROP_FLOAT);
  86. n->SmudgeLength=laCreateInSocket("LENGTH",LA_PROP_FLOAT);
  87. n->DabsPerSize=laCreateInSocket("Dabs Per Size",LA_PROP_FLOAT);
  88. n->Slender=laCreateInSocket("SLENDER",LA_PROP_FLOAT);
  89. n->Angle=laCreateInSocket("ANGLE",LA_PROP_FLOAT);
  90. n->Color=laCreateInSocket("COLOR",LA_PROP_FLOAT);
  91. strSafeSet(&n->Base.Name, "Brush Outputs");
  92. }
  93. void IDN_BrushOutputsDestroy(OurBrushOutputsNode* n){
  94. laDestroyInSocket(n->Offset);
  95. laDestroyInSocket(n->Size); laDestroyInSocket(n->Transparency); laDestroyInSocket(n->Hardness); laDestroyInSocket(n->Smudge);
  96. laDestroyInSocket(n->SmudgeLength); laDestroyInSocket(n->DabsPerSize); laDestroyInSocket(n->Slender); laDestroyInSocket(n->Angle);
  97. laDestroyInSocket(n->Color);
  98. strSafeDestroy(&n->Base.Name);
  99. }
  100. int IDN_BrushOutputsVisit(OurBrushOutputsNode* n, laListHandle* l){
  101. LA_GUARD_THIS_NODE(n);
  102. #define BRUSH_OUT_VISIT(a)\
  103. if(LA_SRC_AND_PARENT(n->a)){ laBaseNode*bn=n->a->Source->Parent; LA_VISIT_NODE(bn); }
  104. BRUSH_OUT_VISIT(Offset)
  105. BRUSH_OUT_VISIT(Size)
  106. BRUSH_OUT_VISIT(Transparency)
  107. BRUSH_OUT_VISIT(Hardness)
  108. BRUSH_OUT_VISIT(Smudge)
  109. BRUSH_OUT_VISIT(SmudgeLength)
  110. BRUSH_OUT_VISIT(DabsPerSize)
  111. BRUSH_OUT_VISIT(Slender)
  112. BRUSH_OUT_VISIT(Angle)
  113. BRUSH_OUT_VISIT(Color)
  114. #undef BRUSH_OUT_VISIT
  115. n->Base.Eval=LA_DAG_FLAG_PERM; lstAppendPointer(l, n);
  116. return LA_DAG_FLAG_PERM;
  117. }
  118. int IDN_BrushOutputsEval(OurBrushOutputsNode* n){
  119. if(!Our->CurrentBrush) return 0;
  120. #define BRUSH_OUT_EVAL(a)\
  121. if(LA_SRC_AND_PARENT(n->a) && (n->a->Source->DataType&LA_PROP_FLOAT)){ Our->CurrentBrush->Eval##a=*((real*)n->a->Source->Data); }
  122. if(LA_SRC_AND_PARENT(n->Offset) && (n->Offset->Source->DataType&LA_PROP_FLOAT|LA_PROP_ARRAY) && n->Offset->Source->ArrLen>=2){
  123. Our->CurrentBrush->EvalOffset[0]=((real*)n->Offset->Source->Data)[0];
  124. Our->CurrentBrush->EvalOffset[1]=((real*)n->Offset->Source->Data)[1];
  125. }
  126. if(LA_SRC_AND_PARENT(n->Color) && (n->Color->Source->DataType&LA_PROP_FLOAT|LA_PROP_ARRAY) && n->Color->Source->ArrLen>=3){
  127. Our->CurrentBrush->EvalColor[0]=((real*)n->Color->Source->Data)[0];
  128. Our->CurrentBrush->EvalColor[1]=((real*)n->Color->Source->Data)[1];
  129. Our->CurrentBrush->EvalColor[2]=((real*)n->Color->Source->Data)[2];
  130. }
  131. BRUSH_OUT_EVAL(Size)
  132. BRUSH_OUT_EVAL(Transparency)
  133. BRUSH_OUT_EVAL(Hardness)
  134. BRUSH_OUT_EVAL(Smudge)
  135. BRUSH_OUT_EVAL(SmudgeLength)
  136. BRUSH_OUT_EVAL(DabsPerSize)
  137. BRUSH_OUT_EVAL(Slender)
  138. BRUSH_OUT_EVAL(Angle)
  139. #undef BRUSH_OUT_EVAL
  140. return 1;
  141. }
  142. void ui_BrushOutputsNode(laUiList *uil, laPropPack *This, laPropPack *Extra, laColumn *UNUSED, int context){
  143. laColumn* c=laFirstColumn(uil); OurBrushOutputsNode*n=This->EndInstance;
  144. laUiItem* b,*u;
  145. LA_BASE_NODE_HEADER(uil,c,This);
  146. b=laBeginRow(uil,c,0,0);
  147. laShowNodeSocket(uil,c,This,"offset",0)->Flags|=LA_UI_SOCKET_LABEL_N;
  148. laShowNodeSocket(uil,c,This,"size",0)->Flags|=LA_UI_SOCKET_LABEL_N;
  149. laShowNodeSocket(uil,c,This,"transparency",0)->Flags|=LA_UI_SOCKET_LABEL_N;
  150. laShowNodeSocket(uil,c,This,"hardness",0)->Flags|=LA_UI_SOCKET_LABEL_N;
  151. laShowNodeSocket(uil,c,This,"slender",0)->Flags|=LA_UI_SOCKET_LABEL_N;
  152. laShowNodeSocket(uil,c,This,"angle",0)->Flags|=LA_UI_SOCKET_LABEL_N;
  153. laShowNodeSocket(uil,c,This,"color",0)->Flags|=LA_UI_SOCKET_LABEL_N;
  154. laEndRow(uil,b);
  155. b=laBeginRow(uil,c,0,0);
  156. laShowNodeSocket(uil,c,This,"smudge",0)->Flags|=LA_UI_SOCKET_LABEL_E;
  157. laShowNodeSocket(uil,c,This,"smudge_length",0)->Flags|=LA_UI_SOCKET_LABEL_E;
  158. laEndRow(uil,b);
  159. 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);
  160. }
  161. void IDN_BrushDeviceInit(OurBrushDeviceNode* n, int NoCreate){
  162. if(!NoCreate){
  163. n->Pressure=laCreateOutSocket(n,"PRESSURE",LA_PROP_FLOAT);
  164. n->Tilt=laCreateOutSocket(n,"TILT",LA_PROP_FLOAT|LA_PROP_ARRAY);
  165. n->IsEraser=laCreateOutSocket(n,"ERASER",LA_PROP_INT);
  166. n->Position=laCreateOutSocket(n,"POS",LA_PROP_FLOAT|LA_PROP_ARRAY);
  167. n->Speed=laCreateOutSocket(n,"SPD",LA_PROP_FLOAT);
  168. n->Angle=laCreateOutSocket(n,"ANGLE",LA_PROP_FLOAT);
  169. n->Length=laCreateOutSocket(n,"LENGTH",LA_PROP_FLOAT);
  170. n->LengthAccum=laCreateOutSocket(n,"ACUM",LA_PROP_FLOAT);
  171. strSafeSet(&n->Base.Name, "Brush Device");
  172. }
  173. n->Pressure->Data=&n->rPressure;
  174. n->Tilt->Data=n->rTilt; n->Tilt->ArrLen=2;
  175. n->IsEraser->Data=&n->rIsEraser;
  176. n->Position->Data=n->rPosition; n->Position->ArrLen=2;
  177. n->Speed->Data=&n->rSpeed;
  178. n->Angle->Data=&n->rAngle;
  179. n->Length->Data=&n->rLength;
  180. n->LengthAccum->Data=&n->rLengthAccum;
  181. }
  182. void IDN_BrushDeviceDestroy(OurBrushDeviceNode* n){
  183. laDestroyOutSocket(n->Pressure); laDestroyOutSocket(n->Tilt); laDestroyOutSocket(n->Position); laDestroyOutSocket(n->IsEraser); laDestroyOutSocket(n->Speed);
  184. laDestroyOutSocket(n->Angle); laDestroyOutSocket(n->Length); laDestroyOutSocket(n->LengthAccum);
  185. strSafeDestroy(&n->Base.Name);
  186. }
  187. int IDN_BrushDeviceVisit(OurBrushDeviceNode* n, laListHandle* l){
  188. LA_GUARD_THIS_NODE(n); n->Base.Eval=LA_DAG_FLAG_PERM; lstAppendPointer(l, n);
  189. return LA_DAG_FLAG_PERM;
  190. }
  191. int IDN_BrushDeviceEval(OurBrushDeviceNode* n){
  192. if(!Our->CurrentBrush){ return 0; } // unlikely;
  193. tnsVectorSet2v(n->rPosition, Our->CurrentBrush->EvalPosition);
  194. tnsVectorSet2v(n->rTilt, Our->CurrentBrush->EvalTilt);
  195. n->rAngle=Our->CurrentBrush->EvalStrokeAngle;
  196. n->rIsEraser = Our->CurrentBrush->EvalIsEraser;
  197. n->rPressure = Our->CurrentBrush->EvalPressure;
  198. n->rSpeed = Our->CurrentBrush->EvalSpeed;
  199. n->rLength = Our->CurrentBrush->EvalStrokeLength;
  200. n->rLengthAccum = Our->CurrentBrush->EvalStrokeLengthAccum;
  201. return 1;
  202. }
  203. void ui_BrushDeviceNode(laUiList *uil, laPropPack *This, laPropPack *Extra, laColumn *UNUSED, int context){
  204. laColumn* c=laFirstColumn(uil); OurBrushDeviceNode*n=This->EndInstance;
  205. laUiItem* b,*u;
  206. LA_BASE_NODE_HEADER(uil,c,This);
  207. b=laBeginRow(uil,c,0,0);
  208. laShowSeparator(uil,c)->Expand=1;
  209. laShowNodeSocket(uil,c,This,"position",0)->Flags|=LA_UI_SOCKET_LABEL_N;
  210. laShowNodeSocket(uil,c,This,"speed",0)->Flags|=LA_UI_SOCKET_LABEL_N;
  211. laShowNodeSocket(uil,c,This,"angle",0)->Flags|=LA_UI_SOCKET_LABEL_N;
  212. laShowNodeSocket(uil,c,This,"pressure",0)->Flags|=LA_UI_SOCKET_LABEL_N;
  213. laShowNodeSocket(uil,c,This,"tilt",0)->Flags|=LA_UI_SOCKET_LABEL_N;
  214. laShowNodeSocket(uil,c,This,"is_eraser",0)->Flags|=LA_UI_SOCKET_LABEL_N;
  215. laEndRow(uil,b);
  216. b=laBeginRow(uil,c,0,0); laShowSeparator(uil,c)->Expand=1;
  217. laShowNodeSocket(uil,c,This,"length_accum",0)->Flags|=LA_UI_SOCKET_LABEL_W; laShowNodeSocket(uil,c,This,"length",0)->Flags|=LA_UI_SOCKET_LABEL_W; laEndRow(uil,b);
  218. }
  219. int ourEvalBrush(){
  220. for(laListItemPointer*lip=Our->BrushEval.pFirst;lip;lip=lip->pNext){
  221. laBaseNode* n=lip->p; if(!n->InitDone){ n->Type->Init(n,1); n->InitDone=1; } n->Type->Eval(n);
  222. }
  223. return 1;
  224. }
  225. int ourRebuildBrushEval(){
  226. while(lstPopPointer(&Our->BrushEval));
  227. if(!Our->CurrentBrush || !Our->CurrentBrush->Rack) return LA_DAG_FLAG_PERM;
  228. laListHandle pending={0}; laRackPage* rp=Our->CurrentBrush->Rack; if(!rp)return LA_DAG_FLAG_PERM;
  229. for(laNodeRack* ir=rp->Racks.pFirst;ir;ir=ir->Item.pNext){
  230. for(laBaseNode*bn=ir->Nodes.pFirst;bn;bn=bn->Item.pNext){ lstAppendPointer(&pending,bn); bn->Eval=0; }
  231. }
  232. laBaseNode*n;int result=LA_DAG_FLAG_PERM; laListItemPointer*NextLip;
  233. for(laListItemPointer*lip=pending.pFirst;lip;lip=NextLip){ n=lip->p; NextLip=lip->pNext;
  234. if(n->Eval&LA_DAG_FLAG_PERM) continue;
  235. result=n->Type->Visit(n,&Our->BrushEval); if(result==LA_DAG_FLAG_ERR){ while(lstPopPointer(&pending)); break; }
  236. }
  237. if(result==LA_DAG_FLAG_ERR){ while(lstPopPointer(&MAIN.InputMapping->Eval)); return LA_DAG_FLAG_ERR; }
  238. return LA_DAG_FLAG_PERM;
  239. }
  240. void ourRegisterNodes(){
  241. laPropContainer *pc; laProp *p;
  242. laOperatorType *at;
  243. laEnumProp *ep;
  244. pc=laAddPropertyContainer("our_node_brush_settings", "Brush Settings", "Brush settings node to read from",0,ui_BrushSettingsNode,sizeof(OurBrushSettingsNode),0,0,1);
  245. OUR_PC_IDN_BRUSH_SETTINGS=pc; laPropContainerExtraFunctions(pc,0,0,0,0,laui_DefaultNodeOperationsPropUiDefine);
  246. laAddSubGroup(pc,"base","Base","Base node","la_base_node",0,0,0,0,0,0,0,0,0,0,0,LA_UDF_LOCAL);
  247. laAddSubGroup(pc,"canvas_scale", "Canvas scale","Canvas scale","la_out_socket",0,0,0,offsetof(OurBrushSettingsNode,CanvasScale),0,0,0,0,0,0,0,LA_UDF_SINGLE);
  248. laAddSubGroup(pc,"size", "Size","Size","la_out_socket",0,0,0,offsetof(OurBrushSettingsNode,Size),0,0,0,0,0,0,0,LA_UDF_SINGLE);
  249. laAddSubGroup(pc,"transparency", "Transparency","Transparency","la_out_socket",0,0,0,offsetof(OurBrushSettingsNode,Transparency),0,0,0,0,0,0,0,LA_UDF_SINGLE);
  250. laAddSubGroup(pc,"hardness", "Hardness","Hardness","la_out_socket",0,0,0,offsetof(OurBrushSettingsNode,Hardness),0,0,0,0,0,0,0,LA_UDF_SINGLE);
  251. laAddSubGroup(pc,"smudge", "Smudge","Smudge","la_out_socket",0,0,0,offsetof(OurBrushSettingsNode,Smudge),0,0,0,0,0,0,0,LA_UDF_SINGLE);
  252. laAddSubGroup(pc,"smudge_length", "Smudge Length","Smudge length","la_out_socket",0,0,0,offsetof(OurBrushSettingsNode,SmudgeLength),0,0,0,0,0,0,0,LA_UDF_SINGLE);
  253. laAddSubGroup(pc,"dabs_per_size", "Dabs Per Size","Dabs per size","la_out_socket",0,0,0,offsetof(OurBrushSettingsNode,DabsPerSize),0,0,0,0,0,0,0,LA_UDF_SINGLE);
  254. laAddSubGroup(pc,"slender", "Slender","Slender","la_out_socket",0,0,0,offsetof(OurBrushSettingsNode,Slender),0,0,0,0,0,0,0,LA_UDF_SINGLE);
  255. laAddSubGroup(pc,"angle", "Angle","Angle","la_out_socket",0,0,0,offsetof(OurBrushSettingsNode,Angle),0,0,0,0,0,0,0,LA_UDF_SINGLE);
  256. laAddSubGroup(pc,"color", "Color","Color","la_out_socket",0,0,0,offsetof(OurBrushSettingsNode,Color),0,0,0,0,0,0,0,LA_UDF_SINGLE);
  257. pc=laAddPropertyContainer("our_node_brush_outputs", "Brush Outputs", "Brush outputs to draw actual dabs",0,ui_BrushOutputsNode,sizeof(OurBrushOutputsNode),0,0,1);
  258. OUR_PC_IDN_BRUSH_OUTPUTS=pc; laPropContainerExtraFunctions(pc,0,0,0,0,laui_DefaultNodeOperationsPropUiDefine);
  259. laAddSubGroup(pc,"base","Base","Base node","la_base_node",0,0,0,0,0,0,0,0,0,0,0,LA_UDF_LOCAL);
  260. laAddSubGroup(pc,"offset", "Offset","Offset","la_in_socket",0,0,0,offsetof(OurBrushOutputsNode,Offset),0,0,0,0,0,0,0,LA_UDF_SINGLE);
  261. laAddSubGroup(pc,"size", "Size","Size","la_in_socket",0,0,0,offsetof(OurBrushOutputsNode,Size),0,0,0,0,0,0,0,LA_UDF_SINGLE);
  262. laAddSubGroup(pc,"transparency", "Transparency","Transparency","la_in_socket",0,0,0,offsetof(OurBrushOutputsNode,Transparency),0,0,0,0,0,0,0,LA_UDF_SINGLE);
  263. laAddSubGroup(pc,"hardness", "Hardness","Hardness","la_in_socket",0,0,0,offsetof(OurBrushOutputsNode,Hardness),0,0,0,0,0,0,0,LA_UDF_SINGLE);
  264. laAddSubGroup(pc,"smudge", "Smudge","Smudge","la_in_socket",0,0,0,offsetof(OurBrushOutputsNode,Smudge),0,0,0,0,0,0,0,LA_UDF_SINGLE);
  265. laAddSubGroup(pc,"smudge_length", "Smudge Length","Smudge length","la_in_socket",0,0,0,offsetof(OurBrushOutputsNode,SmudgeLength),0,0,0,0,0,0,0,LA_UDF_SINGLE);
  266. laAddSubGroup(pc,"dabs_per_size", "Dabs Per Size","Dabs per size","la_in_socket",0,0,0,offsetof(OurBrushOutputsNode,DabsPerSize),0,0,0,0,0,0,0,LA_UDF_SINGLE);
  267. laAddSubGroup(pc,"slender", "Slender","Slender","la_in_socket",0,0,0,offsetof(OurBrushOutputsNode,Slender),0,0,0,0,0,0,0,LA_UDF_SINGLE);
  268. laAddSubGroup(pc,"angle", "Angle","Angle","la_in_socket",0,0,0,offsetof(OurBrushOutputsNode,Angle),0,0,0,0,0,0,0,LA_UDF_SINGLE);
  269. laAddSubGroup(pc,"color", "Color","Color","la_in_socket",0,0,0,offsetof(OurBrushOutputsNode,Color),0,0,0,0,0,0,0,LA_UDF_SINGLE);
  270. pc=laAddPropertyContainer("our_node_brush_device", "Brush Device", "Brush device input",0,ui_BrushDeviceNode,sizeof(OurBrushDeviceNode),0,0,1);
  271. OUR_PC_IDN_BRUSH_DEVICE =pc; laPropContainerExtraFunctions(pc,0,0,0,0,laui_DefaultNodeOperationsPropUiDefine);
  272. laAddSubGroup(pc,"base","Base","Base node","la_base_node",0,0,0,0,0,0,0,0,0,0,0,LA_UDF_LOCAL);
  273. laAddSubGroup(pc,"pressure","Pressure","Pressure of the input","la_out_socket",0,0,0,offsetof(OurBrushDeviceNode,Pressure),0,0,0,0,0,0,0,LA_UDF_SINGLE);
  274. laAddSubGroup(pc,"tilt", "Tilt","Pen tilt vector","la_out_socket",0,0,0,offsetof(OurBrushDeviceNode,Tilt),0,0,0,0,0,0,0,LA_UDF_SINGLE);
  275. laAddSubGroup(pc,"is_eraser", "Is Eraser","Input event is from an eraser","la_out_socket",0,0,0,offsetof(OurBrushDeviceNode,IsEraser),0,0,0,0,0,0,0,LA_UDF_SINGLE);
  276. laAddSubGroup(pc,"position", "Dab position","Interpolated dab position","la_out_socket",0,0,0,offsetof(OurBrushDeviceNode,Position),0,0,0,0,0,0,0,LA_UDF_SINGLE);
  277. laAddSubGroup(pc,"speed","Speed","Speed on the canvas","la_out_socket",0,0,0,offsetof(OurBrushDeviceNode,Speed),0,0,0,0,0,0,0,LA_UDF_SINGLE);
  278. laAddSubGroup(pc,"angle","Angle","Direction of the brush","la_out_socket",0,0,0,offsetof(OurBrushDeviceNode,Angle),0,0,0,0,0,0,0,LA_UDF_SINGLE);
  279. laAddSubGroup(pc,"length","Length","Length of this brush stroke","la_out_socket",0,0,0,offsetof(OurBrushDeviceNode,Length),0,0,0,0,0,0,0,LA_UDF_SINGLE);
  280. laAddSubGroup(pc,"length_accum","Accumulated Length","Accumulated stroke length","la_out_socket",0,0,0,offsetof(OurBrushDeviceNode,LengthAccum),0,0,0,0,0,0,0,LA_UDF_SINGLE);
  281. LA_IDN_REGISTER("Brush Settings",L'🖌',OUR_IDN_BRUSH_SETTINGS,OUR_PC_IDN_BRUSH_SETTINGS, IDN_BrushSettingsInit, IDN_BrushSettingsDestroy, IDN_BrushSettingsVisit, IDN_BrushSettingsEval, OurBrushSettingsNode);
  282. LA_IDN_REGISTER("Brush Outputs",L'🖌',OUR_IDN_BRUSH_OUTPUTS,OUR_PC_IDN_BRUSH_OUTPUTS, IDN_BrushOutputsInit, IDN_BrushOutputsDestroy, IDN_BrushOutputsVisit, IDN_BrushOutputsEval, OurBrushOutputsNode);
  283. LA_IDN_REGISTER("Brush Device",L'🖳',OUR_IDN_BRUSH_DEVICE,OUR_PC_IDN_BRUSH_DEVICE, IDN_BrushDeviceInit, IDN_BrushDeviceDestroy, IDN_BrushDeviceVisit, IDN_BrushDeviceEval, OurBrushDeviceNode);
  284. laNodeCategory* nc=laAddNodeCategory("Our Paint",0,LA_RACK_TYPE_DRIVER);
  285. laNodeCategoryAddNodeTypes(LA_NODE_CATEGORY_DRIVER, &OUR_IDN_BRUSH_OUTPUTS,0);
  286. laNodeCategoryAddNodeTypes(nc, &OUR_IDN_BRUSH_DEVICE, 0);
  287. laNodeCategoryAddNodeTypes(nc, &OUR_IDN_BRUSH_SETTINGS, 0);
  288. }