/* * LaGUI: A graphical application framework. * Copyright (C) 2022-2023 Wu Yiming * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "la_5.h" #include extern LA MAIN; extern tnsMain *T; tnsShape* tnsNewShape(tnsShapeObject* so){ tnsShape* s=memAcquireSimple(sizeof(tnsShape)); lstAppendItem(&so->Shapes,s); return s; } tnsSPoint* tnsNewSPoint(tnsShape* s,real x, real y,real ldx,real ldy, real rdx,real rdy){ tnsSPoint* sp=memAcquireSimple(sizeof(tnsSPoint)); tnsVectorSet2(sp->p,x,y); tnsVectorSet2(sp->dl,ldx,ldy); tnsVectorSet2(sp->dr,rdx,rdy); lstAppendItem(&s->Points,sp); return sp; } void tnsShapeRefreshIndex(tnsShapeObject* so){ u32bit i; for(tnsShape* s=so->Shapes.pFirst;s;s=s->Item.pNext){ for(tnsSPoint* sp=s->Points.pFirst;sp;sp=sp->Item.pNext){ sp->i=i; i++; } } } int tnsShapePointAnySelected(tnsShape* s){ for(tnsSPoint* sp=s->Points.pFirst;sp;sp=sp->Item.pNext){ if(sp->flags&TNS_MESH_FLAG_SELECTED) return 1; } return 0; } int tnsShapeAnySelected(tnsShapeObject* so){ for(tnsShape* s=so->Shapes.pFirst;s;s=s->Item.pNext){ if(tnsShapePointAnySelected(s)) return 1; } return 0; } void tnsShapeDeselectAll(tnsShapeObject* so){ for(tnsShape* s=so->Shapes.pFirst;s;s=s->Item.pNext){ for(tnsSPoint* sp=s->Points.pFirst;sp;sp=sp->Item.pNext){ sp->flags&=(~TNS_MESH_FLAG_SELECTED); } } } void tnsShapeSelectAll(tnsShapeObject* so){ for(tnsShape* s=so->Shapes.pFirst;s;s=s->Item.pNext){ for(tnsSPoint* sp=s->Points.pFirst;sp;sp=sp->Item.pNext){ sp->flags|=TNS_MESH_FLAG_SELECTED; } } } void tnsShapeSelectPoint(tnsShapeObject* so, tnsSPoint* sp, int select, int toggle){ if(!so) return; if(toggle) tnsShapeSelectPoint(so,sp,(sp->flags&TNS_MESH_FLAG_SELECTED?0:1),0); elif(select) sp->flags|=TNS_MESH_FLAG_SELECTED; else sp->flags&=(~TNS_MESH_FLAG_SELECTED); //if(!so->FirstSelectV) so->FirstSelectV=sp; so->LastSelectV=sp; } void tnsShapeSelectRingFrom(tnsShapeObject* so, tnsSPoint* sp, int select, int toggle){ int has_idle=0; laListHandle spl={sp->Item.pPrev,sp->Item.pNext}; while(spl.pFirst && ((laListItem*)spl.pFirst)->pPrev){ spl.pFirst=((laListItem*)spl.pFirst)->pPrev; } while(spl.pLast && ((laListItem*)spl.pLast)->pNext){ spl.pLast=((laListItem*)spl.pLast)->pNext; } if(toggle){ for(tnsSPoint* isp=spl.pFirst;isp;isp=isp->Item.pNext){ if(isp!=sp && (!(isp->flags&TNS_MESH_FLAG_SELECTED))) has_idle=1; if(has_idle){ break; } } if(has_idle){ select=1; }else{ select=0; } } for(tnsSPoint* isp=spl.pFirst;isp;isp=isp->Item.pNext){ if(select){ isp->flags|=TNS_MESH_FLAG_SELECTED; }else{ isp->flags&=(~TNS_MESH_FLAG_SELECTED); } } } void tnsShapeEnterEditMode(tnsShapeObject* so){ if(so->Mode==TNS_MESH_EDIT_MODE) return; so->Mode = TNS_MESH_EDIT_MODE; tnsInvalidateEvaluation(so); } void tnsShapeLeaveEditMode(tnsShapeObject* so){ if(so->Mode==TNS_MESH_OBJECT_MODE) return; so->Mode = TNS_MESH_OBJECT_MODE; tnsInvalidateEvaluation(so); } tnsShapeObject* tnsDuplicateShapeObject(tnsShapeObject* from){ if(from->Base.Type!=TNS_OBJECT_SHAPE) return 0; tnsShapeObject* to = memAcquireHyper(sizeof(tnsShapeObject)); tnsInitObjectBase(to, from->Base.ParentObject?from->Base.ParentObject:from->Base.InRoot, from->Base.Name->Ptr, TNS_OBJECT_SHAPE,0,0,0,0,0,0,0,0,1); tnsCopyObjectTransformationsLocal(to,from); tnsMaterialSlot* new_current=0; for(tnsMaterialSlot* ms=from->Materials.pFirst;ms;ms=ms->Item.pNext){ tnsMaterialSlot* nms=tnsNewMaterialSlot(to); nms->Index=ms->Index; memAssignRef(nms,&nms->Material,ms->Material); if(ms==from->CurrentMaterial) new_current=nms; } memAssignRef(to,&to->CurrentMaterial,new_current); if(!from->Shapes.pFirst){ return to; } for(tnsShape* s=from->Shapes.pFirst;s;s=s->Item.pNext){ tnsShape* ns=tnsNewShape(to); for(tnsSPoint* sp=s->Points.pFirst;sp;sp=sp->Item.pNext){ tnsSPoint* nsp=tnsNewSPoint(ns,sp->p[0],sp->p[1],sp->dl[0],sp->dl[1],sp->dr[0],sp->dr[1]); nsp->flags=sp->flags; } ns->flags=s->flags;ns->mat=s->mat; } return to; } void tnsInitShapeSquare(tnsShapeObject* so, real size){ tnsShape* s=tnsNewShape(so); tnsNewSPoint(s,-size,-size,0,0,0,0)->flags|=TNS_MESH_FLAG_SELECTED; tnsNewSPoint(s,-size,size,0,0,0,0)->flags|=TNS_MESH_FLAG_SELECTED; tnsNewSPoint(s,size,size,0,0,0,0)->flags|=TNS_MESH_FLAG_SELECTED; tnsNewSPoint(s,size,-size,0,0,0,0)->flags|=TNS_MESH_FLAG_SELECTED; tnsShapeRefreshIndex(so); } void tns_DrawShape(tnsShape* s, real* override_color, int DrawEdit, real PointScale){ if(!s->Points.pFirst) return; int HasSelection=0; NVGcontext* vg=MAIN.CurrentWindow->nvg; if(DrawEdit==2){ nvgShapeAntiAlias(vg,0); for(tnsSPoint* sp=s->Points.pFirst;sp;sp=sp->Item.pNext){ nvgBeginPath(vg); nvgCircle(vg,sp->p[0],sp->p[1],PointScale*1); real color[4]={0,0,0,1}; TNS_ID_TO_COLOR(color,sp->i+1); nvgFillColor(vg,nvgRGBAf(LA_COLOR4(color))); nvgFill(vg); } nvgShapeAntiAlias(vg,1); return; } nvgBeginPath(vg); tnsSPoint* sp1=s->Points.pFirst; nvgMoveTo(vg,sp1->p[0],sp1->p[1]); if(sp1->flags&TNS_MESH_FLAG_SELECTED){HasSelection=1;} for(tnsSPoint* sp=sp1->Item.pNext;sp;sp=sp->Item.pNext){ nvgLineTo(vg,sp->p[0],sp->p[1]); if(sp->flags&TNS_MESH_FLAG_SELECTED){HasSelection=1;} } nvgClosePath(vg); nvgFillColor(vg, override_color?nvgRGBAf(LA_COLOR4(override_color)):nvgRGBAf(0.8,0.8,0.8,1)); nvgFill(vg); if(DrawEdit){ tnsVector4d color; tnsVectorCopy4d(laAccentColor(LA_BT_VERTEX),color); real* ActiveColor=laAccentColor(LA_BT_SVERTEX); if(!HasSelection) color[3]*=0.4; nvgStrokeColor(vg,nvgRGBAf(LA_COLOR4(color))); nvgStrokeWidth(vg,PointScale*4); nvgStroke(vg); for(tnsSPoint* sp=s->Points.pFirst;sp;sp=sp->Item.pNext){ nvgBeginPath(vg); nvgCircle(vg,sp->p[0],sp->p[1],PointScale*5); nvgFillColor(vg,sp->flags&TNS_MESH_FLAG_SELECTED?nvgRGBAf(LA_COLOR4(ActiveColor)):nvgRGBAf(LA_COLOR4(color))); nvgFill(vg); } } } void tnsDrawShapeObjectShapes(tnsEvaluatedInstance* ei, la3DObjectDrawExtra* de, real* override_color, int DrawEdit){ tnsShapeObject* so=ei->Object; NVGcontext* vg=MAIN.CurrentWindow->nvg; real sca[3]; tnsExtractScale44d(ei->Mat,sca); real rot[3]; tnsExtractXYZEuler44d(ei->Mat,rot); nvgSave(vg); if(de->Is3D){ tnsVector4d pos; tnsApplyTransform44d(pos,de->mViewProj,&ei->Mat[12]); pos[0]/=pos[3]; pos[1]/=pos[3]; nvgTranslate(vg,pos[0]*de->W/2,pos[1]*de->H/2); nvgScale(vg,LA_RH*sca[0],LA_RH*sca[1]); nvgRotate(vg,rot[2]); }else{ nvgTranslate(vg,ei->Mat[12],-ei->Mat[13]); nvgScale(vg,sca[0],-sca[1]); nvgRotate(vg,rot[2]); } for(tnsShape*s=so->Shapes.pFirst;s;s=s->Item.pNext){ tns_DrawShape(s,override_color,DrawEdit?DrawEdit:(so->Mode==TNS_MESH_EDIT_MODE),de->PointScale/sca[0]); } nvgRestore(vg); } void tnsDrawShapeObject(tnsEvaluatedInstance* ei, la3DObjectDrawExtra* de){ tnsDrawShapeObjectShapes(ei,de,0,0); } void tnsDrawShapeObjectSelectionID(tnsEvaluatedInstance* ei, la3DObjectDrawExtra* de){ int i=ei->InstanceSelectionID; real color[4]={0,0,0,1}; TNS_ID_TO_COLOR(color,i); tnsDrawShapeObjectShapes(ei,de,color,0); } void tnsDrawShapePointsSelectionID(tnsEvaluatedInstance* ei, la3DObjectDrawExtra* de){ tnsDrawShapeObjectShapes(ei,de,0,2); } void tnsDrawShapeObjectOverlay(tnsEvaluatedInstance* ei, la3DObjectDrawExtra* de){ int i=ei->InstanceSelectionID; real color[4]; tnsVectorCopy4d(laAccentColor(LA_BT_ACTIVE),color); if(ei->Object!=ei->Object->InRoot->Active){ color[3]=0.4; }else{ color[3]=0.7; } tnsDrawShapeObjectShapes(ei,de,color,0); } void tnsEvaluateShapeObject(tnsShapeObject* so, tnsEvaluateData* ed){ int DrawTo=TNS_EVAL_LAYER_SOLID; if(so->Backdrop){ DrawTo=TNS_EVAL_LAYER_BACKDROP; } tnsAddEvaluatedInstance(ed,so,tnsDrawShapeObject,DrawTo,0,0,0); if(ed->FillSelectionID){ tnsAddEvaluatedInstance(ed,so,tnsDrawShapeObjectSelectionID,TNS_EVAL_LAYER_SELECTION,0,1,so->Base.SelectID); } if(ed->FillOutline && (!ed->OverrideID)){ if((so->Base.Flags&TNS_OBJECT_FLAGS_SELECTED) && (so->Mode!=TNS_MESH_EDIT_MODE)){ tnsAddEvaluatedInstance(ed,so,tnsDrawShapeObjectOverlay,TNS_EVAL_LAYER_OVERLAY,0,0,0); } } } tnsShapeObject *tnsCreateShapeEmpty(tnsObject *under, char *Name, real AtX, real AtY, real AtZ){ tnsShapeObject *so = memAcquireHyper(sizeof(tnsShapeObject)); tnsInitObjectBase(&so->Base, under, Name, TNS_OBJECT_SHAPE, AtX, AtY, AtZ, 0, 0, 0, 1.0f, TNS_ROTATION_XYZ_EULER, 1.0f); return so; } tnsShapeObject *tnsCreateShapeSquare(tnsObject *under, char *Name, real AtX, real AtY, real AtZ, real size){ tnsShapeObject *so=tnsCreateShapeEmpty(under, Name, AtX, AtY, AtZ); tnsInitShapeSquare(so, size); return so; }