*/}}

la_tns_shape.c 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533
  1. /*
  2. * LaGUI: A graphical application framework.
  3. * Copyright (C) 2022-2023 Wu Yiming
  4. *
  5. * This program is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation, either version 3 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. #include "la_5.h"
  19. #include <math.h>
  20. extern LA MAIN;
  21. extern tnsMain *T;
  22. tnsShape* tnsNewShape(tnsShapeObject* so){
  23. tnsShape* s=memAcquireSimple(sizeof(tnsShape));
  24. lstAppendItem(&so->Shapes,s); return s;
  25. }
  26. tnsSPoint* tnsNewSPoint(tnsShape* s,real x, real y,real ldx,real ldy, real rdx,real rdy){
  27. tnsSPoint* sp=memAcquireSimple(sizeof(tnsSPoint));
  28. tnsVectorSet2(sp->p,x,y); tnsVectorSet2(sp->dl,ldx,ldy); tnsVectorSet2(sp->dr,rdx,rdy);
  29. lstAppendItem(&s->Points,sp); return sp;
  30. }
  31. tnsSPoint* tnsShapeInsertSPointAt(tnsShape* s, tnsSPoint* pivot, int before){
  32. tnsSPoint* sp=memAcquireSimple(sizeof(tnsSPoint));
  33. tnsVectorSet2v(sp->p,pivot->p); tnsVectorSet2v(sp->dl,pivot->dl); tnsVectorSet2v(sp->dr,pivot->dr);
  34. if(before){ lstInsertItemBefore(&s->Points,sp,pivot); }
  35. else{ lstInsertItemAfter(&s->Points,sp,pivot); }
  36. return sp;
  37. }
  38. void tnsShapeSetHole(tnsShape* s, int closed, int toggle){
  39. if(toggle) tnsShapeSetHole(s,!(s->flags&TNS_SHAPE_HOLE),0);
  40. else{ if(closed) s->flags|=TNS_SHAPE_HOLE; else s->flags&=(~TNS_SHAPE_HOLE); }
  41. }
  42. void tnsShapeSetClosed(tnsShape* s, int closed, int toggle){
  43. if(toggle) tnsShapeSetClosed(s,!(s->flags&TNS_SHAPE_CLOSED),0);
  44. else{ if(closed) s->flags|=TNS_SHAPE_CLOSED; else s->flags&=(~TNS_SHAPE_CLOSED); }
  45. }
  46. void tnsShapeSetEndPoint(tnsShape* s, tnsSPoint* p){
  47. tnsSPoint* ep=s->Points.pLast, *sp=s->Points.pFirst, *np=p->Item.pNext; if(!np || ep==sp || sp->Item.pNext==ep) return;
  48. sp->Item.pPrev=ep; ep->Item.pNext=sp; np->Item.pPrev=0; p->Item.pNext=0;
  49. s->Points.pFirst=np; s->Points.pLast=p;
  50. }
  51. void tnsShapeClearExtraFlags(tnsShapeObject* so){
  52. for(tnsShape* s=so->Shapes.pFirst;s;s=s->Item.pNext){ s->flags&=(~TNS_MESH_FLAG_PICKED);
  53. for(tnsSPoint* sp=s->Points.pFirst;sp;sp=sp->Item.pNext){ sp->flags&=(~TNS_MESH_FLAG_PICKED); }
  54. }
  55. }
  56. void tnsShapeRefreshIndex(tnsShapeObject* so){
  57. u32bit i=0; tnsShape* NextS; for(tnsShape* s=so->Shapes.pFirst;s;s=NextS){ NextS=s->Item.pNext;
  58. if(!s->Points.pFirst){ lstRemoveItem(&so->Shapes,s); memLeave(s); continue; }
  59. for(tnsSPoint* sp=s->Points.pFirst;sp;sp=sp->Item.pNext){ sp->i=i; i++; }
  60. }
  61. }
  62. int tnsShapePointAnySelected(tnsShape* s){
  63. for(tnsSPoint* sp=s->Points.pFirst;sp;sp=sp->Item.pNext){ if(sp->flags&TNS_SPOINT_SELECTED) return 1; } return 0;
  64. }
  65. int tnsShapeAnySelected(tnsShapeObject* so){
  66. for(tnsShape* s=so->Shapes.pFirst;s;s=s->Item.pNext){ if(tnsShapePointAnySelected(s)) return 1; } return 0;
  67. }
  68. void tnsShapeDeselectAll(tnsShapeObject* so){
  69. for(tnsShape* s=so->Shapes.pFirst;s;s=s->Item.pNext){
  70. for(tnsSPoint* sp=s->Points.pFirst;sp;sp=sp->Item.pNext){ sp->flags&=(~TNS_SPOINT_SELECTED); }
  71. }
  72. }
  73. void tnsShapeSelectAll(tnsShapeObject* so){
  74. for(tnsShape* s=so->Shapes.pFirst;s;s=s->Item.pNext){
  75. for(tnsSPoint* sp=s->Points.pFirst;sp;sp=sp->Item.pNext){ sp->flags|=TNS_SPOINT_SELECTED; }
  76. }
  77. }
  78. void tnsShapeSelectPoint(tnsShapeObject* so, tnsSPoint* sp, int select, int toggle, int lr){
  79. if(!so) return; int flag=(lr==1)?TNS_SPOINT_SELECTED_L:(lr==2)?TNS_SPOINT_SELECTED_R:(TNS_SPOINT_SELECTED);
  80. if(!(sp->flags&TNS_SPOINT_BEZIER)){ flag=TNS_SPOINT_SELECTED; }
  81. if(toggle) tnsShapeSelectPoint(so,sp,((sp->flags&flag)==flag?0:1),0,lr);
  82. elif(select) sp->flags|=flag; else sp->flags&=(~flag);
  83. //if(!so->FirstSelectV) so->FirstSelectV=sp; so->LastSelectV=sp;
  84. }
  85. void tnsShapeSelectRingFrom(tnsShapeObject* so, tnsSPoint* sp, int select, int toggle){
  86. int has_idle=0; laListHandle spl={sp->Item.pPrev,sp->Item.pNext};
  87. while(spl.pFirst && ((laListItem*)spl.pFirst)->pPrev){ spl.pFirst=((laListItem*)spl.pFirst)->pPrev; }
  88. while(spl.pLast && ((laListItem*)spl.pLast)->pNext){ spl.pLast=((laListItem*)spl.pLast)->pNext; }
  89. if(toggle){
  90. for(tnsSPoint* isp=spl.pFirst;isp;isp=isp->Item.pNext){
  91. if(isp!=sp && (!(isp->flags&TNS_SPOINT_SELECTED))) has_idle=1;
  92. if(has_idle){ break; }
  93. }
  94. if(has_idle){ select=1; }else{ select=0; }
  95. }
  96. for(tnsSPoint* isp=spl.pFirst;isp;isp=isp->Item.pNext){
  97. if(select){ isp->flags|=TNS_SPOINT_SELECTED; }else{ isp->flags&=(~TNS_SPOINT_SELECTED); }
  98. }
  99. }
  100. void tnsShapeSelectLinked(tnsShapeObject* so){
  101. for(tnsShape* s=so->Shapes.pFirst;s;s=s->Item.pNext){
  102. if(!tnsShapePointAnySelected(s)){ continue; }
  103. for(tnsSPoint* sp=s->Points.pFirst;sp;sp=sp->Item.pNext){ sp->flags|=TNS_SPOINT_SELECTED; }
  104. }
  105. }
  106. tnsShape* tnsShapeRemovePoint(tnsShapeObject* so, tnsShape* s, tnsSPoint* sp, int SplitShape){
  107. if(SplitShape && sp->Item.pNext && sp->Item.pPrev){
  108. if(s->flags&TNS_SHAPE_CLOSED){ tnsShapeSetEndPoint(s,sp); }
  109. tnsShape* ns=tnsNewShape(so); ns->mat=s->mat;
  110. tnsSPoint* NextIP; for(tnsSPoint* ip=sp->Item.pNext;ip;ip=NextIP){ NextIP=ip->Item.pNext;
  111. tnsSPoint* nsp=tnsNewSPoint(ns,ip->p[0],ip->p[1],ip->dl[0],ip->dl[1],ip->dr[0],ip->dr[1]);
  112. nsp->flags=ip->flags; lstRemoveItem(&s->Points,ip);
  113. }
  114. s->flags&=(~TNS_SHAPE_CLOSED); ns->flags&=(~TNS_SHAPE_CLOSED);
  115. lstRemoveItem(&s->Points,sp); memLeave(sp); return ns;
  116. }else{
  117. lstRemoveItem(&s->Points,sp); memLeave(sp); return 0;
  118. }
  119. }
  120. int tnsShapeConnect(tnsShapeObject* so, tnsShape* s1, tnsShape* s2, tnsSPoint* sp1, tnsSPoint* sp2){
  121. if((sp1!=s1->Points.pFirst && sp1!=s1->Points.pLast) || (sp2!=s2->Points.pFirst && sp2!=s2->Points.pLast)) return 0;
  122. if(sp1==s1->Points.pFirst){ lstReverse(&s1->Points);for(tnsSPoint*sp=s1->Points.pFirst;sp;sp=sp->Item.pNext){ LA_SWAP(real,sp->dl[0],sp->dr[0]); LA_SWAP(real,sp->dl[1],sp->dr[1]); } }
  123. if(sp2==s2->Points.pLast){ lstReverse(&s2->Points);for(tnsSPoint*sp=s2->Points.pFirst;sp;sp=sp->Item.pNext){ LA_SWAP(real,sp->dl[0],sp->dr[0]); LA_SWAP(real,sp->dl[1],sp->dr[1]); } }
  124. tnsSPoint* ip;while(ip=lstPopItem(&s2->Points)){
  125. tnsSPoint* nsp=tnsNewSPoint(s1,ip->p[0],ip->p[1],ip->dl[0],ip->dl[1],ip->dr[0],ip->dr[1]);
  126. nsp->flags=ip->flags; memLeave(ip);
  127. }
  128. lstRemoveItem(&so->Shapes.pFirst,s2); memLeave(s2); tnsShapeRefreshIndex(so);
  129. return 1;
  130. }
  131. int tnsShapeConnectSelected(tnsShapeObject* so){
  132. tnsShape* s1=0,*s2=0; tnsSPoint* sp1=0,*sp2=0;
  133. for(tnsShape*s=so->Shapes.pFirst;s;s=s->Item.pNext){ if(s->flags&TNS_SHAPE_CLOSED) continue;
  134. if(!s1){
  135. if(((tnsSPoint*)s->Points.pFirst)->flags&TNS_MESH_FLAG_SELECTED){ s1=s;sp1=s->Points.pFirst; }
  136. elif(((tnsSPoint*)s->Points.pLast)->flags&TNS_MESH_FLAG_SELECTED){ s1=s;sp1=s->Points.pLast; }
  137. }else{
  138. if(((tnsSPoint*)s->Points.pFirst)->flags&TNS_MESH_FLAG_SELECTED){ s2=s;sp2=s->Points.pFirst; break; }
  139. elif(((tnsSPoint*)s->Points.pLast)->flags&TNS_MESH_FLAG_SELECTED){ s2=s;sp2=s->Points.pLast; break; }
  140. }
  141. }
  142. if(s1&&s2&&sp1&&sp2){ return tnsShapeConnect(so,s1,s2,sp1,sp2); } return 0;
  143. }
  144. int tnsShapeExtrudeSelected(tnsShapeObject* so, int DupliOnly){
  145. laListHandle* pairs; tnsShape* NextS; int any=0;
  146. for(tnsShape* s=so->Shapes.pFirst;s;s=NextS){ NextS=s->Item.pNext;
  147. if(s->flags&TNS_MESH_FLAG_PICKED){ continue; }
  148. tnsSPoint* PrevSP=0,*NextSP=0,*nsp=0;
  149. tnsShape* ns=0; int broken=0;
  150. for(tnsSPoint* sp=s->Points.pFirst;sp;sp=sp->Item.pNext){
  151. if(!(sp->flags&TNS_MESH_FLAG_SELECTED)){ broken=1; break; }
  152. }
  153. if(!broken){ any=1;
  154. tnsShape* ns=tnsNewShape(so); for(tnsSPoint* sp=s->Points.pFirst;sp;sp=sp->Item.pNext){
  155. tnsSPoint* nsp=tnsNewSPoint(ns,sp->p[0],sp->p[1],sp->dl[0],sp->dl[1],sp->dr[0],sp->dr[1]); nsp->flags=sp->flags;
  156. }
  157. ns->flags=(s->flags|TNS_MESH_FLAG_PICKED); ns->mat=s->mat;
  158. for(tnsSPoint* sp=s->Points.pFirst;sp;sp=sp->Item.pNext){ sp->flags&=(~TNS_SPOINT_SELECTED); } continue;
  159. }
  160. for(tnsSPoint* sp=s->Points.pFirst;sp;sp=NextSP){ NextSP=sp->Item.pNext;
  161. if(!(sp->flags&TNS_MESH_FLAG_SELECTED)){ PrevSP=sp; continue; }
  162. int doprev=0,donext=0;
  163. if((!PrevSP) || (PrevSP->flags^sp->flags)&TNS_MESH_FLAG_SELECTED){ doprev=1; }
  164. if((!NextSP) || (NextSP->flags^sp->flags)&TNS_MESH_FLAG_SELECTED){ donext=1; }
  165. if(DupliOnly){
  166. if(doprev){ ns=tnsNewShape(so); ns->flags=(s->flags&(~TNS_SHAPE_CLOSED));
  167. ns->flags|=TNS_MESH_FLAG_PICKED; ns->mat=s->mat; any=1;
  168. }
  169. if(ns){ nsp=tnsNewSPoint(ns,sp->p[0],sp->p[1],sp->dl[0],sp->dl[1],sp->dr[0],sp->dr[1]);
  170. nsp->flags=sp->flags;
  171. }
  172. if(donext){ ns=0; }
  173. }else{
  174. if(!(doprev&&donext)){ any=1;
  175. if(doprev) tnsShapeInsertSPointAt(s,sp,1);
  176. elif(donext) tnsShapeInsertSPointAt(s,sp,0);
  177. }else{
  178. if((!NextSP) && donext){ tnsShapeInsertSPointAt(s,sp,1); }
  179. else{ tnsShapeInsertSPointAt(s,sp,0); }
  180. }
  181. }
  182. PrevSP=sp;
  183. }
  184. }
  185. if(DupliOnly){
  186. for(tnsShape* s=so->Shapes.pFirst;s;s=NextS){ NextS=s->Item.pNext;
  187. if(s->flags&TNS_MESH_FLAG_PICKED){ continue; }
  188. for(tnsSPoint* sp=s->Points.pFirst;sp;sp=sp->Item.pNext){ sp->flags&=(~TNS_SPOINT_SELECTED); }
  189. }
  190. }
  191. tnsShapeClearExtraFlags(so);
  192. tnsShapeRefreshIndex(so);
  193. return any;
  194. }
  195. void tnsShapeEnterEditMode(tnsShapeObject* so){
  196. if(so->Mode==TNS_MESH_EDIT_MODE) return;
  197. so->Mode = TNS_MESH_EDIT_MODE; tnsShapeRefreshIndex(so);
  198. tnsInvalidateEvaluation(so);
  199. }
  200. void tnsShapeLeaveEditMode(tnsShapeObject* so){
  201. if(so->Mode==TNS_MESH_OBJECT_MODE) return;
  202. so->Mode = TNS_MESH_OBJECT_MODE;
  203. tnsInvalidateEvaluation(so);
  204. }
  205. tnsShapeObject* tnsDuplicateShapeObject(tnsShapeObject* from){
  206. if(from->Base.Type!=TNS_OBJECT_SHAPE) return 0;
  207. tnsShapeObject* to = memAcquireHyper(sizeof(tnsShapeObject));
  208. tnsInitObjectBase(to, from->Base.ParentObject?from->Base.ParentObject:from->Base.InRoot, from->Base.Name->Ptr, TNS_OBJECT_SHAPE,0,0,0,0,0,0,0,0,1);
  209. tnsCopyObjectTransformationsLocal(to,from);
  210. tnsMaterialSlot* new_current=0;
  211. for(tnsMaterialSlot* ms=from->Materials.pFirst;ms;ms=ms->Item.pNext){
  212. tnsMaterialSlot* nms=tnsNewMaterialSlot(to); nms->Index=ms->Index;
  213. memAssignRef(nms,&nms->Material,ms->Material);
  214. if(ms==from->CurrentMaterial) new_current=nms;
  215. }
  216. memAssignRef(to,&to->CurrentMaterial,new_current);
  217. if(!from->Shapes.pFirst){ return to; }
  218. for(tnsShape* s=from->Shapes.pFirst;s;s=s->Item.pNext){
  219. tnsShape* ns=tnsNewShape(to); for(tnsSPoint* sp=s->Points.pFirst;sp;sp=sp->Item.pNext){
  220. tnsSPoint* nsp=tnsNewSPoint(ns,sp->p[0],sp->p[1],sp->dl[0],sp->dl[1],sp->dr[0],sp->dr[1]); nsp->flags=sp->flags;
  221. }
  222. ns->flags=s->flags;ns->mat=s->mat;
  223. }
  224. return to;
  225. }
  226. void tnsInitShapeSquare(tnsShapeObject* so, real size){
  227. tnsShape* s=tnsNewShape(so);
  228. tnsNewSPoint(s,-size,-size,0,0,0,0)->flags|=TNS_MESH_FLAG_SELECTED;
  229. tnsNewSPoint(s,-size,size,0,0,0,0)->flags|=TNS_MESH_FLAG_SELECTED;
  230. tnsNewSPoint(s,size,size,0,0,0,0)->flags|=TNS_MESH_FLAG_SELECTED;
  231. tnsNewSPoint(s,size,-size,0,0,0,0)->flags|=TNS_MESH_FLAG_SELECTED;
  232. tnsShapeSetClosed(s,1,0); tnsShapeRefreshIndex(so);
  233. }
  234. NVGpaint tns_GetMaterial2D(tnsMaterial* m){
  235. NVGcontext* vg=MAIN.CurrentWindow->nvg;
  236. if(m->GradientMode==TNS_GRADIENT_MODE_LINEAR){
  237. return nvgLinearGradient(vg,m->GradientCenter[0],m->GradientCenter[1],m->GradientSize[0],m->GradientSize[1],
  238. nvgRGBAf(LA_COLOR4(m->Color)),nvgRGBAf(LA_COLOR4(m->Color2)));
  239. }elif(m->GradientMode==TNS_GRADIENT_MODE_BOX){
  240. return nvgBoxGradient(vg,m->GradientCenter[0],m->GradientCenter[1],m->GradientSize[0],m->GradientSize[1],
  241. m->GradientBoxR,m->GradientBoxF,nvgRGBAf(LA_COLOR4(m->Color)),nvgRGBAf(LA_COLOR4(m->Color2)));
  242. }elif(m->GradientMode==TNS_GRADIENT_MODE_RADIAL){
  243. return nvgRadialGradient(vg,m->GradientCenter[0],m->GradientCenter[1],m->GradientSize[0],m->GradientSize[1],
  244. nvgRGBAf(LA_COLOR4(m->Color)),nvgRGBAf(LA_COLOR4(m->Color2)));
  245. }
  246. NVGpaint p={0}; return p;
  247. }
  248. void tns_DrawShape(tnsShape* s, tnsMaterial* mat, real* override_color, int DrawEdit, real PointScale){
  249. if(!s->Points.pFirst) return; int HasSelection=0; int closed=(s->flags&TNS_SHAPE_CLOSED);
  250. NVGcontext* vg=MAIN.CurrentWindow->nvg;
  251. if(DrawEdit==2){
  252. nvgShapeAntiAlias(vg,0);
  253. for(tnsSPoint* sp=s->Points.pFirst;sp;sp=sp->Item.pNext){ real color[4]={0,0,0,1};
  254. nvgBeginPath(vg); nvgCircle(vg,sp->p[0],sp->p[1],PointScale*1);
  255. TNS_ID_TO_COLOR(color,sp->i*3+1); nvgFillColor(vg,nvgRGBAf(LA_COLOR4(color))); nvgFill(vg);
  256. nvgBeginPath(vg); nvgCircle(vg,sp->p[0]+sp->dl[0],sp->p[1]+sp->dl[1],PointScale*1);
  257. TNS_ID_TO_COLOR(color,sp->i*3+2); nvgFillColor(vg,nvgRGBAf(LA_COLOR4(color))); nvgFill(vg);
  258. nvgBeginPath(vg); nvgCircle(vg,sp->p[0]+sp->dr[0],sp->p[1]+sp->dr[1],PointScale*1);
  259. TNS_ID_TO_COLOR(color,sp->i*3+3); nvgFillColor(vg,nvgRGBAf(LA_COLOR4(color))); nvgFill(vg);
  260. }
  261. nvgShapeAntiAlias(vg,1);
  262. return;
  263. }
  264. if(DrawEdit){ nvgBeginPath(vg); }
  265. tnsSPoint* sp1=s->Points.pFirst; nvgMoveTo(vg,sp1->p[0],sp1->p[1]); if(sp1->flags&TNS_SPOINT_SELECTED){HasSelection=1;}
  266. for(tnsSPoint* sp=sp1->Item.pNext;sp;sp=sp->Item.pNext){
  267. if(sp->flags&TNS_SPOINT_SELECTED){HasSelection=1;}
  268. if(sp->Item.pPrev){ tnsSPoint* np=sp->Item.pPrev;
  269. real c1[2],c2[2]; tnsVectorSet2v(c1,np->p); tnsVectorSet2v(c2,sp->p);
  270. if(np->flags&TNS_SPOINT_BEZIER){ tnsVectorAccum2d(c1,np->dr); }
  271. if(sp->flags&TNS_SPOINT_BEZIER){ tnsVectorAccum2d(c2,sp->dl); }
  272. nvgBezierTo(vg,c1[0],c1[1],c2[0],c2[1],sp->p[0],sp->p[1]);
  273. }else{
  274. nvgLineTo(vg,sp->p[0],sp->p[1]);
  275. }
  276. }
  277. if(closed && (sp1!=s->Points.pLast)){
  278. tnsSPoint* np=s->Points.pLast; tnsSPoint* sp=sp1;
  279. real c1[2],c2[2]; tnsVectorSet2v(c1,np->p); tnsVectorSet2v(c2,sp->p);
  280. if(np->flags&TNS_SPOINT_BEZIER){ tnsVectorAccum2d(c1,np->dr); }
  281. if(sp->flags&TNS_SPOINT_BEZIER){ tnsVectorAccum2d(c2,sp->dl); }
  282. nvgBezierTo(vg,c1[0],c1[1],c2[0],c2[1],sp->p[0],sp->p[1]);
  283. nvgClosePath(vg);
  284. nvgPathWinding(vg,(s->flags&TNS_SHAPE_HOLE)?NVG_HOLE:NVG_SOLID);
  285. if(!(s->flags&TNS_SHAPE_HOLE)){
  286. if((!override_color) && mat && mat->GradientMode){
  287. nvgFillPaint(vg,tns_GetMaterial2D(mat));
  288. }else{
  289. nvgFillColor(vg, override_color?nvgRGBAf(LA_COLOR4(override_color)):(mat?nvgRGBAf(LA_COLOR4(mat->Color)):nvgRGBAf(0.8,0.8,0.8,1)));
  290. }
  291. }
  292. }
  293. if(DrawEdit || (!closed)){
  294. tnsVector4d color; tnsVectorCopy4d(laAccentColor(LA_BT_VERTEX),color);
  295. real* ActiveColor=laAccentColor(LA_BT_SVERTEX);
  296. if(DrawEdit && (!HasSelection)) color[3]*=0.4;
  297. nvgStrokeColor(vg,override_color?nvgRGBAf(LA_COLOR4(override_color)):nvgRGBAf(LA_COLOR4(color)));
  298. nvgStrokeWidth(vg,PointScale*4);
  299. if(!DrawEdit){nvgShapeAntiAlias(vg,0);nvgStroke(vg);nvgShapeAntiAlias(vg,1);return;}
  300. nvgStroke(vg);
  301. for(tnsSPoint* sp=s->Points.pFirst;sp;sp=sp->Item.pNext){ int mainsel=sp->flags&TNS_MESH_FLAG_SELECTED;
  302. if(sp->flags&(TNS_SPOINT_FREE|TNS_SPOINT_ALIGNED)){
  303. nvgStrokeWidth(vg,PointScale*2);
  304. nvgStrokeColor(vg,(mainsel||(sp->flags&TNS_SPOINT_SELECTED_L))?nvgRGBAf(LA_COLOR4(ActiveColor)):nvgRGBAf(LA_COLOR4(color)));
  305. nvgBeginPath(vg); nvgMoveTo(vg,sp->p[0]+sp->dl[0],sp->p[1]+sp->dl[1]); nvgLineTo(vg,sp->p[0],sp->p[1]);
  306. nvgStroke(vg);
  307. nvgBeginPath(vg); nvgCircle(vg,sp->p[0]+sp->dl[0],sp->p[1]+sp->dl[1],PointScale*5);
  308. nvgStroke(vg);
  309. nvgStrokeColor(vg,(mainsel||(sp->flags&TNS_SPOINT_SELECTED_R))?nvgRGBAf(LA_COLOR4(ActiveColor)):nvgRGBAf(LA_COLOR4(color)));
  310. nvgBeginPath(vg); nvgMoveTo(vg,sp->p[0]+sp->dr[0],sp->p[1]+sp->dr[1]); nvgLineTo(vg,sp->p[0],sp->p[1]);
  311. nvgStroke(vg);
  312. nvgBeginPath(vg); nvgCircle(vg,sp->p[0]+sp->dr[0],sp->p[1]+sp->dr[1],PointScale*5);
  313. nvgStroke(vg);
  314. }
  315. nvgBeginPath(vg); nvgCircle(vg,sp->p[0],sp->p[1],PointScale*5);
  316. nvgFillColor(vg,mainsel?nvgRGBAf(LA_COLOR4(ActiveColor)):nvgRGBAf(LA_COLOR4(color)));
  317. nvgFill(vg);
  318. }
  319. }
  320. }
  321. void tnsDrawShapeObjectShapes(tnsEvaluatedInstance* ei, la3DObjectDrawExtra* de, real* override_color, int DrawEdit){
  322. tnsShapeObject* so=ei->Object; NVGcontext* vg=MAIN.CurrentWindow->nvg;
  323. real sca[3]; tnsExtractScale44d(ei->Mat,sca);
  324. real rot[3]; tnsExtractXYZEuler44d(ei->Mat,rot);
  325. nvgSave(vg);
  326. if(de->Is3D){
  327. tnsVector4d pos; tnsApplyTransform44d(pos,de->mViewProj,&ei->Mat[12]);
  328. pos[0]/=pos[3]; pos[1]/=pos[3];
  329. nvgTranslate(vg,pos[0]*de->W/2,pos[1]*de->H/2);
  330. nvgScale(vg,LA_RH*sca[0],LA_RH*sca[1]); nvgRotate(vg,rot[2]);
  331. }else{
  332. nvgTranslate(vg,ei->Mat[12],-ei->Mat[13]);
  333. nvgScale(vg,sca[0],-sca[1]); nvgRotate(vg,rot[2]);
  334. }
  335. if(DrawEdit!=2){ int begun=0; int ishole=0,nexthole=0;
  336. for(tnsShape*s=so->Shapes.pFirst;s;s=s->Item.pNext){ tnsMaterial* mat=0;
  337. if(de->DisplayMode==LA_CANVAS_DISPLAY_MATERIAL){
  338. for(tnsMaterialSlot* ms=so->Materials.pFirst;ms;ms=ms->Item.pNext){ if(s->mat==ms->Index){ mat=ms->Material; break; } }
  339. }
  340. if(!begun){ begun=1; nvgBeginPath(vg); }
  341. ishole=s->flags&TNS_SHAPE_HOLE; tnsShape* ns=s->Item.pNext; nexthole=ns?(ns->flags&TNS_SHAPE_HOLE):0;
  342. tns_DrawShape(s,mat,override_color,0,de->PointScale/sca[0]);
  343. if(!nexthole /*(!ns) || (ishole &&(!nexthole))*/){ nvgFill(vg); begun=0; }
  344. }
  345. }
  346. if(DrawEdit||so->Mode==TNS_MESH_EDIT_MODE){
  347. for(tnsShape*s=so->Shapes.pFirst;s;s=s->Item.pNext){
  348. tns_DrawShape(s,0,override_color,DrawEdit?DrawEdit:so->Mode==TNS_MESH_EDIT_MODE,de->PointScale/sca[0]);
  349. }
  350. }
  351. nvgRestore(vg);
  352. }
  353. void tnsDrawShapeObject(tnsEvaluatedInstance* ei, la3DObjectDrawExtra* de){
  354. tnsShapeObject* so=ei->Object; if(!so->Shapes.pFirst){ tnsDrawSingleObjectOrigin(so); }
  355. tnsDrawShapeObjectShapes(ei,de,0,0);
  356. }
  357. void tnsDrawShapeObjectSelectionID(tnsEvaluatedInstance* ei, la3DObjectDrawExtra* de){
  358. int i=ei->InstanceSelectionID; real color[4]={0,0,0,1}; TNS_ID_TO_COLOR(color,i);
  359. tnsDrawShapeObjectShapes(ei,de,color,0);
  360. }
  361. void tnsDrawShapePointsSelectionID(tnsEvaluatedInstance* ei, la3DObjectDrawExtra* de){
  362. tnsDrawShapeObjectShapes(ei,de,0,2);
  363. }
  364. void tnsDrawShapeObjectOverlay(tnsEvaluatedInstance* ei, la3DObjectDrawExtra* de){
  365. int i=ei->InstanceSelectionID; real color[4]; tnsVectorCopy4d(laAccentColor(LA_BT_ACTIVE),color);
  366. if(ei->Object!=ei->Object->InRoot->Active){ color[3]=0.4; }else{ color[3]=0.7; }
  367. tnsDrawShapeObjectShapes(ei,de,color,0);
  368. }
  369. void tnsEvaluateShapeObject(tnsShapeObject* so, tnsEvaluateData* ed){
  370. int DrawTo=TNS_EVAL_LAYER_SOLID;
  371. if(so->Backdrop){ DrawTo=TNS_EVAL_LAYER_BACKDROP; }
  372. tnsAddEvaluatedInstance(ed,so,tnsDrawShapeObject,DrawTo,0,0,0);
  373. if(ed->FillSelectionID){
  374. tnsAddEvaluatedInstance(ed,so,tnsDrawShapeObjectSelectionID,TNS_EVAL_LAYER_SELECTION,0,1,so->Base.SelectID);
  375. }
  376. if(ed->FillOutline && (!ed->OverrideID)){
  377. if((so->Base.Flags&TNS_OBJECT_FLAGS_SELECTED) && (so->Mode!=TNS_MESH_EDIT_MODE)){
  378. tnsAddEvaluatedInstance(ed,so,tnsDrawShapeObjectOverlay,TNS_EVAL_LAYER_OVERLAY,0,0,0);
  379. }
  380. }
  381. }
  382. tnsShapeObject *tnsCreateShapeEmpty(tnsObject *under, char *Name, real AtX, real AtY, real AtZ){
  383. tnsShapeObject *so = memAcquireHyper(sizeof(tnsShapeObject));
  384. tnsInitObjectBase(&so->Base, under, Name, TNS_OBJECT_SHAPE, AtX, AtY, AtZ, 0, 0, 0, 1.0f, TNS_ROTATION_XYZ_EULER, 1.0f);
  385. return so;
  386. }
  387. tnsShapeObject *tnsCreateShapeSquare(tnsObject *under, char *Name, real AtX, real AtY, real AtZ, real size){
  388. tnsShapeObject *so=tnsCreateShapeEmpty(under, Name, AtX, AtY, AtZ);
  389. tnsInitShapeSquare(so, size);
  390. return so;
  391. }
  392. int OPCHK_IsAnyPointSelected(laPropPack *This, laStringSplitor *ss){
  393. if(This && This->EndInstance){
  394. laCanvasExtra* ex=This->EndInstance; laUiItem* ui=ex->ParentUi;
  395. tnsObject*root=ui?ui->PP.EndInstance:0; if(!root) return 0;
  396. if(root->Active && root->Active->Type!=TNS_OBJECT_SHAPE) return 0;
  397. tnsShapeObject* so=root->Active; return tnsShapeAnySelected(so);
  398. }
  399. return 0;
  400. }
  401. int OPINV_SetPointHandle(laOperator *a, laEvent *e){
  402. laCanvasExtra* ex=a->This->EndInstance; laUiItem* ui=ex->ParentUi;
  403. tnsObject*root=ui?ui->PP.EndInstance:0;
  404. if(!root || !root->Active || root->Active->Type!=TNS_OBJECT_SHAPE) return LA_FINISHED;
  405. tnsShapeObject* so=root->Active; int ran=0;
  406. char* mode=strGetArgumentString(a->ExtraInstructionsP,"mode");
  407. if(!mode){
  408. laEnableOperatorPanel(a,a->This,e->x,e->y,200,200,0,0,0,0,0,0,0,0,e); return LA_RUNNING;
  409. }
  410. int flags=0,HandleFlags=TNS_SPOINT_ALIGNED|TNS_SPOINT_FREE;
  411. if(strSame(mode,"ALIGNED")){ flags=TNS_SPOINT_ALIGNED; }
  412. elif(strSame(mode,"FREE")){ flags=TNS_SPOINT_FREE; }
  413. tnsVector2d pl={0,0},pr={0,0};
  414. for(tnsShape*s=so->Shapes.pFirst;s;s=s->Item.pNext){
  415. for(tnsSPoint*sp=s->Points.pFirst;sp;sp=sp->Item.pNext){ if(!(sp->flags&TNS_MESH_FLAG_SELECTED)) continue;
  416. int oldf=sp->flags&HandleFlags, hasl=0,hasr=0;
  417. sp->flags&=(~HandleFlags); sp->flags|=flags; ran=1; if(!flags){ continue; }
  418. if(sp->Item.pPrev){ tnsVectorSet2v(pl,((tnsSPoint*)sp->Item.pPrev)->p); hasl=1;}
  419. if(sp->Item.pNext){ tnsVectorSet2v(pr,((tnsSPoint*)sp->Item.pNext)->p); hasr=1;}
  420. if(!hasl){
  421. if(!hasr){ tnsVectorSet2(pl,sp->p[0]-0.5,sp->p[1]); tnsVectorSet2(pr,sp->p[0]+0.5,sp->p[1]); }
  422. else{ tnsVectorSet2(pl,-pr[0]+2*sp->p[0],-pr[1]+2*sp->p[1]); }
  423. }else{
  424. if(!hasr){ tnsVectorSet2(pr,-pl[0]+2*sp->p[0],-pl[1]+2*sp->p[1]); }
  425. }
  426. if(flags==TNS_SPOINT_ALIGNED && flags!=oldf){
  427. tnsVector2d diff; tnsVectorMinus2d(diff,pr,pl); tnsVectorMultiSelf2d(diff,0.25);
  428. tnsVectorSet2v(sp->dr,diff); tnsVectorMultiSelf2d(diff,-1); tnsVectorSet2v(sp->dl,diff);
  429. }elif(flags==TNS_SPOINT_FREE && oldf!=TNS_SPOINT_ALIGNED){
  430. tnsVectorMinus2d(sp->dl,pl,sp->p); tnsVectorMultiSelf2d(sp->dl,0.3);
  431. tnsVectorMinus2d(sp->dr,pr,sp->p); tnsVectorMultiSelf2d(sp->dr,0.3);
  432. }
  433. }
  434. }
  435. if(ran){
  436. laRecordInstanceDifferences(so,"tns_shape_object"); laPushDifferences("Set point handle",TNS_HINT_GEOMETRY);
  437. laNotifyUsers("tns.world");
  438. }
  439. return LA_FINISHED;
  440. }
  441. void laui_SetPointHandle(laUiList *uil, laPropPack *pp, laPropPack *actinst, laColumn *extracol, int context){
  442. laColumn* c=laFirstColumn(uil);
  443. laShowItemFull(uil,c,pp,"_this_M_set_point_handle",0,"mode=NONE;text=Normal",0,0);
  444. laShowItemFull(uil,c,pp,"_this_M_set_point_handle",0,"mode=ALIGNED;text=Aligned",0,0);
  445. laShowItemFull(uil,c,pp,"_this_M_set_point_handle",0,"mode=FREE;text=Free",0,0);
  446. }
  447. int OPINV_SetShapeClosed(laOperator *a, laEvent *e){
  448. laCanvasExtra* ex=a->This->EndInstance; laUiItem* ui=ex->ParentUi;
  449. tnsObject*root=ui?ui->PP.EndInstance:0;
  450. if(!root || !root->Active || root->Active->Type!=TNS_OBJECT_SHAPE) return LA_FINISHED;
  451. tnsShapeObject* so=root->Active; int ran=0;
  452. char* mode=strGetArgumentString(a->ExtraInstructionsP,"mode");
  453. char* res=strGetArgumentString(a->ExtraInstructionsP,"reset");
  454. int set=2; if(strSame(mode,"CLOSE")){ set=1; }elif(strSame(mode,"OPEN")){ set=0; }
  455. int reset=0; if(strSame(res,"TRUE")){ reset=1; }
  456. for(tnsShape*s=so->Shapes.pFirst;s;s=s->Item.pNext){
  457. for(tnsSPoint*sp=s->Points.pFirst;sp;sp=sp->Item.pNext){ if(!(sp->flags&TNS_SPOINT_SELECTED)) continue;
  458. if(reset){ tnsShapeSetEndPoint(s,sp); tnsShapeRefreshIndex(so); tnsShapeSetClosed(s,0,0); }
  459. else{ tnsShapeSetClosed(s,set,set==2); } ran=1; break;
  460. }
  461. }
  462. if(ran){
  463. laRecordInstanceDifferences(so,"tns_shape_object"); laPushDifferences("Open/Close shape",TNS_HINT_GEOMETRY);
  464. laNotifyUsers("tns.world");
  465. }
  466. return LA_FINISHED;
  467. }
  468. int OPINV_SetShapeHole(laOperator *a, laEvent *e){
  469. laCanvasExtra* ex=a->This->EndInstance; laUiItem* ui=ex->ParentUi;
  470. tnsObject*root=ui?ui->PP.EndInstance:0;
  471. if(!root || !root->Active || root->Active->Type!=TNS_OBJECT_SHAPE) return LA_FINISHED;
  472. tnsShapeObject* so=root->Active; int ran=0;
  473. char* mode=strGetArgumentString(a->ExtraInstructionsP,"mode");
  474. int set=2; if(strSame(mode,"HOLE")){ set=1; }elif(strSame(mode,"FILL")){ set=0; }
  475. for(tnsShape*s=so->Shapes.pFirst;s;s=s->Item.pNext){
  476. for(tnsSPoint*sp=s->Points.pFirst;sp;sp=sp->Item.pNext){ if(!(sp->flags&TNS_SPOINT_SELECTED)) continue;
  477. tnsShapeSetHole(s,set,set==2); ran=1; break;
  478. }
  479. }
  480. if(ran){
  481. laRecordInstanceDifferences(so,"tns_shape_object"); laPushDifferences("Open/Close shape",TNS_HINT_GEOMETRY);
  482. laNotifyUsers("tns.world");
  483. }
  484. return LA_FINISHED;
  485. }
  486. int OPINV_ReorderShape(laOperator *a, laEvent *e){
  487. laCanvasExtra* ex=a->This->EndInstance; laUiItem* ui=ex->ParentUi;
  488. tnsObject*root=ui?ui->PP.EndInstance:0;
  489. if(!root || !root->Active || root->Active->Type!=TNS_OBJECT_SHAPE) return LA_FINISHED;
  490. tnsShapeObject* so=root->Active; int ran=0;
  491. char* mode=strGetArgumentString(a->ExtraInstructionsP,"direction");
  492. int set=0; if(strSame(mode,"UP")){ set=1; }elif(strSame(mode,"DOWN")){ set=0; }
  493. tnsShape* ns;
  494. for(tnsShape*s=so->Shapes.pFirst;s;s=ns){ ns=s->Item.pNext;
  495. if((!tnsShapePointAnySelected(s))||s->flags&TNS_MESH_FLAG_PICKED) continue;
  496. if(set) lstMoveUp(&so->Shapes,s); else lstMoveDown(&so->Shapes,s); s->flags|=TNS_MESH_FLAG_PICKED; ran=1;
  497. }
  498. if(ran){ tnsShapeClearExtraFlags(so);
  499. laRecordInstanceDifferences(so,"tns_shape_object"); laPushDifferences("Reorder shapes",TNS_HINT_GEOMETRY);
  500. laNotifyUsers("tns.world");
  501. }
  502. return LA_FINISHED;
  503. }
  504. void la_RegisterShapeOperators(){
  505. laPropContainer *pc; laProp *p;
  506. laOperatorType *at; laEnumProp *ep;
  507. at=laCreateOperatorType("M_set_point_handle", "Set Point Handle", "Set handle type of selected points",OPCHK_IsAnyPointSelected,0,0,OPINV_SetPointHandle,OPMOD_FinishOnData,0,0);
  508. at->UiDefine=laui_SetPointHandle;
  509. at=laCreateOperatorType("M_set_shape_closed", "Set Shape Closed", "Set shape closed or open",OPCHK_IsAnyPointSelected,0,0,OPINV_SetShapeClosed,0,0,0);
  510. at=laCreateOperatorType("M_set_shape_hole", "Set Shape Hole", "Set shape as hole or fill",OPCHK_IsAnyPointSelected,0,0,OPINV_SetShapeHole,0,0,0);
  511. at=laCreateOperatorType("M_reorder_shape", "Reorder shape", "Reorder shapes (move up/down in the stack)",OPCHK_IsAnyPointSelected,0,0,OPINV_ReorderShape,0,0,0);
  512. }