*/}}

la_modelling.c 86 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666
  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. extern LA MAIN;
  20. extern struct _tnsMain *T;
  21. void la_ReadGLocation(tnsOffscreen* off, int x, int y,float* xyz0){
  22. glBindFramebuffer(GL_READ_FRAMEBUFFER, off->FboHandle);
  23. glReadBuffer(GL_COLOR_ATTACHMENT2); glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
  24. glReadPixels(x,y,1,1, GL_RGBA, GL_FLOAT, xyz0);
  25. }
  26. int OPINV_SetCursor(laOperator *a, laEvent *e){
  27. if(!a->This || !a->This->EndInstance){ return 0; }
  28. laCanvasExtra* ex=a->This->EndInstance; tnsCamera*c=ex->ViewingCamera; laUiItem* ui=ex->ParentUi;
  29. tnsObject*root=ui?ui->PP.EndInstance:0; if(!root || root->Type!=TNS_OBJECT_ROOT) return 0;
  30. float pos[4]; la_ReadGLocation(ex->OffScr, e->x-ui->L,ui->B-e->y,pos);
  31. if(pos[0]>-1e20){
  32. tnsVectorSet3v(root->GLocation,pos); laNotifyUsers("tns.world"); return LA_FINISHED_PASS;
  33. }else
  34. {
  35. if(!ex->ViewingCamera){ return LA_FINISHED_PASS; }
  36. real vv[4], gp[4]; tnsMatrix44d proj; tnsMatrix44d inv;
  37. real focus=ex->ViewingCamera->FocusDistance, _near=ex->ViewingCamera->ZMin, _far=ex->ViewingCamera->ZMax;
  38. tnsGetCameraViewProjection(proj,ui->R-ui->L,ui->B-ui->U,ex->ViewingCamera); tnsInverse44d(inv,proj);
  39. vv[0]=(real)(e->x-ui->L)/(real)(ui->R-ui->L)*2-1; vv[0]*=focus;
  40. vv[1]=(real)(ui->B-e->y)/(real)(ui->B-ui->U)*2-1; vv[1]*=focus;
  41. vv[2]=tnsGetRatiod(1/_near,1/_far,1/focus)*focus;
  42. vv[3]=focus;
  43. tnsApplyTransform44dTrue(gp, inv, vv);
  44. tnsVectorMultiSelf3d(gp,1/gp[3]);
  45. real vv0[3]={0,0,-1}, vv1[3], ray[3], p0[3]; real t; tnsMatrix44d inv2;
  46. tnsSelfTransformValueChanged(ex->ViewingCamera);tnsInverse44d(inv2,ex->ViewingCamera->Base.GlobalTransform);
  47. tnsApplyRotation43d(vv1,inv2,vv0);
  48. tnsVectorMulti3d(vv0,vv1,focus);
  49. tnsVectorAccum3d(vv0,ex->ViewingCamera->Base.GLocation);
  50. tnsVectorMinus3d(ray, gp, ex->ViewingCamera->Base.GLocation);
  51. tnsNormalizeSelf3d(ray);
  52. if(tnsIntersectPlaneRay(vv1,vv0,ex->ViewingCamera->Base.GLocation,ray,&t)){
  53. tnsVectorMultiSelf3d(ray,t); tnsVectorPlus3d(gp,ray,ex->ViewingCamera->Base.GLocation);
  54. }
  55. tnsVectorSet3v(root->GLocation,gp); laNotifyUsers("tns.world"); return LA_FINISHED_PASS;
  56. }
  57. return LA_FINISHED_PASS;
  58. }
  59. int OPCHK_ThereIsActiveObject(laPropPack *This, laStringSplitor *ss){
  60. if(!This || !This->EndInstance){ return 0; }
  61. laCanvasExtra* ex=This->EndInstance; tnsCamera*c=ex->ViewingCamera; laUiItem* ui=ex->ParentUi;
  62. tnsObject*root=ui?ui->PP.EndInstance:0; if(!root) return 0;
  63. tnsMeshObject* mo=root->Active; if(!mo) return 0; return 1;
  64. }
  65. int OPINV_ToggleEdit(laOperator *a, laEvent *e){
  66. if(!a->This || !a->This->EndInstance){ return 0; }
  67. laCanvasExtra* ex=a->This->EndInstance; tnsCamera*c=ex->ViewingCamera; laUiItem* ui=ex->ParentUi;
  68. tnsObject*root=ui?ui->PP.EndInstance:0; if(!root) return 0;
  69. tnsMeshObject* mo=root->Active; if(!mo) return 0;
  70. if(mo->Base.Type!=TNS_OBJECT_MESH) return LA_CANCELED;
  71. if(mo->Mode==TNS_MESH_EDIT_MODE) tnsMeshLeaveEditMode(mo); else tnsMeshEnterEditMode(mo);
  72. laRecordInstanceDifferences(mo, "tns_mesh_object"); laPushDifferences("Toggle edit mode", TNS_HINT_GEOMETRY);
  73. laNotifyUsers("tns.world");
  74. return LA_FINISHED_PASS;
  75. }
  76. STRUCTURE(MSelectData){
  77. tnsOffscreen* FBO;
  78. tnsTexture* Color;
  79. void** RefsV; int nextV,maxV;
  80. void** RefsE; int nextE,maxE;
  81. };
  82. MSelectData* la_InitSelectData(int w, int h, tnsCamera* camera){
  83. MSelectData* sd=memAcquireSimple(sizeof(MSelectData));
  84. if (!sd->FBO || sd->FBO->pColor[0]->Height != h || sd->FBO->pColor[0]->Width != w){
  85. if (sd->FBO) tnsDelete2DOffscreen(sd->FBO);
  86. sd->FBO = tnsCreate2DOffscreen(GL_RGB, w, h, 0, 1, 0); sd->Color=sd->FBO->pColor[0];
  87. }
  88. tnsDrawToOffscreen(sd->FBO, 1, 0);
  89. return sd;
  90. }
  91. void la_AssignObjectSelectIDRecursive(tnsObject* root, MSelectData* sd){
  92. for(laListItemPointer*lip=root->ChildObjects.pFirst;lip;lip=lip->pNext){
  93. tnsObject* o=lip->p; if(!o) continue;
  94. arrEnsureLength(&sd->RefsV, sd->nextV, &sd->maxV, sizeof(tnsObject*));
  95. sd->RefsV[sd->nextV]=o; o->SelectID=sd->nextV; sd->nextV++;
  96. if(o->ChildObjects.pFirst){ la_AssignObjectSelectIDRecursive(o,sd); }
  97. }
  98. }
  99. void la_PopulateSelectDataObjects(MSelectData* sd, tnsObject* root, tnsCamera* camera){
  100. arrEnsureLength(&sd->RefsV,0,&sd->maxV,sizeof(tnsObject*));
  101. sd->nextV++; // starting from 1;
  102. la_AssignObjectSelectIDRecursive(root, sd);
  103. if(sd->nextV==1) return; int w=sd->Color->Width, h=sd->Color->Height;
  104. tnsUnbindTexture(); tnsUniformUseTexture(T->immShader,0,0); tnsUseMultiplyColor(0);
  105. tnsEnableShaderv(T->SelectionShader);
  106. glDisableVertexAttribArray(T->SelectionShader->iColor); glVertexAttrib4f(T->SelectionShader->iColor,0,0,0,0);
  107. tnsViewportWithScissor(0,0,w,h);tnsResetViewMatrix();tnsResetModelMatrix();tnsResetProjectionMatrix();
  108. tnsApplyCameraView(w,h,camera);
  109. glClearColor(0,0,0,0); glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
  110. glEnable(GL_DEPTH_TEST);
  111. tnsInvalidateEvaluation(root); tnsSetObjectTreeEvaluationArgs(root,root->Active,1,1); tnsEvaluateObjectTree(root,0);
  112. tnsDrawObjectTree(root,TNS_EVAL_LAYER_SELECTION,0);
  113. glDisable(GL_DEPTH_TEST);
  114. tnsEnableShaderv(T->immShader);
  115. }
  116. void la_PopulateSelectVerts(MSelectData* sd, tnsMeshObject* mo){
  117. arrEnsureLength(&sd->RefsV,0,&sd->maxV,sizeof(tnsMVert*));
  118. if(mo->Base.Type!=TNS_OBJECT_MESH||!mo->mv.pFirst){ return; }
  119. for(tnsMVert* v=mo->mv.pFirst;v;v=v->Item.pNext){
  120. arrEnsureLength(&sd->RefsV, v->i, &sd->maxV, sizeof(tnsObject*));
  121. sd->RefsV[v->i]=v; sd->nextV=TNS_MAX2(v->i, sd->nextV);
  122. }
  123. sd->nextV++;
  124. }
  125. void la_PopulateSelectEdges(MSelectData* sd, tnsMeshObject* mo){
  126. arrEnsureLength(&sd->RefsE,0,&sd->maxE,sizeof(tnsMEdge*));
  127. if(mo->Base.Type!=TNS_OBJECT_MESH||!mo->mv.pFirst){ return; }
  128. for(tnsMEdge* e=mo->me.pFirst;e;e=e->Item.pNext){
  129. arrEnsureLength(&sd->RefsE, e->i, &sd->maxE, sizeof(tnsObject*));
  130. sd->RefsE[e->i]=e; sd->nextE=TNS_MAX2(e->i, sd->nextE);
  131. }
  132. sd->nextE++;
  133. }
  134. void la_PopulateSelectDataPrimitives(MSelectData* sd, tnsMeshObject* mo, tnsCamera* camera, int WhatPrim, int SelectThrough){
  135. int DoVerts=(WhatPrim==LA_CANVAS_SELECT_MODE_VERTS),DoEdges=(WhatPrim==LA_CANVAS_SELECT_MODE_EDGES);
  136. int Knife=(WhatPrim==LA_CANVAS_SELECT_MODE_KNIFE);
  137. if(DoVerts || Knife){ la_PopulateSelectVerts(sd,mo); }
  138. if(DoEdges || Knife){ la_PopulateSelectEdges(sd,mo); }
  139. int w=sd->Color->Width, h=sd->Color->Height;
  140. tnsUnbindTexture(); tnsUniformUseTexture(T->immShader,0,0); tnsUseMultiplyColor(0);
  141. tnsEnableShaderv(T->SelectionShader);
  142. tnsViewportWithScissor(0,0,w,h);tnsResetViewMatrix();tnsResetModelMatrix();tnsResetProjectionMatrix();
  143. tnsApplyCameraView(w,h,camera);
  144. glClearColor(0,0,0,0); glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
  145. tnsPushMatrix(); tnsApplyModelMatrix(mo->Base.GlobalTransform);glEnable(GL_DEPTH_TEST);
  146. if(!SelectThrough){
  147. glDepthMask(GL_TRUE); glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
  148. tnsUniformUseOffset(T->SelectionShader,0);
  149. tnsDrawBatch(mo->Batch,"body",0,0);
  150. glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
  151. }
  152. glDepthMask(GL_FALSE);
  153. tnsUniformUseOffset(T->SelectionShader,1);
  154. if(DoEdges || Knife){ tnsDrawBatch(mo->Batch, "edges_select",0,0); }
  155. if(DoVerts || Knife){ tnsDrawBatch(mo->Batch, "verts_select",0,0); }
  156. tnsUniformUseOffset(T->SelectionShader,0);
  157. tnsPopMatrix();
  158. glDisable(GL_DEPTH_TEST);
  159. tnsEnableShaderv(T->immShader);
  160. }
  161. void la_PadSelectionBuffer(uint8_t* buf, int w, int h, int sx, int sy, int ex, int ey, int real_endx){
  162. if(!sx&&!sy&&!ex&&!ey) return;
  163. uint8_t* pad=calloc(1,sizeof(uint8_t)*4*w*h);
  164. for(int i=0;i<h;i++){
  165. if(i<sy || i>=h-ey){ memset(&pad[i*w*4],0,w*4); continue; }
  166. for(int j=0;j<w;j++){
  167. if(j<sx || j>=w-sx){ memset(&pad[(i*w+j)*4],0,4); continue; }
  168. memcpy(&pad[(i*w+j)*4], &buf[((i-sy)*(real_endx-sx)+j-sx)*4], 4);
  169. }
  170. }
  171. memcpy(buf,pad,sizeof(uint8_t)*4*w*h);
  172. free(pad);
  173. }
  174. uint8_t* la_ReadSelection(MSelectData* sd, u8bit* buf, int x, int y, int w, int h){
  175. glFlush(); glFinish(); glGetError();
  176. glBindFramebuffer(GL_READ_FRAMEBUFFER, sd->FBO->FboHandle);
  177. glReadBuffer(GL_COLOR_ATTACHMENT0);
  178. glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
  179. glReadPixels(x,y,w,h, GL_RGBA, GL_UNSIGNED_BYTE, buf);
  180. return buf;
  181. }
  182. uint8_t* la_ReadSelectionRadius(MSelectData* sd, int uix, int uiy, int radius){
  183. int w=radius*2; int vh=sd->Color->Height,vw=sd->Color->Width;
  184. uint8_t* buf=calloc(1,sizeof(uint8_t)*4*w*w);
  185. int startx=uix-radius, starty=vh-uiy-radius, endx=uix+radius, endy=vh-uiy+radius;
  186. TNS_CLAMP(startx,0,vw);TNS_CLAMP(endx,0,vw);TNS_CLAMP(starty,0,vh);TNS_CLAMP(endy,0,vh);
  187. int _startx=TNS_MAX2(startx,0), _starty=TNS_MAX2(starty,0), _endx=TNS_MIN2(endx,vw), _endy=TNS_MIN2(endy,vh);
  188. la_ReadSelection(sd, buf, _startx, _starty, _endx-_startx, _endy-_starty);
  189. la_PadSelectionBuffer(buf, w, w, _startx-startx, _starty-starty, endx-_endx, endy-_endy,_endx);
  190. return buf;
  191. }
  192. uint8_t* la_ReadSelectionBox(MSelectData* sd, int uix, int uiy, int uix2, int uiy2){
  193. int vh=sd->Color->Height,vw=sd->Color->Width;
  194. if(uix2<uix) LA_SWAP(int,uix,uix2); if(uiy2<uiy) LA_SWAP(int,uiy,uiy2);
  195. TNS_CLAMP(uix,0,vw);TNS_CLAMP(uix2,0,vw);TNS_CLAMP(uiy,0,vh);TNS_CLAMP(uiy2,0,vh);
  196. int w=uix2-uix, h=uiy2-uiy;
  197. uint8_t* buf=calloc(1,sizeof(uint8_t)*4*w*h);
  198. int startx=uix, starty=vh-uiy2, endx=uix+w, endy=starty+h;
  199. int _startx=TNS_MAX2(startx,0), _starty=TNS_MAX2(starty,0), _endx=TNS_MIN2(endx,vw), _endy=TNS_MIN2(endy,vh);
  200. la_ReadSelection(sd, buf, _startx, _starty, _endx-_startx, _endy-_starty);
  201. la_PadSelectionBuffer(buf, w, h, _startx-startx, _starty-starty, endx-_endx, endy-_endy,_endx);
  202. return buf;
  203. }
  204. int la_SelectGetClosest(MSelectData* sd, int uix, int uiy, int radius, int *ElemType){
  205. *ElemType=0; uint8_t* buf=la_ReadSelectionRadius(sd, uix, uiy, radius); if(!buf) return 0;
  206. int w=radius*2; int MinD=INT_MAX,MinDe=INT_MAX; int MinID=0,MinIDe=0, d, elemtype=0;
  207. for(int i=0;i<w;i++){
  208. for(int j=0;j<w;j++){
  209. uint8_t* p=&buf[(i*w+j)*4]; int id=(p[0])|(p[1]<<8)|((p[2]<<16)&(~TNS_MMESH_TYPE_BIT)); if(!id){continue;}
  210. d=tnsDistIdv2(i,j, radius, radius); elemtype=((p[2]<<16)&TNS_MMESH_TYPE_BIT);
  211. if(elemtype==TNS_MMESH_EDGE_BIT){ if(d<MinDe){ MinDe=d; MinIDe=id; } }
  212. elif(d<MinD){ MinD=d; MinID=id; }
  213. //printf("%d ",buf[(i*w+j)*4]);
  214. }
  215. //printf("\n");
  216. }
  217. printf("%d %d\n",MinID, MinIDe);
  218. free(buf);
  219. if(MinID && MinIDe){ if(MinD<MinDe*5){ *ElemType=0; return MinID; } }
  220. if(MinIDe){ *ElemType=TNS_MMESH_EDGE_BIT; return MinIDe; }
  221. if(MinID){ *ElemType=0; return MinID; }
  222. *ElemType=0; return 0;
  223. }
  224. int* la_SelectGetBox(MSelectData* sd, int uix, int uiy, int uix2, int uiy2, int* r_length){
  225. uint8_t* buf=la_ReadSelectionBox(sd, uix, uiy, uix2, uiy2); if(!buf) return 0;
  226. int vh=sd->Color->Height,vw=sd->Color->Width;
  227. if(uix2<uix) LA_SWAP(int,uix,uix2); if(uiy2<uiy) LA_SWAP(int,uiy,uiy2);
  228. TNS_CLAMP(uix,0,vw);TNS_CLAMP(uix2,0,vw);TNS_CLAMP(uiy,0,vh);TNS_CLAMP(uiy2,0,vh);
  229. int w=uix2-uix, h=uiy2-uiy;
  230. int* ids=0; int next=0,max=0;
  231. arrEnsureLength(&ids, next, &max, sizeof(int));
  232. for(int i=0;i<h;i++){
  233. for(int j=0;j<w;j++){
  234. uint8_t* p=&buf[(i*w+j)*4]; int id=(p[0])|(p[1]<<8)|((p[2]<<16)&(~TNS_MMESH_TYPE_BIT));
  235. if(id){ int found=0;
  236. for(int a=0;a<next;a++){ if(ids[a]==id){ found=1; break; } }
  237. if(!found){
  238. arrEnsureLength(&ids, next, &max, sizeof(int)); ids[next]=id; next++; }
  239. }
  240. }
  241. }
  242. free(buf);
  243. *r_length=next;
  244. return ids;
  245. }
  246. void la_FreeSelectData(MSelectData* sd){
  247. tnsDelete2DOffscreen(sd->FBO);
  248. free(sd->RefsV);
  249. free(sd->RefsE);
  250. memFree(sd);
  251. }
  252. void* la_SelectGetRef(MSelectData* sd, int id, int elemtype){
  253. if(!elemtype){ if(id>=0 && id<sd->nextV){ return sd->RefsV[id]; } }
  254. elif(elemtype==TNS_MMESH_EDGE_BIT){ if(id>=0 && id<sd->nextE){ return sd->RefsE[id]; } }
  255. return 0;
  256. }
  257. int OPCHK_ViewportAndSceneExists(laPropPack *This, laStringSplitor *ss){
  258. if(!This || !This->EndInstance){ return 0; } laCanvasExtra* ex=This->EndInstance;
  259. laUiItem* ui=ex->ParentUi; tnsObject* root=ui?ui->PP.EndInstance:0;
  260. if(!ex->ViewingCamera || !root){ return 0; }
  261. return 1;
  262. }
  263. void la_DoObjectSelect(tnsObject* root, tnsObject* o, laCanvasExtra* e, int DeselectAll, int Select, int Toggle){
  264. if(DeselectAll){ tnsDeselectAllObjects(root); memAssignRef(root,&root->Active,0); }
  265. if(o){ tnsSelectObject(o, Select, o==root->Active?0:Toggle); memAssignRef(root,&root->Active,o); }
  266. }
  267. void la_DoMeshSelect(tnsMeshObject* mo, void* p, int WhatPrim, int DeselectAll, int Select, int Toggle){
  268. if(DeselectAll){ tnsMMeshDeselectAll(mo); }
  269. if(p){ if(WhatPrim==LA_CANVAS_SELECT_MODE_VERTS) tnsMMeshSelectVert(mo,p,Select,Toggle);
  270. elif(WhatPrim==LA_CANVAS_SELECT_MODE_EDGES) tnsMMeshSelectEdge(mo,p,Select,Toggle); }
  271. }
  272. #define LA_SELECT_MODE_BOX 1
  273. STRUCTURE(MSelectExtra){
  274. MSelectData* sd;
  275. tnsObject* root;
  276. tnsObject* mo;
  277. tnsCamera* cam;
  278. int Mode;
  279. int InSelect;
  280. laListHandle KnifeElements;
  281. void* PendingElem; int PendingElemType, BatchDirty;
  282. int IsLoop;
  283. };
  284. int OPINV_Select(laOperator *a, laEvent *e){
  285. if(!a->This || !a->This->EndInstance){ return 0; }
  286. laCanvasExtra* ex=a->This->EndInstance; tnsCamera*c=ex->ViewingCamera; laUiItem* ui=ex->ParentUi;
  287. tnsObject*root=ui?ui->PP.EndInstance:0; if(!root) return 0;
  288. tnsMeshObject* mo=root->Active;
  289. int is_geo=0, SelectMode=ex->SelectMode, ring_band=0;
  290. if(strSame(strGetArgumentString(a->ExtraInstructionsP, "mode"), "toggle")){
  291. if(mo && mo->Base.Type==TNS_OBJECT_MESH && mo->Mode==TNS_MESH_EDIT_MODE){
  292. if(tnsMMeshAnySelected(mo)) tnsMMeshDeselectAll(mo); else tnsMMeshSelectAll(mo);
  293. tnsInvalidateMeshBatch(mo); is_geo=1;
  294. }else{
  295. if(tnsAnyObjectsSelected(root)) tnsDeselectAllObjects(root); else tnsSelectAllObjects(root);
  296. }
  297. laNotifyUsers("tns.world"); laRecordAndPush(0,"tns.world", "Toggle selection",is_geo?TNS_HINT_GEOMETRY:TNS_HINT_TRANSFORM);
  298. return LA_FINISHED;
  299. }
  300. int spk=e->SpecialKeyBit & (LA_KEY_CTRL|LA_KEY_ALT);
  301. if(spk==LA_KEY_ALT){ ring_band=1; SelectMode=LA_CANVAS_SELECT_MODE_EDGES; }
  302. elif(spk==(LA_KEY_CTRL|LA_KEY_ALT)){ ring_band=2; SelectMode=LA_CANVAS_SELECT_MODE_EDGES; }
  303. MSelectData* sd=la_InitSelectData(ex->OffScr->pColor[0]->Width, ex->OffScr->pColor[0]->Height, c);
  304. int DeselectAll=1;
  305. int Append=e->SpecialKeyBit&LA_KEY_SHIFT; if(Append) DeselectAll=0;
  306. if(mo && mo->Base.Type==TNS_OBJECT_MESH && mo->Mode==TNS_MESH_EDIT_MODE){
  307. la_PopulateSelectDataPrimitives(sd, mo, ex->ViewingCamera, SelectMode, ex->SelectThrough);
  308. if(strSame(strGetArgumentString(a->ExtraInstructionsP, "mode"), "box")){
  309. MSelectExtra* se=memAcquire(sizeof(MSelectExtra));
  310. ex->OnX=e->x; ex->OnX=e->y;
  311. a->CustomData=se; se->sd=sd; se->Mode=LA_SELECT_MODE_BOX; se->mo=mo; se->cam=c; ex->DrawCursor=1; se->root=root; return LA_RUNNING;
  312. }
  313. int elemtype,id=la_SelectGetClosest(sd, e->x-ui->L, e->y-ui->U, LA_RH,&elemtype)-1;
  314. void* p=la_SelectGetRef(sd,id,elemtype);
  315. la_DoMeshSelect(mo, p, SelectMode, DeselectAll, 1, 1); tnsMMeshEnsureSelection(mo,ex->SelectMode);
  316. if(ring_band && p){
  317. tnsMMeshSelectRingBandFrom(mo,p,ring_band,1,Append); tnsMMeshEnsureSelection(mo,ex->SelectMode);
  318. }
  319. tnsInvalidateMeshBatch(mo);
  320. laNotifyUsers("tns.world"); laRecordAndPush(0,"tns.world","Mesh selection",TNS_HINT_GEOMETRY);
  321. }else{
  322. la_PopulateSelectDataObjects(sd,root,ex->ViewingCamera);
  323. if(strSame(strGetArgumentString(a->ExtraInstructionsP, "mode"), "box")){
  324. MSelectExtra* se=memAcquire(sizeof(MSelectExtra));
  325. ex->OnX=e->x; ex->OnX=e->y;
  326. a->CustomData=se; se->sd=sd; se->Mode=LA_SELECT_MODE_BOX; se->cam=c; ex->DrawCursor=1; se->root=root; return LA_RUNNING;
  327. }
  328. int elemtype,id=la_SelectGetClosest(sd, e->x-ui->L, e->y-ui->U, LA_RH*2,&elemtype);
  329. void* p=la_SelectGetRef(sd,id,elemtype); if(p){ la_DoObjectSelect(root, p, ex, DeselectAll, 1, 1); }
  330. else{ la_DoObjectSelect(root, 0, ex, DeselectAll, 1, 1); }
  331. laNotifyUsers("tns.world"); laRecordAndPush(0,"tns.world","Object selection",TNS_HINT_TRANSFORM);
  332. }
  333. la_FreeSelectData(sd);
  334. return LA_FINISHED_PASS;
  335. }
  336. int OPMOD_Select(laOperator *a, laEvent *e){
  337. if(!a->This || !a->This->EndInstance){ return 0; }
  338. laCanvasExtra* ex=a->This->EndInstance; tnsCamera*c=ex->ViewingCamera; laUiItem* ui=ex->ParentUi;
  339. tnsObject*root=ui?ui->PP.EndInstance:0; if(!root) return 0;
  340. tnsMeshObject* mo=root->Active;
  341. MSelectExtra* se=a->CustomData;
  342. if(e->Type==LA_L_MOUSE_DOWN){ se->InSelect=1; ex->DrawCursor=2; ex->ClickedX=e->x; ex->ClickedY=e->y; laRedrawCurrentPanel(); }
  343. if(e->Type&LA_MOUSE_EVENT){ ex->OnX=e->x; ex->OnY=e->y; laRedrawCurrentPanel(); }
  344. if(e->Type==LA_R_MOUSE_DOWN || (e->Type == LA_KEY_DOWN && e->key==LA_KEY_ESCAPE)){
  345. ex->DrawCursor=0; la_FreeSelectData(se->sd); memFree(se); laNotifyUsers("tns.world"); return LA_FINISHED;
  346. }
  347. int DeselectAll=1;
  348. int Append=e->SpecialKeyBit&LA_KEY_SHIFT; if(Append) DeselectAll=0;
  349. int Remove=e->SpecialKeyBit&LA_KEY_ALT; if(Remove) DeselectAll=0;
  350. int is_geo=0;
  351. if(se->InSelect && e->Type==LA_L_MOUSE_UP){
  352. if(mo && mo->Base.Type==TNS_OBJECT_MESH && mo->Mode==TNS_MESH_EDIT_MODE){
  353. la_DoMeshSelect(mo, 0, ex->SelectMode, DeselectAll, 0, 0);
  354. int len; int* ids=la_SelectGetBox(se->sd, ex->ClickedX-ui->L, ex->ClickedY-ui->U, e->x-ui->L, e->y-ui->U, &len);
  355. for(int i=0;i<len;i++){
  356. int id=ids[i]-1; void* p=la_SelectGetRef(se->sd,id,ex->SelectMode==LA_CANVAS_SELECT_MODE_EDGES?TNS_MMESH_EDGE_BIT:0);
  357. la_DoMeshSelect(mo, p, ex->SelectMode, 0, !Remove, 0);
  358. }
  359. tnsMMeshEnsureSelection(mo,ex->SelectMode);
  360. tnsInvalidateMeshBatch(mo); is_geo=1;
  361. }else{
  362. la_DoObjectSelect(se->root, 0, ex, DeselectAll, 0, 0);
  363. int len; int* ids=la_SelectGetBox(se->sd, ex->ClickedX, ex->ClickedY, e->x-ui->L, e->y-ui->U, &len);
  364. for(int i=0;i<len;i++){
  365. int id=ids[i]; void* p=la_SelectGetRef(se->sd,id,0);
  366. if(p){ la_DoObjectSelect(se->root, p, ex, 0, !Remove, 0); }
  367. }
  368. }
  369. laNotifyUsers("tns.world"); laRecordAndPush(0,"tns.world","Box selection",is_geo?TNS_HINT_GEOMETRY:TNS_HINT_TRANSFORM);
  370. ex->DrawCursor=0;
  371. la_FreeSelectData(se->sd); memFree(se);
  372. laRedrawCurrentPanel();
  373. return LA_FINISHED;
  374. }
  375. return LA_RUNNING;
  376. }
  377. #define LA_TRANSFORM_MODE_GRAB 1
  378. #define LA_TRANSFORM_MODE_ROTATE 2
  379. #define LA_TRANSFORM_MODE_SCALE 3
  380. #define LA_TRANSFORM_RESTORE_LOC 1
  381. #define LA_TRANSFORM_RESTORE_ROT 2
  382. #define LA_TRANSFORM_RESTORE_SCA 3
  383. STRUCTURE(MTOrigObject){
  384. tnsObject* o;
  385. tnsMatrix44d Global;
  386. tnsMatrix44d Local;
  387. int Discard;
  388. };
  389. STRUCTURE(MTOrigMVert){
  390. tnsVector3d p;
  391. tnsVector3d origp;
  392. tnsMVert* mv;
  393. };
  394. STRUCTURE(MTransformData){
  395. tnsMatrix44d Delta;
  396. tnsMatrix44d ViewProjection;
  397. tnsVector4d Up,Right,Foward;
  398. tnsVector4d TCenter;
  399. int CenterX,CenterY; real Initial;
  400. tnsObject* mo; tnsMatrix44d obmatinv,deltainv;
  401. tnsCamera* c; tnsObject* root;
  402. int w,h;
  403. void* Originals; int next,max;
  404. int mode;
  405. int LockAxis[3];
  406. int UseLocal;
  407. real DeltaVal, UserDeltaVal;
  408. laStringEdit* Entry; int UseUserDelta;
  409. int CanvasDeltaMode;
  410. };
  411. MTransformData* la_InitTransformData(int w, int h, tnsCamera* c, int CanvasDeltaMode){
  412. MTransformData* td=memAcquireSimple(sizeof(MTransformData));
  413. tnsVector4d pu={0,1,0,0}, pr={1,0,0,0}, pf={0,0,1};
  414. tnsGetCameraMovingDeltas(c,w,h,1,0,pr); pr[2]=0; pr[3]=0;
  415. tnsGetCameraMovingDeltas(c,w,h,0,-1,pu); pu[2]=0; pu[3]=0;
  416. tnsMatrix44d inv; tnsInverse44d(inv,c->Base.GlobalTransform);
  417. tnsApplyRotation43d(td->Up,inv,pu);
  418. tnsApplyRotation43d(td->Right,inv,pr);
  419. tnsApplyRotation43d(td->Foward,inv,pf);
  420. tnsGetCameraViewProjection(td->ViewProjection, w,h,c);
  421. td->c=c; td->w=w; td->h=h; td->CanvasDeltaMode=CanvasDeltaMode;
  422. strBeginEdit(&td->Entry, "");
  423. return td;
  424. }
  425. void la_GetTransformInitialScale(MTransformData* td, laUiItem* ui, int x, int y){ td->Initial=tnsDistIdv2(x-ui->L,y-ui->U,td->CenterX,td->CenterY); }
  426. void la_GetTransformInitialRotation(MTransformData* td, laUiItem* ui, int x, int y){ td->Initial=atan2(y-ui->U-td->CenterY,x-ui->L-td->CenterX); }
  427. void la_GetTransformCenter2D(MTransformData* td){
  428. tnsVector4d vp; tnsApplyTransform44d(vp,td->ViewProjection,td->TCenter);
  429. if(td->c->CameraType==TNS_CAMERA_PERSP){ tnsVectorMultiSelf3d(vp, 1/vp[3]); }
  430. td->CenterX = (vp[0]/2+0.5f)*td->w; td->CenterY=(-vp[1]/2+0.5f)*td->h;
  431. if(td->CenterX<0||td->CenterY<0) { td->CenterX=td->w/2; td->CenterY=td->h/2; }
  432. }
  433. int la_AddTransformObjectsRecursive(MTransformData* td, tnsObject*root){
  434. int any=0; for(laListItemPointer* lip=root->ChildObjects.pFirst;lip;lip=lip->pNext){
  435. tnsObject* o=lip->p; if(o->ChildObjects.pFirst) any+=la_AddTransformObjectsRecursive(td,o);
  436. if(!(o->Flags&TNS_OBJECT_FLAGS_SELECTED)) continue;
  437. arrEnsureLength(&td->Originals, td->next, &td->max, sizeof(MTOrigObject));
  438. MTOrigObject* to=arrElement(td->Originals, td->next, sizeof(MTOrigObject)); td->next++; to->o=o;
  439. memcpy(to->Global, o->GlobalTransform, sizeof(tnsMatrix44d));
  440. memcpy(to->Local, o->SelfTransform, sizeof(tnsMatrix44d));
  441. tnsVectorAccum3d(td->TCenter,o->GLocation); any++;
  442. int discard=0; tnsObject* po=o; while(po=po->ParentObject){ if(po->Flags&TNS_OBJECT_FLAGS_SELECTED){ discard=1; break;} } if(discard) to->Discard=1;
  443. }
  444. return any;
  445. }
  446. int la_PopulateTransformObjects(MTransformData* td, tnsObject* root){
  447. arrEnsureLength(&td->Originals, 0, &td->max, sizeof(MTOrigObject));
  448. int any=la_AddTransformObjectsRecursive(td,root);
  449. tnsVectorMultiSelf3d(td->TCenter, 1.0f/any);
  450. la_GetTransformCenter2D(td);
  451. return any;
  452. }
  453. int la_PopulateTransformVerticies(MTransformData* td, tnsMeshObject* mo){
  454. int any=0; td->mo=mo;
  455. arrEnsureLength(&td->Originals, 0, &td->max, sizeof(MTOrigMVert));
  456. tnsInverse44d(td->obmatinv, mo->Base.GlobalTransform);
  457. tnsInverse44d(td->deltainv, mo->Base.DeltaTransform);
  458. for(tnsMVert* mv=mo->mv.pFirst;mv;mv=mv->Item.pNext){
  459. if(!(mv->flags&TNS_MESH_FLAG_SELECTED)) continue;
  460. //printf("v %d ",mv->i);
  461. arrEnsureLength(&td->Originals, td->next, &td->max, sizeof(MTOrigMVert));
  462. MTOrigMVert* to=arrElement(td->Originals, td->next, sizeof(MTOrigMVert)); td->next++; to->mv=mv;
  463. tnsApplyTransform43d(to->p, mo->Base.GlobalTransform, mv->p);
  464. memcpy(to->origp, mv->p, sizeof(tnsVector3d)); any++;
  465. tnsVectorAccum3d(td->TCenter,to->p);
  466. }
  467. //printf(" [totmv %d]\n",mo->totmv);
  468. tnsVectorMultiSelf3d(td->TCenter, 1.0f/any);
  469. la_GetTransformCenter2D(td);
  470. return any;
  471. }
  472. void la_ApplyTranslation(MTransformData* td, int x, int y){
  473. tnsMatrix44d trans; tnsVector3d deltay,delta; tnsVector3d gp;
  474. tnsVectorMulti3d(delta, td->Right, x); tnsVectorMulti3d(deltay, td->Up, y); tnsVectorAccum3d(delta, deltay);
  475. tnsVector3d use_delta={LA_COLOR3(delta)}; real len;
  476. if(td->LockAxis[0]||td->LockAxis[1]||td->LockAxis[2]){ len=tnsLength3d(delta); }
  477. if(td->LockAxis[0]>0){ use_delta[1]=use_delta[2]=0; real l=fabs(use_delta[0]); use_delta[0]=l?use_delta[0]*len/l:1e-7; }
  478. if(td->LockAxis[1]>0){ use_delta[0]=use_delta[2]=0; real l=fabs(use_delta[1]); use_delta[1]=l?use_delta[1]*len/l:1e-7; }
  479. if(td->LockAxis[2]>0){ use_delta[0]=use_delta[1]=0; real l=fabs(use_delta[2]); use_delta[2]=l?use_delta[2]*len/l:1e-7; }
  480. if(td->LockAxis[0]<0){ use_delta[0]=0; real l=tnsLength3d(use_delta); tnsVectorMultiSelf3d(use_delta, l?len/l*len/l:0); }
  481. if(td->LockAxis[1]<0){ use_delta[1]=0; real l=tnsLength3d(use_delta); tnsVectorMultiSelf3d(use_delta, l?len/l*len/l:0); }
  482. if(td->LockAxis[2]<0){ use_delta[2]=0; real l=tnsLength3d(use_delta); tnsVectorMultiSelf3d(use_delta, l?len/l*len/l:0); }
  483. td->DeltaVal=tnsLength3d(use_delta);
  484. if(td->UseUserDelta){
  485. tnsVectorMultiSelf3d(use_delta,1/tnsLength3d(use_delta)*td->UserDeltaVal);
  486. tnsVector3d lock={ td->LockAxis[0], td->LockAxis[1], td->LockAxis[2] };
  487. real dir=tnsDot3d(use_delta, lock, 0); tnsVectorMultiSelf3d(use_delta,(td->UserDeltaVal*dir<=0)?-1:1);
  488. td->DeltaVal=td->UserDeltaVal;
  489. }
  490. if(!td->mo){
  491. for(int i=0;i<td->next;i++){
  492. MTOrigObject* to=arrElement(td->Originals, i, sizeof(MTOrigObject)); memcpy(to->o->GlobalTransform, to->Global,sizeof(tnsMatrix44d));
  493. if(to->Discard){ tnsSelfMatrixChanged(to->o,1); continue; }
  494. if(td->CanvasDeltaMode) tnsGlobalMatrixChangedForDelta(to->o, 0); else tnsGlobalMatrixChanged(to->o, 0);
  495. if(td->UseLocal){
  496. if(td->CanvasDeltaMode) tnsMoveObjectDelta(to->o, LA_COLOR3(use_delta));
  497. else tnsMoveObjectLocal(to->o, LA_COLOR3(use_delta));
  498. }else{
  499. if(td->CanvasDeltaMode) tnsMoveObjectGlobalForDelta(to->o, LA_COLOR3(use_delta));
  500. else tnsMoveObjectGlobal(to->o, LA_COLOR3(use_delta));
  501. }
  502. }
  503. }else{
  504. tnsMakeTranslationMatrix44d(trans, LA_COLOR3(use_delta)); tnsMatrix44d final;
  505. if(!td->UseLocal) tnsMultiply44d(final,td->obmatinv,trans);
  506. else tnsMultiply44d(final,trans,td->obmatinv);
  507. for(int i=0;i<td->next;i++){ MTOrigMVert* to=arrElement(td->Originals, i, sizeof(MTOrigMVert));
  508. tnsApplyTransform43d(to->mv->p, final, to->p);
  509. }
  510. tnsInvalidateMeshBatch(td->mo); tnsMMeshCalculateNormal(td->mo);
  511. }
  512. }
  513. void la_ApplyScale(MTransformData* td, int uix, int uiy){
  514. tnsMatrix44d trans; real d=tnsDistIdv2(uix,uiy,td->CenterX,td->CenterY); if(!td->Initial){ td->Initial=100; }
  515. real s=d/td->Initial; tnsVector3d gp;
  516. td->DeltaVal=s; if(td->UseUserDelta) td->DeltaVal=s=td->UserDeltaVal;
  517. if(!td->mo){
  518. for(int i=0;i<td->next;i++){
  519. MTOrigObject* to=arrElement(td->Originals, i, sizeof(MTOrigObject)); memcpy(to->o->GlobalTransform, to->Global,sizeof(tnsMatrix44d));
  520. if(to->Discard){ tnsSelfMatrixChanged(to->o,1); continue; }
  521. if(td->CanvasDeltaMode) tnsGlobalMatrixChangedForDelta(to->o, 0); else tnsGlobalMatrixChanged(to->o, 0);
  522. if(td->CanvasDeltaMode) tnsScaleObjectDelta(to->o,s,LA_COLOR3(td->TCenter));
  523. else tnsScaleObject(to->o, s, LA_COLOR3(td->TCenter));
  524. }
  525. }else{
  526. tnsVector3d use_delta={s,s,s};
  527. if(td->LockAxis[0]>0){ use_delta[1]=use_delta[2]=1;}
  528. if(td->LockAxis[1]>0){ use_delta[0]=use_delta[2]=1;}
  529. if(td->LockAxis[2]>0){ use_delta[0]=use_delta[1]=1;}
  530. if(td->LockAxis[0]<0){ use_delta[0]=1; }
  531. if(td->LockAxis[1]<0){ use_delta[1]=1; }
  532. if(td->LockAxis[2]<0){ use_delta[2]=1; }
  533. tnsMakeScaleMatrix44d(trans,LA_COLOR3(use_delta));
  534. tnsMatrix44d t1,t2,t3; tnsMakeTranslationMatrix44d(t1,LA_COLOR3(td->TCenter)); tnsInverse44d(t2,t1);
  535. tnsMatrix44d final; tnsMultiply44d(t3,t1,trans); tnsMultiply44d(t1,t3,t2);
  536. if(!td->UseLocal) tnsMultiply44d(final,td->obmatinv,t1);
  537. else tnsMultiply44d(final,t1,td->obmatinv);
  538. for(int i=0;i<td->next;i++){ MTOrigMVert* to=arrElement(td->Originals, i, sizeof(MTOrigMVert));
  539. tnsApplyTransform43d(to->mv->p, final, to->p);
  540. }
  541. tnsInvalidateMeshBatch(td->mo); tnsMMeshCalculateNormal(td->mo);
  542. }
  543. }
  544. void la_ApplyRotation(MTransformData* td, int uix, int uiy){
  545. tnsMatrix44d trans; real a=atan2(uiy-td->CenterY,uix-td->CenterX);
  546. real angle=a-td->Initial; tnsVector3d gp; tnsVector3d LimFoward={0}; real* use_forward=td->Foward;
  547. if(td->LockAxis[0]||td->LockAxis[1]||td->LockAxis[2]){ use_forward=LimFoward; }
  548. if(td->LockAxis[0]){ LimFoward[0]=1; }
  549. if(td->LockAxis[1]){ LimFoward[1]=1; }
  550. if(td->LockAxis[2]){ LimFoward[2]=1; }
  551. if(td->UseUserDelta) angle=rad(td->UserDeltaVal); td->DeltaVal=deg(angle);
  552. if(!td->mo){
  553. for(int i=0;i<td->next;i++){
  554. MTOrigObject* to=arrElement(td->Originals, i, sizeof(MTOrigObject)); memcpy(to->o->GlobalTransform, to->Global,sizeof(tnsMatrix44d));
  555. if(to->Discard){ tnsSelfMatrixChanged(to->o,1); continue; }
  556. if(td->CanvasDeltaMode) tnsGlobalMatrixChangedForDelta(to->o, 0); else tnsGlobalMatrixChanged(to->o, 0);
  557. if(td->UseLocal){
  558. if(td->CanvasDeltaMode) tnsRotateObjectDelta(to->o,LA_COLOR3(use_forward),angle,LA_COLOR3(td->TCenter));
  559. else tnsRotateObjectLocal(to->o,LA_COLOR3(use_forward),angle,LA_COLOR3(td->TCenter));
  560. }else{
  561. if(td->CanvasDeltaMode) tnsRotateObjectGlobalForDelta(to->o,LA_COLOR3(use_forward),angle,LA_COLOR3(td->TCenter));
  562. else tnsRotateObjectGlobal(to->o,LA_COLOR3(use_forward),angle,LA_COLOR3(td->TCenter));
  563. }
  564. }
  565. }else{
  566. tnsMakeRotationMatrix44d(trans, angle, LA_COLOR3(use_forward));
  567. tnsMatrix44d t1,t2,t3; tnsMakeTranslationMatrix44d(t1,LA_COLOR3(td->TCenter)); tnsInverse44d(t2,t1);
  568. tnsMatrix44d final; tnsMultiply44d(t3,t1,trans); tnsMultiply44d(t1,t3,t2);
  569. if(!td->UseLocal) tnsMultiply44d(final,td->obmatinv,t1);
  570. else tnsMultiply44d(final,t1,td->obmatinv);
  571. for(int i=0;i<td->next;i++){ MTOrigMVert* to=arrElement(td->Originals, i, sizeof(MTOrigMVert));
  572. tnsApplyTransform43d(to->mv->p, final, to->p);
  573. }
  574. tnsInvalidateMeshBatch(td->mo); tnsMMeshCalculateNormal(td->mo);
  575. }
  576. }
  577. void la_CancelTransformObjects(MTransformData* td){
  578. if(!td->mo){
  579. for(int i=0;i<td->next;i++){ MTOrigObject* to=arrElement(td->Originals, i, sizeof(MTOrigObject));
  580. if(to->Discard){ tnsSelfMatrixChanged(to->o,1); continue; }
  581. memcpy(to->o->GlobalTransform, to->Global,sizeof(tnsMatrix44d));
  582. if(td->CanvasDeltaMode) tnsGlobalMatrixChangedForDelta(to->o, 1);
  583. else tnsGlobalMatrixChanged(to->o, 1);
  584. }
  585. }else{
  586. for(int i=0;i<td->next;i++){ MTOrigMVert* to=arrElement(td->Originals, i, sizeof(MTOrigMVert)); tnsVectorCopy3d(to->origp,to->mv->p); }
  587. tnsInvalidateMeshBatch(td->mo);
  588. }
  589. }
  590. void la_RecordTransformDifferences(MTransformData* td){
  591. if(!td->mo){
  592. for(int i=0;i<td->next;i++){ MTOrigObject* to=arrElement(td->Originals, i, sizeof(MTOrigObject));
  593. laRecordInstanceDifferences(to->o, "tns_object");
  594. } laPushDifferences(td->mode==LA_TRANSFORM_MODE_GRAB?"Moved objects":td->mode==LA_TRANSFORM_MODE_ROTATE?"Rotated objects":"Scaled objects", TNS_HINT_TRANSFORM);
  595. }else{
  596. laRecordInstanceDifferences(td->mo, "tns_mesh_object");
  597. laPushDifferences(td->mode==LA_TRANSFORM_MODE_GRAB?"Moved primitives":td->mode==LA_TRANSFORM_MODE_ROTATE?"Rotated primitives":"Scaled primitives", TNS_HINT_GEOMETRY);
  598. tnsInvalidateMeshBatch(td->mo);
  599. }
  600. }
  601. void la_FreeTransformData(MTransformData* td){
  602. free(td->Originals);
  603. strEndEdit(&td->Entry, 1);
  604. memFree(td);
  605. }
  606. void la_MakeTransformOperatorHint(laOperator* a, MTransformData* td){
  607. strSafeDestroy(&a->RuntimeHint);
  608. strSafePrint(&a->RuntimeHint, "%s ",
  609. td->mode==LA_TRANSFORM_MODE_GRAB?"Grab":td->mode==LA_TRANSFORM_MODE_ROTATE?"Rotate":td->mode==LA_TRANSFORM_MODE_SCALE?"Scale":"");
  610. char* entry=strGetEditString(td->Entry,0);
  611. strSafePrint(&a->RuntimeHint, "Delta: %.3lf [🔢 %s] 🆇🆈🆉 Lock axis: %s 🈳 %s ", td->DeltaVal, (entry&&entry[0])?entry:"Type...",
  612. td->LockAxis[0]?"X":td->LockAxis[1]?"Y":td->LockAxis[2]?"Z":"None",
  613. td->UseLocal?"Global/[Local]":"[Global]/Local");
  614. free(entry);
  615. if(td->mode==LA_TRANSFORM_MODE_GRAB){ strSafePrint(&a->RuntimeHint, "🡅🆇🆈🆉 Reverse: %s ",
  616. (td->LockAxis[0]<0||td->LockAxis[1]<0||td->LockAxis[2]<0)?"Yes":"No"); }
  617. if(td->mode!=LA_TRANSFORM_MODE_GRAB){ strSafePrint(&a->RuntimeHint,"🅶 Grab "); }
  618. if(td->mode!=LA_TRANSFORM_MODE_SCALE){ strSafePrint(&a->RuntimeHint,"🆂 Scale "); }
  619. if(td->mode!=LA_TRANSFORM_MODE_ROTATE){ strSafePrint(&a->RuntimeHint,"🆁 Rotate "); }
  620. }
  621. void la_RestoreTransform(tnsObject* ob, int restore_type, int restore_delta){
  622. if(restore_delta){
  623. if(restore_type==LA_TRANSFORM_RESTORE_LOC){ tnsVectorSet3(ob->DLocation,0,0,0); }
  624. elif(restore_type==LA_TRANSFORM_RESTORE_ROT){ tnsVectorSet3(ob->DRotation,0,0,0); }
  625. elif(restore_type==LA_TRANSFORM_RESTORE_SCA){ ob->DScale=1; }
  626. tnsDeltaTransformValueChanged(ob);
  627. }else{
  628. if(restore_type==LA_TRANSFORM_RESTORE_LOC){ tnsVectorSet3(ob->Location,0,0,0); }
  629. elif(restore_type==LA_TRANSFORM_RESTORE_ROT){ tnsVectorSet3(ob->Rotation,0,0,0); }
  630. elif(restore_type==LA_TRANSFORM_RESTORE_SCA){ ob->Scale=1; }
  631. tnsSelfTransformValueChanged(ob);
  632. }
  633. }
  634. int la_InitTransform(laOperator* a, laEvent* e, int mode, int restore_type, int restore_delta){
  635. if(!a->This || !a->This->EndInstance){ return 0; }
  636. laCanvasExtra* ex=a->This->EndInstance; tnsCamera*c=ex->ViewingCamera; laUiItem* ui=ex->ParentUi;
  637. tnsObject*root=ui?ui->PP.EndInstance:0; if(!root) return 0;
  638. tnsMeshObject* mo=root->Active;
  639. MTransformData* td=la_InitTransformData(ex->OffScr->pColor[0]->Width, ex->OffScr->pColor[0]->Height, c, ex->DeltaMode);
  640. a->CustomData = td;
  641. td->mode=mode;
  642. td->root=root;
  643. int ret=0;
  644. if(mo && mo->Base.Type==TNS_OBJECT_MESH && mo->Mode==TNS_MESH_EDIT_MODE){
  645. if(la_PopulateTransformVerticies(td, mo)){ ex->ClickedX=e->x; ex->ClickedY=e->y; ret=1; }
  646. }else{
  647. if(la_PopulateTransformObjects(td,root)){ ex->ClickedX=e->x; ex->ClickedY=e->y; ret=1; }
  648. if(ret && restore_type){
  649. for(int i=0;i<td->next;i++){ MTOrigObject* ob=arrElement(td->Originals, i, sizeof(MTOrigObject));
  650. la_RestoreTransform(ob->o,restore_type,restore_delta);
  651. }
  652. la_RecordTransformDifferences(td); laNotifyUsers("tns.world"); la_FreeTransformData(td);
  653. return 0;
  654. }
  655. }
  656. if(ret){
  657. if(mode==LA_TRANSFORM_MODE_SCALE){ la_GetTransformInitialScale(td,ui,e->x,e->y); ex->DrawCursor=LA_CANVAS_CURSOR_ARROW; }
  658. elif(mode==LA_TRANSFORM_MODE_ROTATE){ la_GetTransformInitialRotation(td,ui,e->x,e->y); ex->DrawCursor=LA_CANVAS_CURSOR_ARROW; }
  659. ex->TargetX=td->CenterX+ui->L; ex->TargetY=td->CenterY+ui->U; ex->OnX=e->x; ex->OnY=e->y;
  660. la_MakeTransformOperatorHint(a, td);
  661. laNotifyUsers("tns.world"); return 1;
  662. }
  663. return 0;
  664. }
  665. int OPINV_Grab(laOperator *a, laEvent *e){
  666. if(la_InitTransform(a, e, LA_TRANSFORM_MODE_GRAB,0,0)) return LA_RUNNING; return LA_FINISHED_PASS;
  667. }
  668. int OPINV_Scale(laOperator *a, laEvent *e){
  669. if(la_InitTransform(a, e, LA_TRANSFORM_MODE_SCALE,0,0)) return LA_RUNNING; return LA_FINISHED_PASS;
  670. }
  671. int OPINV_Rotate(laOperator *a, laEvent *e){
  672. if(la_InitTransform(a, e, LA_TRANSFORM_MODE_ROTATE,0,0)) return LA_RUNNING; return LA_FINISHED_PASS;
  673. }
  674. int OPMOD_Transformation(laOperator *a, laEvent *e){
  675. if(!a->This || !a->This->EndInstance){ return 0; }
  676. laCanvasExtra* ex=a->This->EndInstance; tnsCamera*c=ex->ViewingCamera; laUiItem* ui=ex->ParentUi;
  677. tnsObject*root=ui?ui->PP.EndInstance:0; if(!root) return 0;
  678. tnsMeshObject* mo=root->Active;
  679. MTransformData* td=a->CustomData;
  680. if (e->Input=='x'||e->Input=='y'||e->Input=='z'||e->Input=='g'||e->Input=='s'||e->Input=='r'||
  681. e->Input=='X'||e->Input=='Y'||e->Input=='Z'||e->Input==' '){ /*pass*/ }
  682. else{ la_ProcessTextEdit(e, td->Entry, 0); }
  683. char* entered;
  684. if(entered=strGetEditString(td->Entry,0)){ int status;
  685. if((status=sscanf(entered,"%lf",&td->UserDeltaVal)) && status!=EOF) td->UseUserDelta=1; else td->UseUserDelta=0;
  686. td->UserDeltaVal=fabs(td->UserDeltaVal); for(char*pc=entered;*pc;pc++){ if(*pc=='-') td->UserDeltaVal=-td->UserDeltaVal; } free(entered);
  687. }
  688. if(e->Type==LA_KEY_DOWN){
  689. int Other=1; if(e->SpecialKeyBit&LA_KEY_SHIFT){ Other=-1; }
  690. if(e->key=='x'){ td->LockAxis[0]=Other*((Other<0&&td->LockAxis[0])?td->LockAxis[0]:!td->LockAxis[0]); td->LockAxis[1]=td->LockAxis[2]=0; }
  691. if(e->key=='y'){ td->LockAxis[1]=Other*((Other<0&&td->LockAxis[1])?td->LockAxis[1]:!td->LockAxis[1]); td->LockAxis[0]=td->LockAxis[2]=0; }
  692. if(e->key=='z'){ td->LockAxis[2]=Other*((Other<0&&td->LockAxis[2])?td->LockAxis[2]:!td->LockAxis[2]); td->LockAxis[0]=td->LockAxis[1]=0; }
  693. if(e->key=='g' && td->mode!=LA_TRANSFORM_MODE_GRAB){ td->mode=LA_TRANSFORM_MODE_GRAB; ex->DrawCursor=0; }
  694. if(e->key=='s' && td->mode!=LA_TRANSFORM_MODE_SCALE){ td->mode=LA_TRANSFORM_MODE_SCALE; la_GetTransformInitialScale(td,ui,e->x,e->y);ex->DrawCursor=LA_CANVAS_CURSOR_ARROW; }
  695. if(e->key=='r' && td->mode!=LA_TRANSFORM_MODE_ROTATE){ td->mode=LA_TRANSFORM_MODE_ROTATE; la_GetTransformInitialRotation(td,ui,e->x,e->y);ex->DrawCursor=LA_CANVAS_CURSOR_ARROW; }
  696. if(e->key==' '){ td->UseLocal=!td->UseLocal; }
  697. }
  698. if(e->Type==LA_MOUSEMOVE || e->Type==LA_KEY_DOWN){
  699. switch(td->mode){
  700. case LA_TRANSFORM_MODE_GRAB: la_ApplyTranslation(td,e->x-ex->ClickedX, e->y-ex->ClickedY); break;
  701. case LA_TRANSFORM_MODE_SCALE: la_ApplyScale(td,e->x-ui->L, e->y-ui->U); break;
  702. case LA_TRANSFORM_MODE_ROTATE: la_ApplyRotation(td,e->x-ui->L, e->y-ui->U); break;
  703. default: break;
  704. }
  705. ex->OnX=e->x; ex->OnY=e->y;
  706. laNotifyUsers("tns.world");
  707. }
  708. if(e->Type==LA_L_MOUSE_DOWN || (e->Type==LA_KEY_DOWN && e->key==LA_KEY_ENTER)){ ex->DrawCursor=0;
  709. la_RecordTransformDifferences(td);
  710. laNotifyUsers("tns.world"); la_FreeTransformData(td); return LA_FINISHED;
  711. }
  712. if(e->Type==LA_R_MOUSE_DOWN || e->Type==LA_ESCAPE_DOWN){ ex->DrawCursor=0;
  713. la_CancelTransformObjects(td); laNotifyUsers("tns.world"); la_FreeTransformData(td); return LA_FINISHED;
  714. }
  715. la_MakeTransformOperatorHint(a, td);
  716. return LA_RUNNING;
  717. }
  718. int OPINV_ClearTransformation(laOperator *a, laEvent *e){
  719. laCanvasExtra* ex=a->This->EndInstance; int restore=0;
  720. char* channel=strGetArgumentString(a->ExtraInstructionsP,"channel");
  721. if(channel){
  722. if(channel[0]=='L' || channel[0]=='l'){ restore=LA_TRANSFORM_RESTORE_LOC; }
  723. if(channel[0]=='R' || channel[0]=='r'){ restore=LA_TRANSFORM_RESTORE_ROT; }
  724. if(channel[0]=='S' || channel[0]=='s'){ restore=LA_TRANSFORM_RESTORE_SCA; }
  725. }else{
  726. laEnableOperatorPanel(a,a->This,e->x,e->y,150,200,0,0,0,0,0,0,0,0,e); return LA_RUNNING;
  727. }
  728. char* dt=strGetArgumentString(a->ExtraInstructionsP,"delta");
  729. int delta=dt?strSame(dt,"true"):ex->DeltaMode;
  730. la_InitTransform(a,e,0,restore,delta);
  731. return LA_FINISHED;
  732. }
  733. void laui_ClearTransformation(laUiList *uil, laPropPack *pp, laPropPack *actinst, laColumn *extracol, int context){
  734. laColumn* c=laFirstColumn(uil), *cl,*cr; laSplitColumn(uil,c,0.6); cl=laLeftColumn(c,0); cr=laRightColumn(c,0);
  735. laShowItemFull(uil,cl,pp,"_this_M_clear_transformations",0,"channel=loc;text=Location",0,0);
  736. laShowItemFull(uil,cl,pp,"_this_M_clear_transformations",0,"channel=rot;text=Rotation",0,0);
  737. laShowItemFull(uil,cl,pp,"_this_M_clear_transformations",0,"channel=sca;text=Scale",0,0);
  738. laShowItemFull(uil,cr,pp,"_this_M_clear_transformations",0,"channel=loc;text=Delta;delta=true",0,0);
  739. laShowItemFull(uil,cr,pp,"_this_M_clear_transformations",0,"channel=rot;text=Delta;delta=true",0,0);
  740. laShowItemFull(uil,cr,pp,"_this_M_clear_transformations",0,"channel=sca;text=Delta;delta=true",0,0);
  741. }
  742. int la_ParentableRecursive(tnsObject* root, tnsObject* parent){
  743. for(laListItemPointer* lip=root->ChildObjects.pFirst;lip;lip=lip->pNext){
  744. tnsObject* o=lip->p; if((!o) || (!(o->Flags&TNS_OBJECT_FLAGS_SELECTED)) || (o==parent)) continue;
  745. if(!tnsCheckParentable(o,parent)) return 0;
  746. if(!la_ParentableRecursive(o,parent)) return 0;
  747. }return 1;
  748. }
  749. void la_MakeParentExecuteRecursive(tnsObject* root, tnsObject* parent, int Unparent, int KeepTransform){
  750. laListItemPointer* NextLip;
  751. for(laListItemPointer* lip=root->ChildObjects.pFirst;lip;lip=NextLip){ NextLip=lip->pNext;
  752. tnsObject* o=lip->p; if((!o) || (!(o->Flags&TNS_OBJECT_FLAGS_SELECTED)) || (o==parent)) continue;
  753. if(Unparent) tnsUnparentObject(o, KeepTransform);
  754. else tnsParentObject(o, parent, KeepTransform);
  755. la_MakeParentExecuteRecursive(o,parent,Unparent,KeepTransform);
  756. }
  757. laNotifyUsers("tns.world");
  758. }
  759. int OPINV_MakeParent(laOperator *a, laEvent *e){
  760. if(!a->This || !a->This->EndInstance){ return 0; }
  761. laCanvasExtra* ex=a->This->EndInstance; tnsCamera*c=ex->ViewingCamera; laUiItem* ui=ex->ParentUi;
  762. tnsObject*root=ui?ui->PP.EndInstance:0; if(!root) return 0;
  763. tnsObject* mo=root->Active;
  764. int Unparent=0,KeepTransform=1;
  765. char* action=strGetArgumentString(a->ExtraInstructionsP,"action");
  766. char* keep=strGetArgumentString(a->ExtraInstructionsP,"keep_transform");
  767. if(strSame(action,"unparent")){ Unparent=1; }
  768. if(strSame(keep,"false")){ KeepTransform=0; }
  769. if(!Unparent){ if((!mo) || (!(mo->Flags&TNS_OBJECT_FLAGS_SELECTED))) return LA_FINISHED;
  770. if(!la_ParentableRecursive(root,mo)){ laEnableMessagePanel(0,0,"It didn't work","There are loops in parenting",e->x,e->y,0,e); return LA_FINISHED; }
  771. }
  772. if(keep){
  773. la_MakeParentExecuteRecursive(root,mo,Unparent,KeepTransform);
  774. laRecordInstanceDifferences(T->World, "tns_world"); laPushDifferences(Unparent?"Unparent":"Parent", TNS_HINT_TRANSFORM);
  775. return LA_FINISHED;
  776. }
  777. laEnableOperatorPanel(a,a->This,e->x,e->y,200,200,0,0,0,0,0,0,0,0,e);
  778. return LA_RUNNING;
  779. }
  780. void laui_MakeParent(laUiList *uil, laPropPack *pp, laPropPack *actinst, laColumn *extracol, int context){
  781. laColumn* c=laFirstColumn(uil);
  782. laShowItemFull(uil,c,pp,"_this_M_make_parent",0,"action=parent;keep_transform=true;text=Keep transform",0,0);
  783. laShowItemFull(uil,c,pp,"_this_M_make_parent",0,"action=parent;keep_transform=false;text=Directly",0,0);
  784. }
  785. void laui_Unparent(laUiList *uil, laPropPack *pp, laPropPack *actinst, laColumn *extracol, int context){
  786. laColumn* c=laFirstColumn(uil);
  787. laShowItemFull(uil,c,pp,"_this_M_unparent",0,"action=unparent;keep_transform=true;text=Keep transform",0,0);
  788. laShowItemFull(uil,c,pp,"_this_M_unparent",0,"action=unparent;keep_transform=false;text=Directly",0,0);
  789. }
  790. STRUCTURE(MEDupVert){
  791. int oi; tnsMVert* nmv; tnsMVert* omv; int IsBorder;
  792. };
  793. STRUCTURE(MEDupEdge){
  794. int oi; tnsMEdge* nme; tnsMEdge* ome; int IsBorder;
  795. };
  796. STRUCTURE(MEDupFace){
  797. int oi; tnsMFace* nmf; tnsMFace* omf;
  798. };
  799. STRUCTURE(MExtrudeExtra){
  800. MEDupVert* dv; int nextv,maxv;
  801. MEDupEdge* de; int nexte,maxe;
  802. MEDupFace* df; int nextf,maxf;
  803. tnsMeshObject* mo;
  804. int RemoveOriginalFaces;
  805. };
  806. int la_IsSelectionBorderVertex(tnsMVert* mv){
  807. if(!mv->elink.pFirst)
  808. return 0;
  809. int NearSelected=0, NearUnselected=0;
  810. for(laListItemPointer* lip=mv->elink.pFirst;lip;lip=lip->pNext){
  811. tnsMEdge* me=lip->p; if(!(me->fl&&me->fr)) return 1;
  812. tnsMVert* av=tnsMMeshEdgeAnotherVert(me,mv);
  813. if(me->fl->flags&TNS_MESH_FLAG_SELECTED){ NearSelected=1; } else { return 1; }
  814. if(me->fr->flags&TNS_MESH_FLAG_SELECTED){ NearSelected=1; } else { return 1; }
  815. if(NearUnselected && NearSelected) return 1;
  816. }
  817. return 0;
  818. }
  819. int la_IsSelectionBorderEdge(tnsMEdge* me){
  820. if(me->fl&&me->fr){
  821. if ((me->fl->flags&TNS_MESH_FLAG_SELECTED) && (!(me->fr->flags&TNS_MESH_FLAG_SELECTED))||
  822. (me->fr->flags&TNS_MESH_FLAG_SELECTED) && (!(me->fl->flags&TNS_MESH_FLAG_SELECTED))) return 1;
  823. else return (me->fr->flags==me->fl->flags&&me->fl->flags==0);
  824. } return 1;
  825. }
  826. MExtrudeExtra* la_InitExtrude(tnsMeshObject* mo){
  827. MExtrudeExtra* ee=memAcquireSimple(sizeof(MExtrudeExtra));
  828. arrEnsureLength(&ee->dv, ee->nextv, &ee->maxv, sizeof(MEDupVert));
  829. arrEnsureLength(&ee->de, ee->nexte, &ee->maxe, sizeof(MEDupEdge));
  830. arrEnsureLength(&ee->df, ee->nextf, &ee->maxf, sizeof(MEDupFace));
  831. ee->mo=mo;
  832. return ee;
  833. }
  834. void la_ExtrudeMakeDuplication(MExtrudeExtra* ee){
  835. tnsMeshObject* mo=ee->mo;
  836. for(tnsMVert* mv=mo->mv.pFirst;mv;mv=mv->Item.pNext){ if(!(mv->flags&TNS_MESH_FLAG_SELECTED)) continue;
  837. arrEnsureLength(&ee->dv, ee->nextv, &ee->maxv, sizeof(MEDupVert));
  838. MEDupVert* dv=&ee->dv[ee->nextv];
  839. tnsMVert* nmv=tnsMMeshNewVert(mo); tnsVectorCopy3d(mv->p, &nmv->p); dv->oi=mv->i; mv->i=ee->nextv; dv->nmv=nmv; dv->omv=mv;
  840. dv->IsBorder=la_IsSelectionBorderVertex(mv);
  841. ee->nextv++;
  842. }
  843. for(tnsMEdge* me=mo->me.pFirst;me;me=me->Item.pNext){ if(!(me->flags&TNS_MESH_FLAG_SELECTED)) continue;
  844. arrEnsureLength(&ee->de, ee->nexte, &ee->maxe, sizeof(MEDupEdge));
  845. MEDupEdge* de=&ee->de[ee->nexte];
  846. tnsMEdge* nme=tnsMMeshNewEdge(mo); de->oi=me->i; me->i=ee->nexte; de->nme=nme; de->ome=me; de->IsBorder=la_IsSelectionBorderEdge(me);
  847. tnsMMeshEdgeAssignVerts(nme, ee->dv[me->vl->i].nmv, ee->dv[me->vr->i].nmv);
  848. if(de->IsBorder&&me->fl&&me->fr){ ee->RemoveOriginalFaces=1; }
  849. ee->nexte++;
  850. }
  851. for(tnsMFace* mf=mo->mf.pFirst;mf;mf=mf->Item.pNext){
  852. if(!(mf->flags&TNS_MESH_FLAG_SELECTED)) continue;
  853. arrEnsureLength(&ee->df, ee->nextf, &ee->maxf, sizeof(MEDupFace));
  854. MEDupFace* df=&ee->df[ee->nextf];
  855. tnsMFace* nmf=tnsMMeshNewFace(mo); df->oi=mf->i; mf->i=ee->nextf; df->nmf=nmf; df->omf=mf;
  856. for(laListItemPointer*lip=mf->l.pFirst;lip;lip=lip->pNext){
  857. tnsMEdge* ome=lip->p; tnsMMeshFaceAddEdge(nmf,ee->de[ome->i].nme);
  858. }
  859. ee->nextf++;
  860. }
  861. for(int i=0;i<ee->nextv;i++){ ee->dv[i].omv->i=ee->dv[i].oi; ee->dv[i].omv->flags&=(~TNS_MESH_FLAG_SELECTED); ee->dv[i].nmv->flags|=TNS_MESH_FLAG_SELECTED; }
  862. for(int i=0;i<ee->nexte;i++){ ee->de[i].ome->i=ee->de[i].oi; ee->de[i].ome->flags&=(~TNS_MESH_FLAG_SELECTED); ee->de[i].nme->flags|=TNS_MESH_FLAG_SELECTED; }
  863. for(int i=0;i<ee->nextf;i++){
  864. ee->df[i].omf->i=ee->df[i].oi;
  865. ee->df[i].omf->flags&=(~TNS_MESH_FLAG_SELECTED);
  866. ee->df[i].nmf->flags|=TNS_MESH_FLAG_SELECTED; }
  867. }
  868. void la_RemoveOriginalFaces(MExtrudeExtra* ee){
  869. tnsMeshObject* mo=ee->mo;
  870. if(ee->RemoveOriginalFaces){
  871. for(int i=0;i<ee->nextf;i++){ tnsMMeshRemoveFaceOnly(mo, ee->df[i].omf); }
  872. for(int i=0;i<ee->nexte;i++){ if(ee->de[i].IsBorder) continue; tnsMMeshRemoveEdgeFace(mo, ee->de[i].ome); }
  873. for(int i=0;i<ee->nextv;i++){ if(ee->dv[i].IsBorder) continue; tnsMMeshRemoveVertEdgeFace(mo, ee->dv[i].omv); }
  874. }
  875. }
  876. void la_ReconnectFaces(MExtrudeExtra* ee){
  877. tnsMeshObject* mo=ee->mo;
  878. for(int i=0;i<ee->nexte;i++){
  879. if(!ee->de[i].IsBorder) continue; MEDupEdge*de=&ee->de[i];
  880. tnsMMeshMakeFace4v(mo, de->ome->vl, de->ome->vr, de->nme->vr, de->nme->vl);
  881. }
  882. }
  883. void la_FinishExtrude(MExtrudeExtra* ee, int PushDifferences){
  884. tnsMMeshRefreshIndex(ee->mo);
  885. tnsInvalidateMeshBatch(ee->mo);
  886. if(PushDifferences){
  887. laRecordInstanceDifferences(ee->mo, "tns_mesh_object"); laPushDifferences("Extruded", TNS_HINT_GEOMETRY); laNotifyUsers("tns.world");
  888. }
  889. free(ee->dv); free(ee->de); free(ee->df); memFree(ee);
  890. }
  891. int OPINV_Extrude(laOperator *a, laEvent *e){
  892. if(!a->This || !a->This->EndInstance){ return 0; }
  893. laCanvasExtra* ex=a->This->EndInstance; tnsCamera*c=ex->ViewingCamera; laUiItem* ui=ex->ParentUi;
  894. tnsObject*root=ui?ui->PP.EndInstance:0; if(!root) return 0;
  895. tnsMeshObject* mo=root->Active; if(mo->Base.Type!=TNS_OBJECT_MESH || mo->Mode!=TNS_MESH_EDIT_MODE) return 0;
  896. if(!tnsMMeshAnySelected(mo)) return LA_FINISHED;
  897. MExtrudeExtra* ee=la_InitExtrude(mo);
  898. la_ExtrudeMakeDuplication(ee);
  899. if(strSame(strGetArgumentString(a->ExtraInstructionsP,"duplicate_only"), "true")){
  900. la_FinishExtrude(ee, 1);
  901. if(la_InitTransform(a, e, LA_TRANSFORM_MODE_GRAB,0,0)) return LA_RUNNING; return LA_FINISHED;
  902. }
  903. la_RemoveOriginalFaces(ee);
  904. la_ReconnectFaces(ee);
  905. la_FinishExtrude(ee, 1);
  906. if(la_InitTransform(a, e, LA_TRANSFORM_MODE_GRAB,0,0)) return LA_RUNNING; return LA_FINISHED;
  907. return LA_FINISHED;
  908. }
  909. int la_EdgeShouldDeleteVert(tnsMVert* mv){
  910. if(!mv->elink.pFirst) return 0;
  911. int NearSelected=0, NearUnselected=0;
  912. for(laListItemPointer* lip=mv->elink.pFirst;lip;lip=lip->pNext){
  913. tnsMEdge* me=lip->p;
  914. tnsMVert* av=tnsMMeshEdgeAnotherVert(me,mv);
  915. if(av->flags&TNS_MESH_FLAG_SELECTED){ NearSelected=1; } else { NearUnselected=1; }
  916. if(NearUnselected && NearSelected) return 0;
  917. }
  918. if(NearSelected&&(!NearUnselected)) return 1; return 0;
  919. }
  920. int la_FaceShouldDeleteVert(tnsMVert* mv){
  921. if(!mv->elink.pFirst) return 0;
  922. int NearSelected=0, NearUnselected=0, IsBorder=0;
  923. for(laListItemPointer* lip=mv->elink.pFirst;lip;lip=lip->pNext){
  924. tnsMEdge* me=lip->p;
  925. if(!(me->fl&&me->fr)){ IsBorder=1; }
  926. if(me->fl){ if(me->fl->flags&TNS_MESH_FLAG_SELECTED){ NearSelected=1; } else { NearUnselected=1; } }
  927. if(me->fr){ if(me->fr->flags&TNS_MESH_FLAG_SELECTED){ NearSelected=1; } else { NearUnselected=1; } }
  928. if(NearUnselected && NearSelected) return 0;
  929. }
  930. if((!NearUnselected) && IsBorder) return 1;
  931. return 1;
  932. }
  933. int la_FaceShouldDeleteEdge(tnsMEdge* me){
  934. if(me->fl&&me->fr){
  935. if ((me->fl->flags&TNS_MESH_FLAG_SELECTED) && (!(me->fr->flags&TNS_MESH_FLAG_SELECTED))||
  936. (me->fr->flags&TNS_MESH_FLAG_SELECTED) && (!(me->fl->flags&TNS_MESH_FLAG_SELECTED))) return 0;
  937. else return (me->fr->flags==me->fl->flags&&me->fl->flags==1);
  938. }else{
  939. if(me->fl&&me->fl->flags&TNS_MESH_FLAG_SELECTED&&!me->fr) return 1;
  940. if(me->fr&&me->fr->flags&TNS_MESH_FLAG_SELECTED&&!me->fl) return 1;
  941. } return 0;
  942. }
  943. void la_DeleteVertices(tnsMeshObject* mo){
  944. tnsMVert* nextmv; for(tnsMVert*mv=mo->mv.pFirst;mv;mv=nextmv){ nextmv=mv->Item.pNext; if(!(mv->flags&TNS_MESH_FLAG_SELECTED)) continue;
  945. tnsMMeshRemoveVertEdgeFace(mo, mv);
  946. }
  947. }
  948. void la_DeleteEdges(tnsMeshObject* mo){
  949. laListHandle lv={0};
  950. for(tnsMVert*mv=mo->mv.pFirst;mv;mv=mv->Item.pNext){ if(!(mv->flags&TNS_MESH_FLAG_SELECTED)) continue;
  951. if(la_EdgeShouldDeleteVert(mv)) lstAppendPointer(&lv,mv);
  952. }
  953. tnsMEdge* nextme; for(tnsMEdge*me=mo->me.pFirst;me;me=nextme){ nextme=me->Item.pNext; if(!(me->flags&TNS_MESH_FLAG_SELECTED)) continue;
  954. tnsMMeshRemoveEdgeFace(mo, me);
  955. }
  956. tnsMVert* mv; while(mv=lstPopPointer(&lv)){ tnsMMeshRemoveVertEdgeFace(mo,mv); }
  957. }
  958. void la_DeleteFaces(tnsMeshObject* mo, int OnlyFaces){
  959. laListHandle lv={0}, le={0};
  960. if(OnlyFaces){
  961. tnsMFace* nextmf; for(tnsMFace*mf=mo->mf.pFirst;mf;mf=nextmf){ nextmf=mf->Item.pNext; if(!(mf->flags&TNS_MESH_FLAG_SELECTED)) continue;
  962. tnsMMeshRemoveFaceOnly(mo, mf);
  963. }
  964. }else{
  965. for(tnsMVert*mv=mo->mv.pFirst;mv;mv=mv->Item.pNext){ if(!(mv->flags&TNS_MESH_FLAG_SELECTED)) continue;
  966. if(la_FaceShouldDeleteVert(mv)) lstAppendPointer(&lv,mv);
  967. }
  968. for(tnsMEdge*me=mo->me.pFirst;me;me=me->Item.pNext){ if(!(me->flags&TNS_MESH_FLAG_SELECTED)) continue;
  969. if(la_FaceShouldDeleteEdge(me)) lstAppendPointer(&le,me);
  970. }
  971. tnsMFace* nextmf; for(tnsMFace*mf=mo->mf.pFirst;mf;mf=nextmf){ nextmf=mf->Item.pNext; if(!(mf->flags&TNS_MESH_FLAG_SELECTED)) continue;
  972. tnsMMeshRemoveFaceOnly(mo, mf);
  973. }
  974. tnsMEdge* me; while(me=lstPopPointer(&le)){ tnsMMeshRemoveEdgeFace(mo,me); }
  975. tnsMVert* mv; while(mv=lstPopPointer(&lv)){ tnsMMeshRemoveVertEdgeFace(mo,mv); }
  976. }
  977. }
  978. int la_DeleteSelectedObjectsRecursive(tnsObject* root){
  979. int any=0; for(laListItemPointer* lip=root->ChildObjects.pFirst;lip;lip=lip->pNext){ if(!lip->p) continue;
  980. tnsObject* o=lip->p; la_DeleteSelectedObjectsRecursive(lip->p);
  981. if(o->Flags&TNS_OBJECT_FLAGS_SELECTED){ tnsDestroyObject(o); any++; }
  982. }
  983. return any;
  984. }
  985. int OPINV_Delete(laOperator *a, laEvent *e){
  986. if(!a->This || !a->This->EndInstance){ return 0; }
  987. laCanvasExtra* ex=a->This->EndInstance; tnsCamera*c=ex->ViewingCamera; laUiItem* ui=ex->ParentUi;
  988. tnsObject*root=ui?ui->PP.EndInstance:0; if(!root) return 0;
  989. tnsMeshObject* mo=root->Active; if(!mo) return 0;
  990. if(mo->Base.Type!=TNS_OBJECT_MESH || mo->Mode!=TNS_MESH_EDIT_MODE){
  991. if(la_DeleteSelectedObjectsRecursive(root)){
  992. laRecordInstanceDifferences(T->World, "tns_world"); laPushDifferences("Deleted objects", TNS_HINT_TRANSFORM); laNotifyUsers("tns.world");
  993. }
  994. }else{
  995. if(!tnsMMeshAnySelected(mo)) return LA_FINISHED;
  996. if(strSame(strGetArgumentString(a->ExtraInstructionsP, "mode"),"vertices")){
  997. la_DeleteVertices(mo);
  998. }elif(strSame(strGetArgumentString(a->ExtraInstructionsP, "mode"),"edges")){
  999. la_DeleteEdges(mo);
  1000. }elif(strSame(strGetArgumentString(a->ExtraInstructionsP, "mode"),"faces")){
  1001. la_DeleteFaces(mo,0);
  1002. }elif(strSame(strGetArgumentString(a->ExtraInstructionsP, "mode"),"only_faces")){
  1003. la_DeleteFaces(mo,1);
  1004. }else{
  1005. laEnableOperatorPanel(a,a->This,e->x,e->y,200,200,0,0,0,0,0,0,0,0,e);
  1006. return LA_RUNNING;
  1007. }
  1008. tnsMMeshDeselectAll(mo);
  1009. tnsMMeshRefreshIndex(mo);
  1010. tnsInvalidateMeshBatch(mo);
  1011. laRecordInstanceDifferences(mo, "tns_mesh_object"); laPushDifferences("Deleted primitives", TNS_HINT_GEOMETRY); laNotifyUsers("tns.world");
  1012. }
  1013. return LA_FINISHED;
  1014. }
  1015. void laui_Delete(laUiList *uil, laPropPack *pp, laPropPack *actinst, laColumn *extracol, int context){
  1016. laColumn* c=laFirstColumn(uil);
  1017. laShowItemFull(uil,c,pp,"_this_M_delete",0,"mode=vertices;text=Vertices",0,0);
  1018. laShowItemFull(uil,c,pp,"_this_M_delete",0,"mode=edges;text=Edges",0,0);
  1019. laShowItemFull(uil,c,pp,"_this_M_delete",0,"mode=faces;text=Faces",0,0);
  1020. laShowItemFull(uil,c,pp,"_this_M_delete",0,"mode=only_faces;text=Only Faces",0,0);
  1021. }
  1022. STRUCTURE(MIslandInfo){
  1023. laListItem Item;
  1024. laListHandle v,e,f;int numv,nume,numf;
  1025. int Paired,HasBranches;
  1026. };
  1027. STRUCTURE(MMakeData){
  1028. laListHandle Islands; int NumIslands;
  1029. };
  1030. #define M_SHOULD_INCL_PRIM(m) \
  1031. ((!(m->flags&TNS_MESH_FLAG_PICKED)) && (m->flags&TNS_MESH_FLAG_SELECTED))
  1032. #define M_SHOULD_USE_OE(oe,sf) \
  1033. (((!oe->fl)&&((!sf)||(oe->fr!=sf)))||((!oe->fr)&&((!sf)||(oe->fl!=sf))))
  1034. MIslandInfo* la_NewMIsland(MMakeData* md){ MIslandInfo* ii=memAcquireSimple(sizeof(MIslandInfo)); lstAppendItem(&md->Islands, ii); md->NumIslands++; return ii; }
  1035. void la_FillIslandFromVert(MIslandInfo* ii, tnsMVert* mv, int SelectMode){
  1036. mv->flags|=TNS_MESH_FLAG_PICKED; lstAppendPointer(&ii->v,mv); ii->numv++; int connections=0;
  1037. for(laListItemPointer* lip=mv->elink.pFirst;lip;lip=lip->pNext){ tnsMEdge* oe=lip->p; tnsMVert* ov=tnsMMeshEdgeAnotherVert(oe,mv);
  1038. if(ov->flags&TNS_MESH_FLAG_SELECTED) connections++; else continue;
  1039. if(SelectMode==LA_CANVAS_SELECT_MODE_EDGES){ if(!(oe->flags&TNS_MESH_FLAG_SELECTED)) continue; }
  1040. if(M_SHOULD_INCL_PRIM(ov)){ la_FillIslandFromVert(ii,ov,SelectMode); } else { continue; }
  1041. if(M_SHOULD_INCL_PRIM(oe)){ lstAppendPointer(&ii->e,oe); ii->nume++; oe->flags|=TNS_MESH_FLAG_PICKED; }
  1042. if(oe->fl&&M_SHOULD_INCL_PRIM(oe->fl)){ lstAppendPointer(&ii->f,oe->fl); ii->numf++; oe->fl->flags|=TNS_MESH_FLAG_PICKED; }
  1043. if(oe->fr&&M_SHOULD_INCL_PRIM(oe->fr)){ lstAppendPointer(&ii->f,oe->fr); ii->numf++; oe->fr->flags|=TNS_MESH_FLAG_PICKED; }
  1044. }
  1045. if(connections>2) ii->HasBranches=1;
  1046. }
  1047. void la_GetSelectionIslands(tnsMeshObject* mo, MMakeData* md, int SelectMode){
  1048. tnsMMeshClearExtraFlags(mo);
  1049. for(tnsMVert* mv=mo->mv.pFirst;mv;mv=mv->Item.pNext){
  1050. if(M_SHOULD_INCL_PRIM(mv)){ MIslandInfo* ii=la_NewMIsland(md); la_FillIslandFromVert(ii,mv,SelectMode); }
  1051. }
  1052. }
  1053. void la_ClearIslands(MMakeData* md){ MIslandInfo* ii; while(ii=lstPopItem(&md->Islands)){ while(lstPopPointer(&ii->v)); memFree(ii); } }
  1054. tnsMFace* la_MakeFacesFrom1Vert(tnsMeshObject* mo, tnsMVert* mv){
  1055. tnsMEdge* oe1=0,*oe2=0; tnsMVert* ov1,*ov2;
  1056. for(laListItemPointer* lip=mv->elink.pFirst;lip;lip=lip->pNext){
  1057. tnsMEdge* oe=lip->p; if(oe->flags&TNS_MESH_FLAG_SELECTED) continue; if((!oe->fl)||(!oe->fr)){ if(!oe1)oe1=oe;elif(!oe2)oe2=oe;else return 0; /* more than 2 empty edges connected */ }
  1058. } if(!oe1||!oe2) return 0;
  1059. ov1=tnsMMeshEdgeAnotherVert(oe1,mv); ov2=tnsMMeshEdgeAnotherVert(oe2,mv);
  1060. laListHandle vl={0}; lstAppendPointer(&vl,ov1); lstAppendPointer(&vl,mv); lstAppendPointer(&vl,ov2);
  1061. tnsMFace* f=tnsMMeshMakeFaceN(mo, 3, &vl, 0);
  1062. ov1->flags|=TNS_MESH_FLAG_SELECTED;ov2->flags|=TNS_MESH_FLAG_SELECTED; mv->flags&=(~TNS_MESH_FLAG_SELECTED);
  1063. tnsMMeshEnsureSelectionFromVerts(mo);
  1064. while(lstPopPointer(&vl)); return f;
  1065. }
  1066. tnsMFace* la_MakeFacesFrom2Verts(tnsMeshObject* mo, tnsMVert* mv1, tnsMVert* mv2){
  1067. tnsMEdge* oe1=0,*oe2=0; tnsMVert* ov1,*ov2; tnsMFace* sf=0;
  1068. tnsMEdge* se=tnsMMeshVertsShareEdge(mv1,mv2); if(se->fl && se->fr) return 0; sf=se->fl?se->fl:se->fr;
  1069. for(laListItemPointer* lip=mv1->elink.pFirst;lip;lip=lip->pNext){
  1070. tnsMEdge* oe=lip->p; if(oe->flags&TNS_MESH_FLAG_SELECTED) continue; if(M_SHOULD_USE_OE(oe,sf)){ if(!oe1)oe1=oe;else return 0; /* more than 1 empty edge connected */ }
  1071. }
  1072. for(laListItemPointer* lip=mv2->elink.pFirst;lip;lip=lip->pNext){
  1073. tnsMEdge* oe=lip->p; if(oe->flags&TNS_MESH_FLAG_SELECTED) continue; if(M_SHOULD_USE_OE(oe,sf)){ if(!oe2)oe2=oe;else return 0; /* more than 1 empty edge connected */ }
  1074. }
  1075. if(!oe1||!oe2) return 0;
  1076. ov1=tnsMMeshEdgeAnotherVert(oe1,mv1); ov2=tnsMMeshEdgeAnotherVert(oe2,mv2);
  1077. ov1->flags|=TNS_MESH_FLAG_SELECTED;ov2->flags|=TNS_MESH_FLAG_SELECTED; mv1->flags&=(~TNS_MESH_FLAG_SELECTED);mv2->flags&=(~TNS_MESH_FLAG_SELECTED);
  1078. laListHandle vl={0}; int vcount=3;
  1079. lstAppendPointer(&vl,ov1); lstAppendPointer(&vl,mv1); lstAppendPointer(&vl,mv2); if(ov2!=ov1){ lstAppendPointer(&vl,ov2); vcount=4; }
  1080. tnsMFace* f=tnsMMeshMakeFaceN(mo, vcount, &vl, 0); tnsMMeshEnsureSelectionFromVerts(mo);
  1081. while(lstPopPointer(&vl)); return f;
  1082. }
  1083. int la_IsEndingVert(tnsMVert* mv){
  1084. int sel=0; for(laListItemPointer*lip=mv->elink.pFirst;lip;lip=lip->pNext){ tnsMEdge* me=lip->p;
  1085. if(tnsMMeshEdgeAnotherVert(me,mv)->flags&TNS_MESH_FLAG_SELECTED){ sel++; if(sel>1) return 0; }
  1086. }
  1087. if(sel==1) return 1; return 0;
  1088. }
  1089. void la_EnsureIslandVertsSequence(MIslandInfo* ii){
  1090. laListHandle l={0}; tnsMVert* startv=((laListItemPointer*)ii->v.pFirst)->p; laListItemPointer* nextlip;
  1091. for(laListItemPointer*lip=ii->v.pFirst;lip;lip=lip->pNext){ if(la_IsEndingVert(lip->p)){ startv=lip->p; break; } } // otherwise a loop, doesn't matter.
  1092. lstRemovePointer(&ii->v, startv); lstAppendPointer(&l, startv);
  1093. while(ii->v.pFirst){
  1094. for(laListItemPointer*lip=ii->v.pFirst;lip;lip=lip->pNext){ nextlip=lip->pNext;
  1095. if(tnsMMeshVertsShareEdge(startv, lip->p)){ startv=lip->p; lstRemoveItem(&ii->v,lip); lstAppendItem(&l, lip); break; }
  1096. }
  1097. }
  1098. memcpy(&ii->v, &l, sizeof(laListHandle));
  1099. }
  1100. MIslandInfo* la_GetNeighborIsland(tnsMVert* from, MMakeData* md){
  1101. int found=0; real dist=1e10; MIslandInfo* rii=0; for(MIslandInfo* ii=md->Islands.pFirst;ii;ii=ii->Item.pNext){ if(ii->Paired) continue;
  1102. found=1; tnsMVert* mv1=((laListItemPointer*)ii->v.pFirst)->p,*mv2=((laListItemPointer*)ii->v.pLast)->p;
  1103. real d1=tnsDist3dv(mv1->p, from->p),d2=tnsDist3dv(mv2->p, from->p);
  1104. if(d2<d1 && d2<dist){ lstReverse(&ii->v); } if(d1<dist || d2<dist){ rii=ii; }
  1105. }
  1106. if(rii) rii->Paired=1;
  1107. return rii;
  1108. }
  1109. int la_MakeFacesFromIslands(tnsMeshObject* mo, MMakeData* md){
  1110. int success=0;
  1111. if(!md->Islands.pFirst) return 0;
  1112. if(md->Islands.pFirst==md->Islands.pLast){
  1113. MIslandInfo* ii=md->Islands.pFirst; if(ii->HasBranches) return 0;
  1114. if(ii->numv==1){ laListItemPointer*lip=ii->v.pFirst; if(la_MakeFacesFrom1Vert(mo,lip->p)) success++; }
  1115. elif(ii->numv==2){ laListItemPointer*lip=ii->v.pFirst,*lip2=ii->v.pLast; if(la_MakeFacesFrom2Verts(mo,lip->p, lip2->p)) success++; }
  1116. else{ la_EnsureIslandVertsSequence(ii); if(tnsMMeshMakeFaceN(mo, ii->numv, &ii->v, 0)) success++; }
  1117. }else{
  1118. for(MIslandInfo* ii=md->Islands.pFirst;ii;ii=ii->Item.pNext){ if(ii->HasBranches) return 0; la_EnsureIslandVertsSequence(ii); }
  1119. laListHandle final={0}; int vcount=0;
  1120. MIslandInfo* ii=md->Islands.pFirst; ii->Paired=1; for(laListItemPointer* lip=ii->v.pFirst;lip;lip=lip->pNext){ lstAppendPointer(&final, lip->p); vcount++; }
  1121. while((ii=la_GetNeighborIsland(((laListItemPointer*)ii->v.pLast)->p, md))){
  1122. for(laListItemPointer* lip=ii->v.pFirst;lip;lip=lip->pNext){ lstAppendPointer(&final, lip->p); vcount++; }
  1123. }
  1124. tnsMEdge* fallback_e=0;
  1125. if(tnsMMeshMakeFaceN(mo,vcount,&final, &fallback_e) || fallback_e) success++;
  1126. while(lstPopPointer(&final));
  1127. }
  1128. return success;
  1129. }
  1130. int OPINV_Make(laOperator *a, laEvent *e){
  1131. if(!a->This || !a->This->EndInstance){ return 0; }
  1132. laCanvasExtra* ex=a->This->EndInstance; tnsCamera*c=ex->ViewingCamera; laUiItem* ui=ex->ParentUi;
  1133. tnsObject*root=ui?ui->PP.EndInstance:0; if(!root) return 0;
  1134. tnsMeshObject* mo=root->Active;
  1135. if(!mo||mo->Base.Type!=TNS_OBJECT_MESH || mo->Mode!=TNS_MESH_EDIT_MODE){ return LA_CANCELED; }
  1136. MMakeData md={0};
  1137. la_GetSelectionIslands(mo,&md,ex->SelectMode);
  1138. int success=la_MakeFacesFromIslands(mo,&md); if(success){ tnsMMeshCalculateNormal(mo); }
  1139. la_ClearIslands(&md);
  1140. tnsMMeshRefreshIndex(mo);
  1141. tnsMMeshEnsureSelection(mo,ex->SelectMode);
  1142. tnsInvalidateMeshBatch(mo);
  1143. if(laRecordInstanceDifferences(mo, "tns_mesh_object")) laPushDifferences("Make primitives", TNS_HINT_GEOMETRY);
  1144. laNotifyUsers("tns.world");
  1145. return LA_FINISHED;
  1146. }
  1147. int OPINV_Subdiv(laOperator *a, laEvent *e){
  1148. if(!a->This || !a->This->EndInstance){ return 0; }
  1149. laCanvasExtra* ex=a->This->EndInstance; tnsCamera*c=ex->ViewingCamera; laUiItem* ui=ex->ParentUi;
  1150. tnsObject*root=ui?ui->PP.EndInstance:0; if(!root) return 0;
  1151. tnsMeshObject* mo=root->Active;
  1152. if(mo->Base.Type!=TNS_OBJECT_MESH || mo->Mode!=TNS_MESH_EDIT_MODE){ return LA_CANCELED; }
  1153. laListHandle pending={0}; for(tnsMEdge* me=mo->me.pFirst;me;me=me->Item.pNext){ if(me->flags&TNS_MESH_FLAG_SELECTED) lstAppendPointer(&pending, me); }
  1154. if(!pending.pFirst) return LA_FINISHED;
  1155. tnsMEdge* me; while(me=lstPopPointer(&pending)){ tnsMVert* mv=tnsMMeshEdgeInsertVertAt(mo,me,0.5,0,0,0); mv->flags|=TNS_MESH_FLAG_SELECTED; }
  1156. tnsMMeshRefreshIndex(mo);
  1157. tnsMMeshEnsureSelection(mo,ex->SelectMode);
  1158. tnsInvalidateMeshBatch(mo);
  1159. if(laRecordInstanceDifferences(mo, "tns_mesh_object")) laPushDifferences("Subdivide edges", TNS_HINT_GEOMETRY);
  1160. laNotifyUsers("tns.world");
  1161. return LA_FINISHED;
  1162. }
  1163. #define LA_ADD_CTX_OBJECT 0
  1164. #define LA_ADD_CTX_MESH 1
  1165. STRUCTURE(laObjectAddData){
  1166. int Context;
  1167. };
  1168. int OPINV_Add(laOperator *a, laEvent *e){
  1169. if(!a->This || !a->This->EndInstance){ return 0; }
  1170. laCanvasExtra* ex=a->This->EndInstance; tnsCamera*c=ex->ViewingCamera; laUiItem* ui=ex->ParentUi;
  1171. tnsObject*root=ui?ui->PP.EndInstance:0; if(!root) return 0;
  1172. tnsMeshObject* mo=root->Active; int ran=0; tnsObject* no=0;
  1173. laObjectAddData *ad=memAcquire(sizeof(laObjectAddData));a->CustomData=ad;
  1174. char* str=strGetArgumentString(a->ExtraInstructionsP, "mode");
  1175. if((!mo) || mo->Base.Type!=TNS_OBJECT_MESH || mo->Mode!=TNS_MESH_EDIT_MODE){ ad->Context=LA_ADD_CTX_OBJECT;
  1176. if(strSame(str,"PLANE")){ tnsDeselectAllObjects(root);
  1177. no=tnsCreateMeshPlane(root, "Plane",0,0,0,10); no->Flags|=TNS_OBJECT_FLAGS_SELECTED; memAssignRef(root,&root->Active,no); ran=1; }
  1178. elif(strSame(str,"INSTANCER")){ tnsDeselectAllObjects(root);
  1179. no=tnsCreateInstancer(root, "Instancer",0,0,0); no->Flags|=TNS_OBJECT_FLAGS_SELECTED; memAssignRef(root,&root->Active,no); ran=1; }
  1180. else{ laEnableOperatorPanel(a,a->This,e->x,e->y,200,200,0,0,0,0,0,0,0,0,e); return LA_RUNNING; }
  1181. if(ran){ laRecordAndPush(0,"tns.world","Add object",TNS_HINT_GEOMETRY); laNotifyUsers("tns.world"); }
  1182. }else{ ad->Context=LA_ADD_CTX_MESH;
  1183. if(strSame(str,"PLANE")){
  1184. tnsMMeshDeselectAll(mo); tnsAddMMeshPlane(mo, 10); tnsMMeshEnsureSelection(mo,ex->SelectMode); ran=1;
  1185. }else{ laEnableOperatorPanel(a,a->This,e->x,e->y,200,200,0,0,0,0,0,0,0,0,e); return LA_RUNNING; }
  1186. if(ran){
  1187. tnsMMeshRefreshIndex(mo); tnsInvalidateMeshBatch(mo);
  1188. laRecordInstanceDifferences(mo, "tns_mesh_object"); laPushDifferences("Add primitives", TNS_HINT_GEOMETRY); laNotifyUsers("tns.world");
  1189. }
  1190. }
  1191. return LA_FINISHED;
  1192. }
  1193. void laui_Add(laUiList *uil, laPropPack *pp, laPropPack *actinst, laColumn *extracol, int context){
  1194. laColumn* c=laFirstColumn(uil);
  1195. laUiItem* b=laOnConditionThat(uil,c,laEqual(laPropExpression(actinst,"context"),laIntExpression(LA_ADD_CTX_OBJECT)));{
  1196. laShowLabel(uil,c,"Empty",0,0)->Flags|=LA_TEXT_MONO|LA_UI_FLAGS_DISABLED;
  1197. laShowItemFull(uil,c,pp,"_this_M_add",0,"mode=INSTANCER;text=Instancer",0,0);
  1198. }laEndCondition(uil,b);
  1199. laShowLabel(uil,c,"Primitives",0,0)->Flags|=LA_TEXT_MONO|LA_UI_FLAGS_DISABLED;
  1200. laShowItemFull(uil,c,pp,"_this_M_add",0,"mode=PLANE;text=Plane",0,0);
  1201. }
  1202. int OPINV_Separate(laOperator *a, laEvent *e){
  1203. if(!a->This || !a->This->EndInstance){ return 0; }
  1204. laCanvasExtra* ex=a->This->EndInstance; tnsCamera*c=ex->ViewingCamera; laUiItem* ui=ex->ParentUi;
  1205. tnsObject*root=ui?ui->PP.EndInstance:0; if(!root) return LA_CANCELED;
  1206. tnsMeshObject* mo=root->Active; int ran=0;
  1207. if(mo->Base.Type!=TNS_OBJECT_MESH || mo->Mode!=TNS_MESH_EDIT_MODE){
  1208. return LA_CANCELED;
  1209. }
  1210. if(!tnsMMeshAnySelected(mo)) return LA_CANCELED;
  1211. MExtrudeExtra* ee=la_InitExtrude(mo);
  1212. la_ExtrudeMakeDuplication(ee);
  1213. ee->RemoveOriginalFaces=1;la_RemoveOriginalFaces(ee);
  1214. tnsMeshObject* no=tnsCreateMeshEmpty(mo->Base.ParentObject?mo->Base.ParentObject:mo->Base.InRoot, mo->Base.Name->Ptr, 0,0,0);
  1215. tnsCopyObjectTransformationsLocal(no,mo);
  1216. no->Mode=TNS_MESH_EDIT_MODE;
  1217. tnsMVert* nmv; for(tnsMVert* mv=mo->mv.pFirst;mv;mv=nmv){ nmv=mv->Item.pNext; if(!(mv->flags&TNS_MESH_FLAG_SELECTED))continue;
  1218. lstRemoveItem(&mo->mv, mv); lstAppendItem(&no->mv, mv); no->totmv++; mo->totmv--; }
  1219. tnsMEdge* nme; for(tnsMEdge* me=mo->me.pFirst;me;me=nme){ nme=me->Item.pNext; if(!(me->flags&TNS_MESH_FLAG_SELECTED))continue;
  1220. lstRemoveItem(&mo->me, me); lstAppendItem(&no->me, me); no->totme++; mo->totme--; }
  1221. tnsMFace* nmf; for(tnsMFace* mf=mo->mf.pFirst;mf;mf=nmf){ nmf=mf->Item.pNext; if(!(mf->flags&TNS_MESH_FLAG_SELECTED))continue;
  1222. lstRemoveItem(&mo->mf, mf); lstAppendItem(&no->mf, mf); no->totmf++; mo->totmf--; }
  1223. tnsMMeshRefreshIndex(no); tnsMeshLeaveEditMode(no);
  1224. la_FinishExtrude(ee, 0);
  1225. tnsMMeshRefreshIndex(mo); tnsInvalidateMeshBatch(mo);
  1226. laRecordAndPush(0,"tns.world","Separate mesh parts",TNS_HINT_GEOMETRY); laNotifyUsers("tns.world");
  1227. return LA_FINISHED;
  1228. }
  1229. void la_PopulateSelectedMeshObjects(tnsObject* root, laListHandle* l){
  1230. if(root->Type==TNS_OBJECT_MESH && root->Flags&TNS_OBJECT_FLAGS_SELECTED){ lstAppendPointer(l,root); }
  1231. for(laListItemPointer* lip=root->ChildObjects.pFirst;lip;lip=lip->pNext){
  1232. la_PopulateSelectedMeshObjects(lip->p, l);
  1233. }
  1234. }
  1235. int OPINV_Combine(laOperator *a, laEvent *e){
  1236. if(!a->This || !a->This->EndInstance){ return 0; }
  1237. laCanvasExtra* ex=a->This->EndInstance; tnsCamera*c=ex->ViewingCamera; laUiItem* ui=ex->ParentUi;
  1238. tnsObject*root=ui?ui->PP.EndInstance:0; if(!root) return LA_CANCELED;
  1239. tnsMeshObject* mo=root->Active; int ran=0;
  1240. if(!mo || mo->Base.Type!=TNS_OBJECT_MESH || mo->Mode==TNS_MESH_EDIT_MODE){ return LA_CANCELED; }
  1241. laListHandle pending={0}; la_PopulateSelectedMeshObjects(root,&pending);
  1242. tnsMeshObject* o; while(o=lstPopPointer(&pending)){ if(o==mo || o->Mode==TNS_MESH_EDIT_MODE) continue;
  1243. if(tnsMergeMeshObjects(mo, o)) ran++;
  1244. }
  1245. if(ran){
  1246. tnsMMeshRefreshIndex(mo); tnsInvalidateMeshBatch(mo);
  1247. laRecordAndPush(0,"tns.world","Merge mesh objects",TNS_HINT_GEOMETRY); laNotifyUsers("tns.world");
  1248. }
  1249. return LA_FINISHED;
  1250. }
  1251. int OPINV_Duplicate(laOperator *a, laEvent *e){
  1252. if(!a->This || !a->This->EndInstance){ return 0; }
  1253. laCanvasExtra* ex=a->This->EndInstance; tnsCamera*c=ex->ViewingCamera; laUiItem* ui=ex->ParentUi;
  1254. tnsObject*root=ui?ui->PP.EndInstance:0; if(!root) return LA_CANCELED;
  1255. tnsMeshObject* mo=root->Active; int ran=0;
  1256. if(!mo || mo->Base.Type!=TNS_OBJECT_MESH || mo->Mode==TNS_MESH_EDIT_MODE){ return LA_CANCELED; }
  1257. laListHandle pending={0}; la_PopulateSelectedMeshObjects(root,&pending);
  1258. tnsMeshObject* o; tnsMeshObject* no;while(o=lstPopPointer(&pending)){ if(o->Mode==TNS_MESH_EDIT_MODE) continue;
  1259. if(no=tnsDuplicateMeshObjects(o)){ no->Base.Flags|=TNS_OBJECT_FLAGS_SELECTED; o->Base.Flags&=(~TNS_OBJECT_FLAGS_SELECTED);
  1260. if(mo==o){ memAssignRef(root,&root->Active,no); } ran++;
  1261. }
  1262. }
  1263. if(ran){
  1264. laRecordAndPush(0,"tns.world","Merge mesh objects",TNS_HINT_GEOMETRY); laNotifyUsers("tns.world");
  1265. if(la_InitTransform(a,e,LA_TRANSFORM_MODE_GRAB,0,0)) return LA_RUNNING; return LA_FINISHED;
  1266. }
  1267. return LA_FINISHED;
  1268. }
  1269. int OPINV_RecalculateNormals(laOperator *a, laEvent *e){
  1270. if(!a->This || !a->This->EndInstance){ return 0; }
  1271. laCanvasExtra* ex=a->This->EndInstance; tnsCamera*c=ex->ViewingCamera; laUiItem* ui=ex->ParentUi;
  1272. tnsObject*root=ui?ui->PP.EndInstance:0; if(!root) return LA_CANCELED;
  1273. tnsMeshObject* mo=root->Active; int ran=0;
  1274. if(!mo || mo->Base.Type!=TNS_OBJECT_MESH || mo->Mode!=TNS_MESH_EDIT_MODE){ return LA_CANCELED; }
  1275. ran=tnsMMeshCalculateNormal(mo);
  1276. if(ran){ tnsInvalidateMeshBatch(mo); laRecordAndPush(0,"tns.world","Recalculate Normals",TNS_HINT_GEOMETRY); laNotifyUsers("tns.world"); }
  1277. return LA_FINISHED;
  1278. }
  1279. STRUCTURE(MKnifeElement){
  1280. laListItem Item;
  1281. void* p;
  1282. int Type;
  1283. };
  1284. void la_KnifeUpdateToolBatch(MSelectExtra* se,tnsMeshObject* o){
  1285. if(o->ExtraBatch) tnsDeleteBatch(o->ExtraBatch); o->ExtraBatch=0;
  1286. int count=lstCountElements(&se->KnifeElements); if((!count) && (!se->PendingElem)) return;
  1287. float* points=calloc((count+1)*3,sizeof(real));
  1288. float* p=points; real tmp[3],trans[4];
  1289. for(MKnifeElement* ke=se->KnifeElements.pFirst;ke;ke=ke->Item.pNext){
  1290. if(ke->Type==TNS_MMESH_EDGE_BIT){ tnsMEdge* me=ke->p; tnsVectorSet3v(tmp,me->vl->p); tnsVectorAccum3d(tmp,me->vr->p);
  1291. tnsVectorMultiSelf3d(tmp,0.5); tnsApplyTransform43d(trans,o->Base.GlobalTransform,tmp); tnsVectorSet3v(p,trans); }
  1292. else{ tnsMVert* mv=ke->p; tnsApplyTransform43d(trans,o->Base.GlobalTransform,mv->p); tnsVectorSet3v(p,trans); }
  1293. p+=3;
  1294. }
  1295. if(se->PendingElem){
  1296. if(se->PendingElemType==TNS_MMESH_EDGE_BIT){ tnsMEdge* me=se->PendingElem; tnsVectorSet3v(tmp,me->vl->p); tnsVectorAccum3d(tmp,me->vr->p);
  1297. tnsVectorMultiSelf3d(tmp,0.5); tnsApplyTransform43d(trans,o->Base.GlobalTransform,tmp); tnsVectorSet3v(p,trans); }
  1298. else{ tnsMVert* mv=se->PendingElem; tnsApplyTransform43d(trans,o->Base.GlobalTransform,mv->p); tnsVectorSet3v(p,trans); }
  1299. }elif(count){
  1300. tnsVectorSet3v(p,p-3);
  1301. }
  1302. uint32_t elem=count;
  1303. tnsBatch* batch=tnsCreateBatch(count+1,3,points,0,0,0,0); tnsBatchCommand*c;
  1304. c=tnsCreateCommand(batch, "hovering_point", 1, 3, GL_POINTS, &elem, 0);
  1305. tnsCommandUseUniformColor(c,laAccentColor(LA_BT_SVERTEX));
  1306. tnsCommandUseWidth(c, 8);
  1307. if(count){
  1308. c=tnsCreateCommand(batch, "edges", count+(se->IsLoop?0:1), 3, se->IsLoop?GL_LINE_LOOP:GL_LINE_STRIP, 0, 0);
  1309. tnsCommandUseUniformColor(c,laAccentColor(LA_BT_NORMAL));
  1310. tnsCommandUseWidth(c, 2);
  1311. c=tnsCreateCommand(batch, "points", count, 3, GL_POINTS, 0, 0);
  1312. tnsCommandUseUniformColor(c,laAccentColor(LA_BT_NORMAL));
  1313. tnsCommandUseWidth(c, 6);
  1314. }
  1315. o->ExtraBatch=batch;
  1316. free(points);
  1317. }
  1318. int la_KnifeIsDuplicated(MSelectExtra* se, void* ref){
  1319. for(MKnifeElement* ke=se->KnifeElements.pFirst;ke;ke=ke->Item.pNext){
  1320. if(ke->Type==TNS_MMESH_EDGE_BIT && ke->p==ref){ return 1; }
  1321. }
  1322. return 0;
  1323. }
  1324. void la_KnifeAppendCut(MSelectExtra* se){
  1325. MKnifeElement* ke=lstAppendPointerSized(&se->KnifeElements,se->PendingElem,sizeof(MKnifeElement));
  1326. ke->Type=se->PendingElemType;
  1327. }
  1328. int la_KnifeRegisterCuts(MSelectExtra* se, tnsMeshObject* mo, int TryClose){
  1329. if(!mo || mo->Base.Type!=TNS_OBJECT_MESH || mo->Mode!=TNS_MESH_EDIT_MODE) return 0;
  1330. if(!se->KnifeElements.pFirst) return 0;
  1331. tnsMVert* lastv=0,*newv=0,*firstv=0; tnsMEdge* newme=0; int changed=0; tnsMFace* mf=0;
  1332. for(MKnifeElement* ke=se->KnifeElements.pFirst;ke;ke=ke->Item.pNext){
  1333. if(ke->Type==TNS_MMESH_EDGE_BIT){
  1334. newv=tnsMMeshEdgeInsertVertAt(mo,ke->p,0.5,0,0,0); changed=1;
  1335. }
  1336. else{ newv=ke->p; }
  1337. if(lastv){ if(tnsMMeshVertsShareFace(lastv,newv)) newme=tnsMMeshMakeEdge(mo, lastv, newv); changed=1; }
  1338. lastv=newv; if(!firstv) firstv=newv; newv->flags|=TNS_MESH_FLAG_SELECTED;
  1339. if(newme){ newme->flags|=TNS_MESH_FLAG_SELECTED; }
  1340. }
  1341. if(TryClose){ if((mf=tnsMMeshVertsShareFace(lastv,firstv))&&mf->looplen==6) newme=tnsMMeshMakeEdge(mo, lastv, firstv); changed=1; }
  1342. if(changed){ tnsMMeshRefreshIndex(mo); tnsMMeshCalculateNormal(mo); }
  1343. return changed;
  1344. }
  1345. void la_KnifeFinish(MSelectExtra* se, tnsMeshObject*o){
  1346. if(o->ExtraBatch) tnsDeleteBatch(o->ExtraBatch); o->ExtraBatch=0;
  1347. while(lstPopPointer(&se->KnifeElements));
  1348. la_FreeSelectData(se->sd); memFree(se);
  1349. }
  1350. void la_KnifeRefreshLoopCuts(MSelectExtra* se, tnsObject* o,tnsMEdge* me){
  1351. if(!me) return;
  1352. tnsMMeshClearExtraFlags(o);
  1353. laListHandle lst={0}; lstAppendPointer(&lst,me); me->flags|=TNS_MESH_FLAG_PICKED;
  1354. tnsMMeshExpandBandList(o, me, &lst);
  1355. if(lst.pFirst==lst.pLast){ while(lstPopPointer(&lst)); return; }
  1356. tnsMEdge* mme; while((mme=lstPopPointer(&lst))){
  1357. MKnifeElement* ke=lstAppendPointerSized(&se->KnifeElements,mme,sizeof(MKnifeElement));
  1358. ke->Type=TNS_MMESH_EDGE_BIT;
  1359. }
  1360. }
  1361. void la_KnifeSortLoopCuts(MSelectExtra* se){
  1362. laListHandle lst={0};MKnifeElement* ke=se->KnifeElements.pFirst,*NextKe;
  1363. if(!ke) return;
  1364. lstRemoveItem(&se->KnifeElements,ke); lstAppendItem(&lst,ke);
  1365. for(ke=se->KnifeElements.pFirst;ke;ke=NextKe){
  1366. NextKe=ke->Item.pNext; tnsMEdge* me=ke->p,*firste=((MKnifeElement*)lst.pFirst)->p,*laste=((MKnifeElement*)lst.pLast)->p;
  1367. if(tnsMMeshEdgeShareFace(me,firste) && (!tnsMMeshEdgeShareVert(me,firste))){
  1368. lstRemoveItem(&se->KnifeElements,ke); lstPushItem(&lst,ke); ke=se->KnifeElements.pFirst; continue; }
  1369. if(tnsMMeshEdgeShareFace(me,laste) && (!tnsMMeshEdgeShareVert(me,laste))){
  1370. lstRemoveItem(&se->KnifeElements,ke); lstAppendItem(&lst,ke); ke=se->KnifeElements.pFirst; continue; }
  1371. }
  1372. if(se->KnifeElements.pFirst){ /* something went wrong */ while(lstPopPointer(&se->KnifeElements)); while(lstPopPointer(&lst)); }
  1373. se->KnifeElements.pFirst=lst.pFirst; se->KnifeElements.pLast=lst.pLast;
  1374. }
  1375. int OPINV_Knife(laOperator *a, laEvent *e){
  1376. if(!a->This || !a->This->EndInstance){ return 0; }
  1377. laCanvasExtra* ex=a->This->EndInstance; tnsCamera*c=ex->ViewingCamera; laUiItem* ui=ex->ParentUi;
  1378. tnsObject*root=ui?ui->PP.EndInstance:0; if(!root) return LA_CANCELED;
  1379. tnsMeshObject* mo=root->Active; int ran=0;
  1380. if(!mo || mo->Base.Type!=TNS_OBJECT_MESH || mo->Mode!=TNS_MESH_EDIT_MODE){ return LA_CANCELED; }
  1381. MSelectExtra* se=memAcquire(sizeof(MSelectExtra));
  1382. MSelectData* sd=la_InitSelectData(ex->OffScr->pColor[0]->Width, ex->OffScr->pColor[0]->Height, c);
  1383. a->CustomData=se; se->sd=sd; se->root=root;
  1384. int SelectMode=LA_CANVAS_SELECT_MODE_KNIFE;
  1385. if(strSame(strGetArgumentString(a->ExtraInstructionsP, "mode"), "loop_cut")){
  1386. se->IsLoop=1; SelectMode=LA_CANVAS_SELECT_MODE_EDGES; }
  1387. la_PopulateSelectDataPrimitives(sd,mo,c,SelectMode,ex->SelectThrough);
  1388. if(se->IsLoop){ strSafePrint(&a->RuntimeHint,"◧ Cut ◨ Cancel"); }
  1389. else{ strSafePrint(&a->RuntimeHint,"◧ Place Cut ◨ Cancel ⮨ Confirm"); }
  1390. return LA_RUNNING;
  1391. }
  1392. int OPMOD_Knife(laOperator *a, laEvent *e){
  1393. if(!a->This || !a->This->EndInstance || !a->CustomData){ return 0; }
  1394. laCanvasExtra* ex=a->This->EndInstance; tnsCamera*c=ex->ViewingCamera; laUiItem* ui=ex->ParentUi;
  1395. tnsObject*root=ui?ui->PP.EndInstance:0; if(!root) return 0;
  1396. MSelectExtra* se=a->CustomData;
  1397. tnsMeshObject* mo=root->Active;
  1398. int changed=0;
  1399. if(e->Type==LA_R_MOUSE_DOWN || (e->Type == LA_KEY_DOWN && e->key==LA_KEY_ESCAPE)){
  1400. la_KnifeFinish(se,mo); laNotifyUsers("tns.world"); return LA_FINISHED;
  1401. }
  1402. if(e->Type&LA_MOUSE_EVENT){
  1403. int elemtype,id=la_SelectGetClosest(se->sd, e->x-ui->L, e->y-ui->U, LA_RH,&elemtype)-1;
  1404. void* p=la_SelectGetRef(se->sd,id,elemtype);
  1405. if(se->IsLoop){
  1406. if(se->PendingElem!=p){ changed=1; while(lstPopPointer(&se->KnifeElements));
  1407. se->PendingElem=p; la_KnifeRefreshLoopCuts(se, mo, se->PendingElem);
  1408. la_KnifeSortLoopCuts(se);
  1409. }
  1410. }else{
  1411. if(la_KnifeIsDuplicated(se,p)) p=0;
  1412. if(se->PendingElem!=p){ changed=1; }
  1413. se->PendingElem=p; se->PendingElemType=elemtype;
  1414. if(e->Type==LA_L_MOUSE_DOWN && p){ la_KnifeAppendCut(se); changed=1; }
  1415. }
  1416. }
  1417. if((e->Type==LA_KEY_DOWN && e->key==LA_KEY_ENTER) || (se->IsLoop && e->Type==LA_L_MOUSE_DOWN)){
  1418. if(la_KnifeRegisterCuts(se,mo,se->IsLoop)){ tnsMMeshEnsureSelection(mo,ex->SelectMode);
  1419. tnsInvalidateMeshBatch(mo); laNotifyUsers("tns.world");
  1420. laRecordAndPush(0,"tns.world",se->IsLoop?"Loop Cut":"Knife Cut",TNS_HINT_GEOMETRY);
  1421. }
  1422. la_KnifeFinish(se,mo); return LA_FINISHED;
  1423. }
  1424. if(changed){
  1425. la_KnifeUpdateToolBatch(se,mo); laRedrawCurrentPanel();
  1426. }
  1427. return LA_RUNNING;
  1428. }
  1429. #define LA_MERGE_MODE_CENTER 0
  1430. #define LA_MERGE_MODE_FIRST 1
  1431. #define LA_MERGE_MODE_LAST 2
  1432. int la_MergeGetCenter(tnsMeshObject* mo, int SelectMode, int MergeMode, real* center){
  1433. real pos[3]={0},tmp[3]={0}; int count=0;
  1434. tnsMVert* usev=0; tnsMEdge* usee=0;
  1435. if(MergeMode!=LA_MERGE_MODE_CENTER){
  1436. if(MergeMode==LA_MERGE_MODE_FIRST){ usev=mo->FirstSelectV; usee=mo->FirstSelectE; }
  1437. elif(MergeMode==LA_MERGE_MODE_LAST){ usev=mo->LastSelectV; usee=mo->LastSelectE; }
  1438. if(SelectMode==LA_CANVAS_SELECT_MODE_VERTS && usev){ tnsVectorCopy3d(usev->p,center); return 1; }
  1439. elif(SelectMode==LA_CANVAS_SELECT_MODE_EDGES && usee){
  1440. tnsVectorAccum3d(pos,usee->vl->p);tnsVectorAccum3d(pos,usee->vr->p);
  1441. tnsVectorMultiSelf3d(pos,0.5f); tnsVectorCopy3d(pos,center); return 1;
  1442. }
  1443. }
  1444. for(tnsMVert* mv=mo->mv.pFirst;mv;mv=mv->Item.pNext){ if(!(mv->flags&TNS_MESH_FLAG_SELECTED)) continue;
  1445. tnsVectorAccum3d(pos,mv->p); count++;
  1446. }
  1447. if(!count) return 0;
  1448. tnsVectorMultiSelf3d(pos,1.0f/count); tnsVectorCopy3d(pos,center);
  1449. return 1;
  1450. }
  1451. void la_MergeSelected(tnsMeshObject* mo, real* center, int* count_success, int* count_fail){
  1452. tnsMVert* fmv=0,*NextMv=0; int success=0,fail=0,has_success=0;
  1453. do{ fail=0; has_success=0;
  1454. for(tnsMVert* mv=mo->mv.pFirst;mv;mv=NextMv){ NextMv=mv->Item.pNext;
  1455. if((!(mv->flags&TNS_MESH_FLAG_SELECTED))||mv==fmv) continue; if(!fmv){ fmv=mv; success++; continue; }
  1456. if(tnsMMeshMergeVerts(mo,fmv,mv)){ success++; has_success=1; }else{ fail++; }
  1457. }
  1458. }while(has_success&&fail);
  1459. if(count_success){ *count_success=success; } if(count_fail){ *count_fail=fail; }
  1460. if(!fmv) return; tnsVectorCopy3d(center,fmv->p);
  1461. tnsMMeshRefreshIndex(mo);
  1462. }
  1463. int OPINV_Merge(laOperator *a, laEvent *e){
  1464. if(!a->This || !a->This->EndInstance){ return 0; }
  1465. laCanvasExtra* ex=a->This->EndInstance; tnsCamera*c=ex->ViewingCamera; laUiItem* ui=ex->ParentUi;
  1466. tnsObject*root=ui?ui->PP.EndInstance:0; if(!root) return LA_CANCELED;
  1467. tnsMeshObject* mo=root->Active; int ran=0;
  1468. if(!mo || mo->Base.Type!=TNS_OBJECT_MESH || mo->Mode!=TNS_MESH_EDIT_MODE){ return LA_CANCELED; }
  1469. char* arg=strGetArgumentString(a->ExtraInstructionsP, "towards");
  1470. if(arg){
  1471. int MergeMode=LA_MERGE_MODE_CENTER; real center[3];
  1472. if(strSame(arg,"FIRST")){ MergeMode=LA_MERGE_MODE_FIRST; }
  1473. elif(strSame(arg,"LAST")){ MergeMode=LA_MERGE_MODE_LAST; }
  1474. if(!(la_MergeGetCenter(mo,ex->SelectMode,MergeMode,center))){
  1475. laEnableMessagePanel(a, 0, "Can't perform merging:", "No vertices selected.", e->x, e->y, 0, e);
  1476. return LA_FINISHED;
  1477. }
  1478. int success,fail;
  1479. la_MergeSelected(mo,center,&success,&fail); //printf("succeeded: %d failed:%d\n",success,fail);
  1480. if(fail){
  1481. char* msg[256]; sprintf(msg,"Succeeded: %d vertices, failed: %d vertices.",success,fail);
  1482. laEnableMessagePanel(a, 0, "Merging partially succeeded.", msg, e->x, e->y, 0, e);
  1483. }
  1484. if(success){
  1485. tnsMMeshEnsureSelection(mo,ex->SelectMode); tnsInvalidateMeshBatch(mo); laNotifyUsers("tns.world");
  1486. laRecordAndPush(0,"tns.world","Merge vertices",TNS_HINT_GEOMETRY);
  1487. }
  1488. }else{
  1489. laEnableOperatorPanel(a,a->This,e->x,e->y,200,200,0,0,0,0,0,0,0,0,e); return LA_RUNNING;
  1490. }
  1491. return LA_FINISHED;
  1492. }
  1493. void laui_Merge(laUiList *uil, laPropPack *pp, laPropPack *actinst, laColumn *extracol, int context){
  1494. laColumn* c=laFirstColumn(uil);
  1495. laShowItemFull(uil,c,pp,"_this_M_merge",0,"towards=CENTER;text=Center",0,0);
  1496. laShowItemFull(uil,c,pp,"_this_M_merge",0,"towards=FIRST;text=First",0,0);
  1497. laShowItemFull(uil,c,pp,"_this_M_merge",0,"towards=LAST;text=Last",0,0);
  1498. }
  1499. int OPINV_NewRootObject(laOperator *a, laEvent *e){
  1500. tnsCreateRootObject("Root"); laNotifyUsers("tns.world.root_objects"); laNotifyUsers("tns.world.active_root");
  1501. return LA_FINISHED;
  1502. }
  1503. int OPCHK_RemoveRootObjects(laPropPack *This, laStringSplitor *ss){
  1504. if(This && This->EndInstance){
  1505. if(la_EnsureSubTarget(This->LastPs->p,0)!=TNS_PC_OBJECT_GENERIC) return 0;
  1506. if(((tnsObject*)This->EndInstance)->Type!=TNS_OBJECT_ROOT) return 0;
  1507. }else{ if(!T->World->ActiveRoot) return 0; }
  1508. return 1;
  1509. }
  1510. int OPINV_RemoveRootObject(laOperator *a, laEvent *e){
  1511. if(a->This && a->This->EndInstance){ tnsDestroyRootObject(a->This->EndInstance); }
  1512. else{ tnsDestroyRootObject(T->World->ActiveRoot); }
  1513. laNotifyUsers("tns.world.root_objects"); laNotifyUsers("tns.world.active_root");
  1514. return LA_FINISHED;
  1515. }
  1516. void la_RegisterModellingOperators(){
  1517. laPropContainer *pc; laProp *p;
  1518. laOperatorType *at; laEnumProp *ep;
  1519. laCreateOperatorType("M_new_root", "New Root", "Create a new root object", 0, 0, 0, OPINV_NewRootObject, 0, '+', 0);
  1520. laCreateOperatorType("M_remove_root", "Remove Root", "Remove root object", OPCHK_RemoveRootObjects, 0, 0, OPINV_RemoveRootObject, 0 ,L'🗴', 0);
  1521. laCreateOperatorType("M_set_cursor", "Set Cursor", "Set cursor in the viewport", OPCHK_ViewportAndSceneExists, 0, 0, OPINV_SetCursor, 0, 0, LA_EXTRA_TO_PANEL);
  1522. laCreateOperatorType("M_toggle_edit_mode", "Toggle Edit Mode", "Toggle edit mode of the active object", OPCHK_ThereIsActiveObject, 0, 0, OPINV_ToggleEdit, 0, 0, 0);
  1523. laCreateOperatorType("M_select", "Select", "Select things in the viewport", OPCHK_ViewportAndSceneExists, 0, 0, OPINV_Select, OPMOD_Select, 0, LA_EXTRA_TO_PANEL);
  1524. laCreateOperatorType("M_grab", "Grab", "Grab things and move around", OPCHK_ViewportAndSceneExists, 0, 0, OPINV_Grab, OPMOD_Transformation, 0, LA_EXTRA_TO_PANEL);
  1525. laCreateOperatorType("M_scale", "Scale", "Scale selected things", OPCHK_ViewportAndSceneExists, 0, 0, OPINV_Scale, OPMOD_Transformation, 0, LA_EXTRA_TO_PANEL);
  1526. laCreateOperatorType("M_rotate", "Rotate", "Rotation selected things", OPCHK_ViewportAndSceneExists, 0, 0, OPINV_Rotate, OPMOD_Transformation, 0, LA_EXTRA_TO_PANEL);
  1527. at=laCreateOperatorType("M_clear_transformations", "Clear Transformations", "Clear object transformations", 0, 0, 0, OPINV_ClearTransformation, OPMOD_FinishOnData, 0, 0);
  1528. at->UiDefine=laui_ClearTransformation;
  1529. at=laCreateOperatorType("M_make_parent", "Make Parent", "Parent objects to active objects or unparent selected ones", 0, 0, 0, OPINV_MakeParent, OPMOD_FinishOnData, 0, 0);
  1530. at->UiDefine = laui_MakeParent;
  1531. at=laCreateOperatorType("M_unparent", "Unparent", "Unparent selected objects", 0, 0, 0, OPINV_MakeParent, OPMOD_FinishOnData, 0, 0);
  1532. at->UiDefine = laui_Unparent;
  1533. laCreateOperatorType("M_extrude", "Extrude", "Extrude parts of the mesh", 0, 0, 0, OPINV_Extrude, OPMOD_Transformation, 0, 0);
  1534. at=laCreateOperatorType("M_delete", "Delete", "Delete parts of the mesh", 0, 0, 0, OPINV_Delete, OPMOD_FinishOnData, 0, 0);
  1535. at->UiDefine=laui_Delete;
  1536. laCreateOperatorType("M_make", "Make", "Make mesh primitive from selected ones", 0, 0, 0, OPINV_Make, 0, 0, 0);
  1537. laCreateOperatorType("M_subdiv", "Subdiv", "Subdivide edges", 0, 0, 0, OPINV_Subdiv, 0, 0, 0);
  1538. at=laCreateOperatorType("M_add", "Add", "Add mesh or primitives", 0, 0, 0, OPINV_Add, OPMOD_FinishOnData, 0, 0);
  1539. at->UiDefine=laui_Add; pc = laDefineOperatorProps(at, 2);
  1540. p=laAddEnumProperty(pc,"context","Context","Context of adding",0,0,0,0,0,offsetof(laObjectAddData,Context),0,0,0,0,0,0,0,0,0,0);
  1541. laAddEnumItemAs(p,"OBJECT","Object","Object context",LA_ADD_CTX_OBJECT,0);
  1542. laAddEnumItemAs(p,"MESH","Mesh","Mesh context",LA_ADD_CTX_MESH,0);
  1543. laCreateOperatorType("M_separate", "Separate", "Separate mesh parts", 0, 0, 0, OPINV_Separate, 0, 0, 0);
  1544. laCreateOperatorType("M_combine", "Combine", "Combine mesh objects", 0, 0, 0, OPINV_Combine, 0, 0, 0);
  1545. laCreateOperatorType("M_duplicate", "Duplicate", "Duplicate objects", 0, 0, 0, OPINV_Duplicate, OPMOD_Transformation, 0, 0);
  1546. laCreateOperatorType("M_recalculate_normals", "Recalculate Normals", "Recalculate normals", 0, 0, 0, OPINV_RecalculateNormals, 0, 0, 0);
  1547. laCreateOperatorType("M_knife", "Knife", "Cut through edges", OPCHK_ViewportAndSceneExists, 0, 0, OPINV_Knife, OPMOD_Knife, 0, LA_EXTRA_TO_PANEL);
  1548. at=laCreateOperatorType("M_merge", "Merge", "Merge vertices", OPCHK_ViewportAndSceneExists, 0, 0, OPINV_Merge, OPMOD_FinishOnData, 0, LA_EXTRA_TO_PANEL);
  1549. at->UiDefine=laui_Merge;
  1550. }