*/}}
Browse Source

Wacom twist support

YimingWu 3 months ago
parent
commit
e051467e58
3 changed files with 45 additions and 15 deletions
  1. 7 2
      ournodes.c
  2. 33 11
      ouroperations.c
  3. 5 2
      ourpaint.h

+ 7 - 2
ournodes.c

@@ -263,8 +263,10 @@ void IDN_BrushDeviceInit(OurBrushDeviceNode* n, int NoCreate){
         n->LengthAccum=laCreateOutSocket(n,"ACUM",LA_PROP_FLOAT);
         strSafeSet(&n->Base.Name, "Brush Device");
     }
+    if(!n->Twist){ n->Twist=laCreateOutSocket(n,"TWIST",LA_PROP_FLOAT); }
     n->Pressure->Data=&n->rPressure;
     n->Tilt->Data=n->rTilt; n->Tilt->ArrLen=2;
+    n->Twist->Data=&n->rTwist;
     n->IsEraser->Data=&n->rIsEraser;
     n->Position->Data=n->rPosition; n->Position->ArrLen=2;
     n->Speed->Data=&n->rSpeed;
@@ -274,7 +276,7 @@ void IDN_BrushDeviceInit(OurBrushDeviceNode* n, int NoCreate){
 }
 void IDN_BrushDeviceDestroy(OurBrushDeviceNode* n){
     laDestroyOutSocket(n->Pressure); laDestroyOutSocket(n->Tilt); laDestroyOutSocket(n->Position); laDestroyOutSocket(n->IsEraser); laDestroyOutSocket(n->Speed);
-    laDestroyOutSocket(n->Angle); laDestroyOutSocket(n->Length); laDestroyOutSocket(n->LengthAccum); 
+    laDestroyOutSocket(n->Angle); laDestroyOutSocket(n->Length); laDestroyOutSocket(n->LengthAccum); laDestroyOutSocket(n->Twist);
     strSafeDestroy(&n->Base.Name);
 }
 int IDN_BrushDeviceVisit(OurBrushDeviceNode* n, laNodeVisitInfo* vi){
@@ -288,6 +290,7 @@ int IDN_BrushDeviceEval(OurBrushDeviceNode* n){
     n->rAngle=Our->CurrentBrush->EvalStrokeAngle;
     n->rIsEraser = Our->CurrentBrush->EvalIsEraser;
     n->rPressure = Our->CurrentBrush->EvalPressure;
+    n->rTwist = Our->CurrentBrush->EvalTwist;
     n->rSpeed = Our->CurrentBrush->EvalSpeed;
     n->rLength = Our->CurrentBrush->EvalStrokeLength;
     n->rLengthAccum = Our->CurrentBrush->EvalStrokeLengthAccum;
@@ -295,7 +298,7 @@ int IDN_BrushDeviceEval(OurBrushDeviceNode* n){
 }
 void IDN_BrushDeviceCopy(OurBrushDeviceNode* new, OurBrushDeviceNode* old, int DoRematch){
     if(DoRematch){ return;}
-    LA_IDN_OLD_DUPL(Pressure) LA_IDN_OLD_DUPL(Tilt) LA_IDN_OLD_DUPL(Position)
+    LA_IDN_OLD_DUPL(Pressure) LA_IDN_OLD_DUPL(Tilt) LA_IDN_OLD_DUPL(Position) LA_IDN_OLD_DUPL(Twist)
     LA_IDN_OLD_DUPL(IsEraser) LA_IDN_OLD_DUPL(Speed) LA_IDN_OLD_DUPL(Angle)
     LA_IDN_OLD_DUPL(Length) LA_IDN_OLD_DUPL(LengthAccum)
 }
@@ -311,6 +314,7 @@ void ui_BrushDeviceNode(laUiList *uil, laPropPack *This, laPropPack *Extra, laCo
         laShowNodeSocket(uil,c,This,"angle",0)->Flags|=LA_UI_SOCKET_LABEL_N;
         laShowNodeSocket(uil,c,This,"pressure",0)->Flags|=LA_UI_SOCKET_LABEL_N;
         laShowNodeSocket(uil,c,This,"tilt",0)->Flags|=LA_UI_SOCKET_LABEL_N;
+        laShowNodeSocket(uil,c,This,"twist",0)->Flags|=LA_UI_SOCKET_LABEL_N;
         laShowNodeSocket(uil,c,This,"is_eraser",0)->Flags|=LA_UI_SOCKET_LABEL_N;
     laEndRow(uil,b);
     b=laBeginRow(uil,c,0,0); laShowSeparator(uil,c)->Expand=1;
@@ -372,6 +376,7 @@ void ourRegisterNodes(){
     laAddSubGroup(pc,"base","Base","Base node","la_base_node",0,0,0,0,0,0,0,0,0,0,0,LA_UDF_LOCAL);
     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);
     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);
+    laAddSubGroup(pc,"twist", "Twist","Pen twist angle","la_out_socket",0,0,0,offsetof(OurBrushDeviceNode,Twist),0,0,0,0,0,0,0,LA_UDF_SINGLE);
     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);
     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);
     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);

