Add user interface to specify union/difference for extrudes, and
implement that. Also make solver work only between the first and last visible group; earlier can just work from previous solve result, and later don't matter. There's some issues with the csg code; it will eventually produce an open mesh, which is very bad. Not sure whether that's a logic bug, or a numerical issue; still generating absurd triangles pretty routinely. [git-p4: depot-paths = "//depot/solvespace/": change = 1741]
This commit is contained in:
parent
1909d4c520
commit
248f74547e
|
@ -276,7 +276,7 @@ void Constraint::MenuConstrain(int id) {
|
|||
break;
|
||||
|
||||
case GraphicsWindow::MNU_SOLVE_NOW:
|
||||
SS.GenerateAll(true);
|
||||
SS.GenerateAll(true, 0, 10000);
|
||||
return;
|
||||
|
||||
case GraphicsWindow::MNU_SOLVE_AUTO:
|
||||
|
|
|
@ -83,7 +83,7 @@ void Constraint::DrawOrGetDistance(Vector *labelPos) {
|
|||
Vector gu = SS.GW.projUp.ScaledBy(1/SS.GW.scale);
|
||||
Vector gn = (gr.Cross(gu)).WithMagnitude(1/SS.GW.scale);
|
||||
|
||||
glxColor3d(1, 0.2, 1);
|
||||
glxColor3d(1, 0.4, 1);
|
||||
switch(type) {
|
||||
case PT_PT_DISTANCE: {
|
||||
Vector ap = SS.GetEntity(ptA)->PointGetNum();
|
||||
|
|
1
file.cpp
1
file.cpp
|
@ -51,6 +51,7 @@ const SolveSpace::SaveTable SolveSpace::SAVED[] = {
|
|||
{ 'g', "Group.opA.v", 'x', &(SS.sv.g.opA.v) },
|
||||
{ 'g', "Group.opB.v", 'x', &(SS.sv.g.opB.v) },
|
||||
{ 'g', "Group.subtype", 'd', &(SS.sv.g.subtype) },
|
||||
{ 'g', "Group.meshCombine", 'd', &(SS.sv.g.meshCombine) },
|
||||
{ 'g', "Group.wrkpl.q.w", 'f', &(SS.sv.g.wrkpl.q.w) },
|
||||
{ 'g', "Group.wrkpl.q.vx", 'f', &(SS.sv.g.wrkpl.q.vx) },
|
||||
{ 'g', "Group.wrkpl.q.vy", 'f', &(SS.sv.g.wrkpl.q.vy) },
|
||||
|
|
|
@ -102,12 +102,19 @@ void GraphicsWindow::Init(void) {
|
|||
projRight.x = 1; projRight.y = projRight.z = 0;
|
||||
projUp.y = 1; projUp.z = projUp.x = 0;
|
||||
|
||||
EnsureValidActives();
|
||||
|
||||
// Start locked on to the XY plane.
|
||||
hRequest r = Request::HREQUEST_REFERENCE_XY;
|
||||
activeWorkplane = r.entity(0);
|
||||
|
||||
// And with the latest visible group active
|
||||
int i;
|
||||
for(i = 0; i < SS.group.n; i++) {
|
||||
Group *g = &(SS.group.elem[i]);
|
||||
if(g->visible) activeGroup = g->h;
|
||||
}
|
||||
|
||||
EnsureValidActives();
|
||||
|
||||
showWorkplanes = true;
|
||||
showNormals = true;
|
||||
showPoints = true;
|
||||
|
@ -1144,11 +1151,10 @@ void GraphicsWindow::Paint(int w, int h) {
|
|||
glxUnlockColor();
|
||||
|
||||
int i, a;
|
||||
// Draw the groups; this fills the polygons, if requested.
|
||||
// Draw the groups; this fills the polygons in a drawing group, and
|
||||
// draws the solid mesh.
|
||||
if(showSolids) {
|
||||
for(i = 0; i < SS.group.n; i++) {
|
||||
SS.group.elem[i].Draw();
|
||||
}
|
||||
(SS.GetGroup(activeGroup))->Draw();
|
||||
}
|
||||
|
||||
// First, draw the entire scene. We don't necessarily want to draw
|
||||
|
@ -1180,35 +1186,5 @@ void GraphicsWindow::Paint(int w, int h) {
|
|||
for(i = 0; i < MAX_SELECTED; i++) {
|
||||
selection[i].Draw();
|
||||
}
|
||||
|
||||
if(SS.group.n >= 5) {
|
||||
SMesh *ma = &(SS.group.elem[2].mesh);
|
||||
SMesh *mb = &(SS.group.elem[4].mesh);
|
||||
|
||||
SBsp3 *pa = SBsp3::FromMesh(ma);
|
||||
SBsp3 *pb = SBsp3::FromMesh(mb);
|
||||
|
||||
SMesh br; ZERO(&br);
|
||||
br.flipNormal = true;
|
||||
br.keepCoplanar = false;
|
||||
br.AddAgainstBsp(mb, pa);
|
||||
|
||||
br.flipNormal = false;
|
||||
br.keepCoplanar = false;
|
||||
br.AddAgainstBsp(ma, pb);
|
||||
|
||||
dbp("triangles in = %d %d out = %d", ma->l.n, mb->l.n, br.l.n);
|
||||
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
glEnable(GL_LIGHTING);
|
||||
glxFillMesh(&br);
|
||||
glDisable(GL_LIGHTING);
|
||||
glxLockColorTo(0, 1, 0);
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
glxDebugMesh(&br);
|
||||
|
||||
br.Clear();
|
||||
FreeAllTemporary();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
28
mesh.cpp
28
mesh.cpp
|
@ -51,6 +51,7 @@ void SMesh::GetBounding(Vector *vmax, Vector *vmin) {
|
|||
|
||||
void SMesh::AddAgainstBsp(SMesh *srcm, SBsp3 *bsp3) {
|
||||
int i;
|
||||
|
||||
for(i = 0; i < srcm->l.n; i++) {
|
||||
STriangle *st = &(srcm->l.elem[i]);
|
||||
int pn = l.n;
|
||||
|
@ -68,6 +69,32 @@ void SMesh::AddAgainstBsp(SMesh *srcm, SBsp3 *bsp3) {
|
|||
}
|
||||
}
|
||||
|
||||
void SMesh::MakeFromUnion(SMesh *a, SMesh *b) {
|
||||
SBsp3 *bspa = SBsp3::FromMesh(a);
|
||||
SBsp3 *bspb = SBsp3::FromMesh(b);
|
||||
|
||||
flipNormal = false;
|
||||
keepCoplanar = false;
|
||||
AddAgainstBsp(b, bspa);
|
||||
|
||||
flipNormal = false;
|
||||
keepCoplanar = true;
|
||||
AddAgainstBsp(a, bspb);
|
||||
}
|
||||
|
||||
void SMesh::MakeFromDifference(SMesh *a, SMesh *b) {
|
||||
SBsp3 *bspa = SBsp3::FromMesh(a);
|
||||
SBsp3 *bspb = SBsp3::FromMesh(b);
|
||||
|
||||
flipNormal = true;
|
||||
keepCoplanar = false;
|
||||
AddAgainstBsp(b, bspa);
|
||||
|
||||
flipNormal = false;
|
||||
keepCoplanar = false;
|
||||
AddAgainstBsp(a, bspb);
|
||||
}
|
||||
|
||||
SBsp2 *SBsp2::Alloc(void) { return (SBsp2 *)AllocTemporary(sizeof(SBsp2)); }
|
||||
SBsp3 *SBsp3::Alloc(void) { return (SBsp3 *)AllocTemporary(sizeof(SBsp3)); }
|
||||
|
||||
|
@ -153,7 +180,6 @@ alt:
|
|||
} else {
|
||||
// I suppose this actually is allowed to happen, if the coplanar
|
||||
// face is the leaf, and all of its neighbors are earlier in tree?
|
||||
dbp("insert in plane");
|
||||
InsertInPlane(false, tr, instead);
|
||||
}
|
||||
} else {
|
||||
|
|
|
@ -178,6 +178,8 @@ public:
|
|||
void GetBounding(Vector *vmax, Vector *vmin);
|
||||
|
||||
void AddAgainstBsp(SMesh *srcm, SBsp3 *bsp3);
|
||||
void MakeFromUnion(SMesh *a, SMesh *b);
|
||||
void MakeFromDifference(SMesh *a, SMesh *b);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
77
sketch.cpp
77
sketch.cpp
|
@ -381,15 +381,27 @@ void Group::CopyEntity(hEntity in, int a, hParam dx, hParam dy, hParam dz,
|
|||
SS.entity.Add(&en);
|
||||
}
|
||||
|
||||
void Group::MakePolygons(void) {
|
||||
SMesh *Group::PreviousGroupMesh(void) {
|
||||
int i;
|
||||
for(i = 0; i < SS.group.n; i++) {
|
||||
Group *g = &(SS.group.elem[i]);
|
||||
if(g->h.v == h.v) break;
|
||||
}
|
||||
if(i == 0 || i >= SS.group.n) oops();
|
||||
return &(SS.group.elem[i-1].mesh);
|
||||
}
|
||||
|
||||
void Group::MakePolygons(void) {
|
||||
poly.Clear();
|
||||
mesh.Clear();
|
||||
|
||||
SEdgeList edges;
|
||||
ZERO(&edges);
|
||||
SMesh outm;
|
||||
ZERO(&outm);
|
||||
|
||||
if(type == DRAWING_3D || type == DRAWING_WORKPLANE) {
|
||||
if(type == DRAWING_3D || type == DRAWING_WORKPLANE ||
|
||||
type == ROTATE || type == TRANSLATE)
|
||||
{
|
||||
int i;
|
||||
for(i = 0; i < SS.entity.n; i++) {
|
||||
Entity *e = &(SS.entity.elem[i]);
|
||||
|
@ -427,7 +439,6 @@ void Group::MakePolygons(void) {
|
|||
SMesh srcm; ZERO(&srcm);
|
||||
(src->poly).TriangulateInto(&srcm);
|
||||
|
||||
SMesh outm; ZERO(&outm);
|
||||
// Do the bottom; that has normal pointing opposite from translate
|
||||
for(i = 0; i < srcm.l.n; i++) {
|
||||
STriangle *st = &(srcm.l.elem[i]);
|
||||
|
@ -435,9 +446,9 @@ void Group::MakePolygons(void) {
|
|||
bt = (st->b).Plus(tbot),
|
||||
ct = (st->c).Plus(tbot);
|
||||
if(flipBottom) {
|
||||
mesh.AddTriangle(ct, bt, at);
|
||||
outm.AddTriangle(ct, bt, at);
|
||||
} else {
|
||||
mesh.AddTriangle(at, bt, ct);
|
||||
outm.AddTriangle(at, bt, ct);
|
||||
}
|
||||
}
|
||||
// And the top; that has the normal pointing the same dir as translate
|
||||
|
@ -447,9 +458,9 @@ void Group::MakePolygons(void) {
|
|||
bt = (st->b).Plus(ttop),
|
||||
ct = (st->c).Plus(ttop);
|
||||
if(flipBottom) {
|
||||
mesh.AddTriangle(at, bt, ct);
|
||||
outm.AddTriangle(at, bt, ct);
|
||||
} else {
|
||||
mesh.AddTriangle(ct, bt, at);
|
||||
outm.AddTriangle(ct, bt, at);
|
||||
}
|
||||
}
|
||||
srcm.Clear();
|
||||
|
@ -463,26 +474,50 @@ void Group::MakePolygons(void) {
|
|||
Vector abot = (edge->a).Plus(tbot), bbot = (edge->b).Plus(tbot);
|
||||
Vector atop = (edge->a).Plus(ttop), btop = (edge->b).Plus(ttop);
|
||||
if(flipBottom) {
|
||||
mesh.AddTriangle(bbot, abot, atop);
|
||||
mesh.AddTriangle(bbot, atop, btop);
|
||||
outm.AddTriangle(bbot, abot, atop);
|
||||
outm.AddTriangle(bbot, atop, btop);
|
||||
} else {
|
||||
mesh.AddTriangle(abot, bbot, atop);
|
||||
mesh.AddTriangle(bbot, btop, atop);
|
||||
outm.AddTriangle(abot, bbot, atop);
|
||||
outm.AddTriangle(bbot, btop, atop);
|
||||
}
|
||||
}
|
||||
}
|
||||
edges.Clear();
|
||||
|
||||
// So our group's mesh appears in outm. Combine this with the previous
|
||||
// group's mesh, using the requested operation.
|
||||
mesh.Clear();
|
||||
SMesh *a = PreviousGroupMesh();
|
||||
if(meshCombine == COMBINE_AS_UNION) {
|
||||
mesh.MakeFromUnion(a, &outm);
|
||||
} else {
|
||||
mesh.MakeFromDifference(a, &outm);
|
||||
}
|
||||
outm.Clear();
|
||||
}
|
||||
|
||||
void Group::Draw(void) {
|
||||
if(!visible) return;
|
||||
// Show this even if the group is not visible. It's already possible
|
||||
// to show or hide just this with the "show solids" flag.
|
||||
|
||||
|
||||
GLfloat mpf[] = { 0.4f, 0.4f, 0.4f, 1.0 };
|
||||
glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, mpf);
|
||||
if(type == DRAWING_3D || type == DRAWING_WORKPLANE) {
|
||||
GLfloat mpf[] = { 0.1f, 0.1f, 0.1f, 1.0 };
|
||||
glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, mpf);
|
||||
} else {
|
||||
GLfloat mpf[] = { 0.3f, 0.3f, 0.3f, 1.0 };
|
||||
glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, mpf);
|
||||
}
|
||||
// The back faces are drawn in red; should never seem them, since we
|
||||
// draw closed shells, so that's a debugging aid.
|
||||
GLfloat mpb[] = { 1.0f, 0.1f, 0.1f, 1.0 };
|
||||
glMaterialfv(GL_BACK, GL_AMBIENT_AND_DIFFUSE, mpb);
|
||||
|
||||
glEnable(GL_LIGHTING);
|
||||
glxFillMesh(&mesh);
|
||||
glDisable(GL_LIGHTING);
|
||||
|
||||
// glxDebugMesh(&mesh);
|
||||
|
||||
if(polyError.yes) {
|
||||
glxColor4d(1, 0, 0, 0.2);
|
||||
glLineWidth(10);
|
||||
|
@ -498,13 +533,11 @@ void Group::Draw(void) {
|
|||
glxWriteText("not closed contour!");
|
||||
glPopMatrix();
|
||||
} else {
|
||||
// glxFillPolygon(&poly);
|
||||
glxColor4d(0, 1.0, 1.0, 0.1);
|
||||
glPolygonOffset(-1, -1);
|
||||
glxFillPolygon(&poly);
|
||||
glPolygonOffset(0, 0);
|
||||
}
|
||||
glEnable(GL_LIGHTING);
|
||||
// glxFillMesh(&mesh);
|
||||
glDisable(GL_LIGHTING);
|
||||
|
||||
// glxDebugMesh(&mesh);
|
||||
}
|
||||
|
||||
hParam Request::AddParam(IdList<Param,hParam> *param, hParam hp) {
|
||||
|
|
7
sketch.h
7
sketch.h
|
@ -84,8 +84,6 @@ public:
|
|||
static const int TRANSLATE = 5030;
|
||||
int type;
|
||||
|
||||
bool solved;
|
||||
|
||||
hGroup opA;
|
||||
hGroup opB;
|
||||
bool visible;
|
||||
|
@ -113,6 +111,10 @@ public:
|
|||
} polyError;
|
||||
SMesh mesh;
|
||||
|
||||
static const int COMBINE_AS_UNION = 0;
|
||||
static const int COMBINE_AS_DIFFERENCE = 1;
|
||||
int meshCombine;
|
||||
|
||||
NameStr name;
|
||||
char *DescriptionString(void);
|
||||
|
||||
|
@ -131,6 +133,7 @@ public:
|
|||
|
||||
void GenerateEquations(IdList<Equation,hEquation> *l);
|
||||
|
||||
SMesh *PreviousGroupMesh(void);
|
||||
void MakePolygons(void);
|
||||
void Draw(void);
|
||||
|
||||
|
|
|
@ -9,11 +9,11 @@ void SolveSpace::Init(char *cmdLine) {
|
|||
LoadFromFile(cmdLine);
|
||||
}
|
||||
|
||||
GenerateAll(false, 0, INT_MAX);
|
||||
|
||||
TW.Init();
|
||||
GW.Init();
|
||||
|
||||
GenerateAll(false);
|
||||
|
||||
TW.Show();
|
||||
}
|
||||
|
||||
|
@ -122,6 +122,21 @@ bool SolveSpace::PruneConstraints(hGroup hg) {
|
|||
}
|
||||
|
||||
void SolveSpace::GenerateAll(bool andSolve) {
|
||||
int i;
|
||||
int firstShown = INT_MAX, lastShown = 0;
|
||||
// The references don't count, so start from group 1
|
||||
for(i = 1; i < group.n; i++) {
|
||||
if(group.elem[i].visible) {
|
||||
firstShown = min(firstShown, i);
|
||||
lastShown = max(lastShown, i);
|
||||
}
|
||||
}
|
||||
// Even if nothing is shown, we have to keep going; the entities get
|
||||
// generated for hidden groups, even though they're not solved.
|
||||
GenerateAll(andSolve, firstShown, lastShown);
|
||||
}
|
||||
|
||||
void SolveSpace::GenerateAll(bool andSolve, int first, int last) {
|
||||
int i, j;
|
||||
|
||||
while(PruneOrphans())
|
||||
|
@ -132,12 +147,6 @@ void SolveSpace::GenerateAll(bool andSolve) {
|
|||
param.MoveSelfInto(&prev);
|
||||
entity.Clear();
|
||||
|
||||
for(i = 0; i < group.n; i++) {
|
||||
group.elem[i].solved = false;
|
||||
}
|
||||
|
||||
// For now, solve the groups in given order; should discover the
|
||||
// correct order later.
|
||||
for(i = 0; i < group.n; i++) {
|
||||
Group *g = &(group.elem[i]);
|
||||
|
||||
|
@ -172,13 +181,24 @@ void SolveSpace::GenerateAll(bool andSolve) {
|
|||
|
||||
if(g->h.v == Group::HGROUP_REFERENCES.v) {
|
||||
ForceReferences();
|
||||
group.elem[0].solved = true;
|
||||
} else {
|
||||
// Solve this group.
|
||||
if(andSolve) SolveGroup(g->h);
|
||||
}
|
||||
if(i >= first && i <= last) {
|
||||
// The group falls inside the range, so really solve it,
|
||||
// and then regenerate the mesh based on the solved stuff.
|
||||
if(andSolve) SolveGroup(g->h);
|
||||
g->MakePolygons();
|
||||
} else {
|
||||
// The group falls outside the range, so just assume that
|
||||
// it's good wherever we left it. The mesh is unchanged,
|
||||
// and the parameters must be marked as known.
|
||||
for(j = 0; j < param.n; j++) {
|
||||
Param *newp = &(param.elem[j]);
|
||||
|
||||
g->MakePolygons();
|
||||
Param *prevp = prev.FindByIdNoOops(newp->h);
|
||||
if(prevp) newp->known = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
prev.Clear();
|
||||
|
@ -217,7 +237,7 @@ pruned:
|
|||
param.Clear();
|
||||
prev.MoveSelfInto(¶m);
|
||||
// Try again
|
||||
GenerateAll(andSolve);
|
||||
GenerateAll(andSolve, first, last);
|
||||
}
|
||||
|
||||
void SolveSpace::ForceReferences(void) {
|
||||
|
@ -299,8 +319,8 @@ void SolveSpace::MenuFile(int id) {
|
|||
case GraphicsWindow::MNU_NEW:
|
||||
SS.NewFile();
|
||||
SS.GenerateAll(false);
|
||||
SS.GW.Init();
|
||||
SS.TW.Init();
|
||||
SS.GW.Init();
|
||||
SS.TW.Show();
|
||||
break;
|
||||
|
||||
|
|
|
@ -229,6 +229,7 @@ public:
|
|||
bool PruneConstraints(hGroup hg);
|
||||
|
||||
void GenerateAll(bool andSolve);
|
||||
void GenerateAll(bool andSolve, int first, int last);
|
||||
bool SolveGroup(hGroup hg);
|
||||
void ForceReferences(void);
|
||||
|
||||
|
|
31
textwin.cpp
31
textwin.cpp
|
@ -266,6 +266,9 @@ void TextWindow::ScreenToggleGroupShown(int link, DWORD v) {
|
|||
hGroup hg = { v };
|
||||
Group *g = SS.GetGroup(hg);
|
||||
g->visible = !(g->visible);
|
||||
// If a group was just shown, then it might not have been generated
|
||||
// previously, so regenerate.
|
||||
SS.GW.GeneratePerSolving();
|
||||
}
|
||||
void TextWindow::ScreenShowGroupsSpecial(int link, DWORD v) {
|
||||
int i;
|
||||
|
@ -341,9 +344,19 @@ void TextWindow::ScreenChangeExtrudeSides(int link, DWORD v) {
|
|||
Group *g = SS.GetGroup(SS.TW.shown->group);
|
||||
if(g->subtype == Group::EXTRUDE_ONE_SIDED) {
|
||||
g->subtype = Group::EXTRUDE_TWO_SIDED;
|
||||
} else {
|
||||
} else if(g->subtype == Group::EXTRUDE_TWO_SIDED) {
|
||||
g->subtype = Group::EXTRUDE_ONE_SIDED;
|
||||
}
|
||||
} else oops();
|
||||
SS.GW.GeneratePerSolving();
|
||||
SS.GW.ClearSuper();
|
||||
}
|
||||
void TextWindow::ScreenChangeMeshCombine(int link, DWORD v) {
|
||||
Group *g = SS.GetGroup(SS.TW.shown->group);
|
||||
if(g->meshCombine == Group::COMBINE_AS_DIFFERENCE) {
|
||||
g->meshCombine = Group::COMBINE_AS_UNION;
|
||||
} else if(g->meshCombine == Group::COMBINE_AS_UNION) {
|
||||
g->meshCombine = Group::COMBINE_AS_DIFFERENCE;
|
||||
} else oops();
|
||||
SS.GW.GeneratePerSolving();
|
||||
SS.GW.ClearSuper();
|
||||
}
|
||||
|
@ -361,12 +374,18 @@ void TextWindow::ShowGroupInfo(void) {
|
|||
|
||||
if(g->type == Group::EXTRUDE) {
|
||||
bool one = (g->subtype == Group::EXTRUDE_ONE_SIDED);
|
||||
Printf(true, "%FtEXTRUDE%E one-sided: %Fh%f%Ll%s%E%Fs%s%E",
|
||||
Printf(true, "%FtEXTRUDE%E %Fh%f%Ll%s%E%Fs%s%E / %Fh%f%Ll%s%E%Fs%s%E",
|
||||
&TextWindow::ScreenChangeExtrudeSides,
|
||||
(one ? "" : "no"), (one ? "yes" : ""));
|
||||
Printf(false, " two-sided: %Fh%f%Ll%s%E%Fs%s%E",
|
||||
(one ? "" : "one side"), (one ? "one-side" : ""),
|
||||
&TextWindow::ScreenChangeExtrudeSides,
|
||||
(!one ? "" : "no"), (!one ? "yes" : ""));
|
||||
(!one ? "" : "two sides"), (!one ? "two sides" : ""));
|
||||
|
||||
bool diff = (g->meshCombine == Group::COMBINE_AS_DIFFERENCE);
|
||||
Printf(false, "%FtCOMBINE%E %Fh%f%Ll%s%E%Fs%s%E / %Fh%f%Ll%s%E%Fs%s%E",
|
||||
&TextWindow::ScreenChangeMeshCombine,
|
||||
(!diff ? "" : "as union"), (!diff ? "as union" : ""),
|
||||
&TextWindow::ScreenChangeMeshCombine,
|
||||
(diff ? "" : "as difference"), (diff ? "as difference" : ""));
|
||||
}
|
||||
|
||||
Printf(true, "%Ftrequests in group");
|
||||
|
|
1
ui.h
1
ui.h
|
@ -74,6 +74,7 @@ public:
|
|||
static void ScreenSelectRequest(int link, DWORD v);
|
||||
static void ScreenSelectConstraint(int link, DWORD v);
|
||||
static void ScreenChangeExtrudeSides(int link, DWORD v);
|
||||
static void ScreenChangeMeshCombine(int link, DWORD v);
|
||||
|
||||
static void ScreenNavigation(int link, DWORD v);
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue
Block a user