+ 33 - 11
ouroperations.c

@@ -196,6 +196,10 @@ void ourui_ToolsPanel(laUiList *uil, laPropPack *This, laPropPack *DetachedProps
     b2=laOnConditionThat(uil,c,laNot(laPropExpression(0,"our.tools.current_brush.use_nodes")));\
     laShowItemFull(uil,c,0,"our.tools.current_brush." a,0,"text=P",0,0);\
     laEndCondition(uil,b2);
+#define OUR_TWIST(a) \
+    b2=laOnConditionThat(uil,c,laNot(laPropExpression(0,"our.tools.current_brush.use_nodes")));\
+    laShowItemFull(uil,c,0,"our.tools.current_brush." a,0,"text=T",0,0);\
+    laEndCondition(uil,b2);
 
     laShowItem(uil,c,0,"our.tool")->Flags|=LA_UI_FLAGS_EXPAND;
     laUiItem* bt=laOnConditionThat(uil,c,laEqual(laPropExpression(0,"our.tool"),laIntExpression(OUR_TOOL_PAINT)));{
@@ -212,7 +216,7 @@ void ourui_ToolsPanel(laUiList *uil, laPropPack *This, laPropPack *DetachedProps
             OUR_BR laShowItem(uil,c,0,"our.tools.current_brush.transparency")->Expand=1; OUR_PRESSURE("pressure_transparency")  OUR_ER
             OUR_BR laShowItem(uil,c,0,"our.tools.current_brush.hardness")->Expand=1;  OUR_PRESSURE("pressure_hardness") OUR_ER
             laShowItem(uil,c,0,"our.tools.current_brush.slender");
-            laShowItem(uil,c,0,"our.tools.current_brush.angle");
+            OUR_BR laShowItem(uil,c,0,"our.tools.current_brush.angle")->Expand=1; OUR_TWIST("twist_angle") OUR_ER;
             laShowItem(uil,c,0,"our.tools.current_brush.dabs_per_size");
             OUR_BR laShowItem(uil,c,0,"our.tools.current_brush.smudge")->Expand=1;  OUR_PRESSURE("pressure_smudge")  OUR_ER
             laShowItem(uil,c,0,"our.tools.current_brush.smudge_resample_length");
@@ -544,12 +548,23 @@ void our_CanvasDrawReferenceBlock(OurCanvasDraw* ocd){
     tnsFlush();
 }
 void our_CanvasDrawBrushCircle(OurCanvasDraw* ocd){
-    if(!Our->CurrentBrush) return; real v[96];
+    if(!Our->CurrentBrush) return; real v[96]; real Radius=Our->CurrentBrush->Size/ocd->Base.ZoomX,gap=rad(2);
     tnsUseImmShader();tnsUseNoTexture();
-    tnsMakeCircle2d(v,48,ocd->Base.OnX,ocd->Base.OnY,Our->CurrentBrush->Size/ocd->Base.ZoomX+0.5,0);
+    tnsMakeCircle2d(v,48,ocd->Base.OnX,ocd->Base.OnY,Radius+0.5,0);
     tnsColor4d(1,1,1,0.3); tnsVertexArray2d(v,48); tnsPackAs(GL_LINE_LOOP);
-    tnsMakeCircle2d(v,48,ocd->Base.OnX,ocd->Base.OnY,Our->CurrentBrush->Size/ocd->Base.ZoomX-0.5,0);
+    tnsMakeCircle2d(v,48,ocd->Base.OnX,ocd->Base.OnY,Radius-0.5,0);
     tnsColor4d(0,0,0,0.3); tnsVertexArray2d(v,48); tnsPackAs(GL_LINE_LOOP);
+    if(Our->EventHasTwist){
+        tnsColor4d(0,0,0,0.3);
+        tnsVertex2d(ocd->Base.OnX+sin(Our->EventTwistAngle+gap)*Radius,ocd->Base.OnY+cos(Our->EventTwistAngle+gap)*Radius);
+        tnsVertex2d(ocd->Base.OnX-sin(Our->EventTwistAngle-gap)*Radius,ocd->Base.OnY-cos(Our->EventTwistAngle-gap)*Radius);
+        tnsVertex2d(ocd->Base.OnX+sin(Our->EventTwistAngle-gap)*Radius,ocd->Base.OnY+cos(Our->EventTwistAngle-gap)*Radius);
+        tnsVertex2d(ocd->Base.OnX-sin(Our->EventTwistAngle+gap)*Radius,ocd->Base.OnY-cos(Our->EventTwistAngle+gap)*Radius);
+        tnsColor4d(1,1,1,0.3);
+        tnsVertex2d(ocd->Base.OnX+sin(Our->EventTwistAngle)*Radius,ocd->Base.OnY+cos(Our->EventTwistAngle)*Radius);
+        tnsVertex2d(ocd->Base.OnX-sin(Our->EventTwistAngle)*Radius,ocd->Base.OnY-cos(Our->EventTwistAngle)*Radius);
+        tnsPackAs(GL_LINES);
+    }
     tnsFlush();
 }
 
@@ -651,7 +666,9 @@ void our_CanvasDrawOverlay(laUiItem* ui,int h){
 
 int ourextramod_Canvas(laOperator *a, laEvent *e){
     laUiItem *ui = a->Instance; OurCanvasDraw* ocd=ui->Extra;
-    if(Our->EnableBrushCircle && (e->Type&LA_MOUSE_EVENT)){ ocd->Base.OnX=e->x; ocd->Base.OnY=e->y; laRedrawCurrentPanel();  }
+    if(Our->EnableBrushCircle && ((e->Type&LA_MOUSE_EVENT)||(e->Type&LA_KEYBOARD_EVENT))){
+        ocd->Base.OnX=e->x; ocd->Base.OnY=e->y; laRedrawCurrentPanel(); Our->EventHasTwist=e->HasTwist; Our->EventTwistAngle=e->Twist;
+    }
     return LA_RUNNING_PASS;
 }
 
@@ -1273,7 +1290,7 @@ real our_PaintGetDabStepDistance(real Size,real DabsPerSize){
     real d=Size/DabsPerSize; if(d<1e-2) d=1e-2; return d;
 }
 int our_PaintGetDabs(OurBrush* b, OurLayer* l, real x, real y, real xto, real yto,
-    real last_pressure, real last_orientation, real last_deviation, real pressure, real Orientation, real Deviation,
+    real last_pressure, real last_orientation, real last_deviation, real last_twist, real pressure, real Orientation, real Deviation, real Twist,
     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("brush input coordinates has nan or inf.\n"); return 0;
@@ -1302,6 +1319,7 @@ int our_PaintGetDabs(OurBrush* b, OurLayer* l, real x, real y, real xto, real yt
                 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_orientation,Orientation,r); b->EvalTilt[1]=tnsInterpolate(last_deviation,Deviation,r);
+                b->EvalTwist=tnsInterpolate(last_twist,Twist,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];
@@ -1312,8 +1330,8 @@ int our_PaintGetDabs(OurBrush* b, OurLayer* l, real x, real y, real xto, real yt
             od->Smudge = b->EvalSmudge*pfac(b->PressureSmudge); od->Color[3]=pow(b->EvalTransparency*pfac(b->PressureTransparency),2.718);
             tnsVectorSet3v(od->Color,b->EvalColor);             od->Force=b->EvalForce*pfac(b->PressureForce);
     #undef pfac;
-            od->Gunkyness = b->EvalGunkyness;
-            od->Slender = b->EvalSlender; od->Angle=b->EvalAngle;
+            od->Gunkyness = b->EvalGunkyness; od->Slender = b->EvalSlender;
+            od->Angle=b->EvalAngle; if(b->TwistAngle){ od->Angle=tnsInterpolate(last_twist,Twist,r); }
             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++;
@@ -1775,17 +1793,18 @@ int ourmod_Paint(laOperator* a, laEvent* e){
             lstAppendItem(&Our->BadEvents,be); Our->BadEventCount++;
             if(Our->BadEventCount>=Our->BadEventsLimit){ Our->BadEventsGiveUp=1; }
         }else{
-            Our->PaintProcessedEvents=1; laEvent* UseEvent;real Pressure=e->Pressure,Orientation=-e->Orientation,Deviation=e->Deviation;
+            Our->PaintProcessedEvents=1; laEvent* UseEvent;real Pressure=e->Pressure,Orientation=-e->Orientation,Deviation=e->Deviation,Twist=e->Twist;
             while(1){
                 UseEvent=lstPopItem(&Our->BadEvents); if(!UseEvent){ UseEvent=e; }
                 real x,y; our_UiToCanvas(&ex->Base,UseEvent,&x,&y); our_SmoothGlobalInput(&x,&y,0);
                 int tl,tr,tu,tb; if(ex->LastPressure<0){ ex->LastPressure=Pressure; }
-                if(our_PaintGetDabs(ob,l,ex->CanvasLastX,ex->CanvasLastY,x,y,ex->LastPressure,ex->LastTilt[0],ex->LastTilt[1],Pressure,Orientation,Deviation,
+                if(our_PaintGetDabs(ob,l,ex->CanvasLastX,ex->CanvasLastY,x,y,ex->LastPressure,ex->LastTilt[0],ex->LastTilt[1],ex->LastTwist,
+                    Pressure,Orientation,Deviation,Twist,
                     &tl,&tr,&tu,&tb,&ex->CanvasLastX,&ex->CanvasLastY)){
                     our_PaintDoDabsWithSmudgeSegments(l,tl,tr,tu,tb);
                     laNotifyUsers("our.canvas"); laMarkMemChanged(Our->CanvasSaverDummyList.pFirst);
                 }
-                ex->LastPressure=Pressure;ex->LastTilt[0]=Orientation;ex->LastTilt[1]=Deviation;
+                ex->LastPressure=Pressure;ex->LastTilt[0]=Orientation;ex->LastTilt[1]=Deviation; ex->LastTwist=Twist;
                 if(UseEvent==e){ break; }
                 else{ memFree(UseEvent); }
             }
@@ -2264,6 +2283,9 @@ void ourRegisterEverything(){
     OUR_ADD_PRESSURE_SWITCH(p);
     p=laAddEnumProperty(pc,"pressure_force","Pressure Force","Use pen pressure to control dab force",LA_WIDGET_ENUM_HIGHLIGHT,0,0,0,0,offsetof(OurBrush,PressureForce),0,0,0,0,0,0,0,0,0,0);
     OUR_ADD_PRESSURE_SWITCH(p);
+    p=laAddEnumProperty(pc,"twist_angle","Twist Angle","Use pen twist to control dab angle",LA_WIDGET_ENUM_HIGHLIGHT,0,0,0,0,offsetof(OurBrush,TwistAngle),0,0,0,0,0,0,0,0,0,0);
+    laAddEnumItemAs(p,"NONE","None","Not using twist",0,0);
+    laAddEnumItemAs(p,"ENABLED","Enabled","Using twist",1,0);
     p=laAddEnumProperty(pc,"use_nodes","Use Nodes","Use nodes to control brush dynamics",LA_WIDGET_ENUM_HIGHLIGHT,0,0,0,0,offsetof(OurBrush,UseNodes),0,0,0,0,0,0,0,0,0,0);
     laAddEnumItemAs(p,"NONE","None","Not using nodes",0,0);
     laAddEnumItemAs(p,"ENABLED","Enabled","Using nodes",1,0);

+ 5 - 2
ourpaint.h

@@ -63,6 +63,7 @@ STRUCTURE(OurCanvasDraw){
     real CanvasDownX,CanvasDownY;
     real LastPressure;
     real LastTilt[2];
+    real LastTwist;
 };
 
 #define OUR_DPC (600*0.3937007874)
@@ -146,6 +147,7 @@ STRUCTURE(OurBrushDeviceNode){
     laNodeOutSocket* Pressure; real rPressure;
     laNodeOutSocket* Position; real rPosition[2];
     laNodeOutSocket* Tilt;     real rTilt[2];
+    laNodeOutSocket* Twist;    real rTwist;
     laNodeOutSocket* IsEraser; int  rIsEraser;
     laNodeOutSocket* Speed;    real rSpeed;
     laNodeOutSocket* Angle;    real rAngle;
@@ -169,7 +171,7 @@ STRUCTURE(OurBrush){
     real MaxStrokeLength;
     real Custom1,Custom2; laSafeString *Custom1Name,*Custom2Name;
     int Iteration;
-    int PressureSize,PressureHardness,PressureTransparency,PressureSmudge,PressureForce; // the simple way
+    int PressureSize,PressureHardness,PressureTransparency,PressureSmudge,PressureForce,TwistAngle; // the simple way
 
     int Binding,DefaultAsEraser;
     int ShowInPages;
@@ -197,6 +199,7 @@ STRUCTURE(OurBrush){
     real EvalPressure;
     real EvalPosition[2];
     real EvalTilt[2];
+    real EvalTwist;
     real EvalStrokeAngle;
     int  EvalIsEraser;
 
@@ -326,7 +329,7 @@ STRUCTURE(OurPaint){
     int BadEventsLimit,BadEventCount,BadEventsGiveUp;
 
     int LockRadius;
-    int EnableBrushCircle;
+    int EnableBrushCircle; int EventHasTwist; real EventTwistAngle;
     int DefaultBitDepth;
     int DefaultColorProfile;
     int PaintUndoLimit;