mirror of
https://github.com/processing/processing4.git
synced 2026-01-30 03:41:15 +01:00
removed first,last vertex and count from InGeometry, implementing vertex
codes
This commit is contained in:
@@ -186,9 +186,13 @@ public class PShapeOpenGL extends PShape {
|
||||
|
||||
// Bezier and Catmull-Rom curves
|
||||
|
||||
protected int bezierDetail = 20;
|
||||
protected int curveDetail = 20;
|
||||
protected float curveTightness = 0;
|
||||
protected int bezierDetail;
|
||||
protected int curveDetail;
|
||||
protected float curveTightness;
|
||||
|
||||
protected int savedBezierDetail;
|
||||
protected int savedCurveDetail;
|
||||
protected float savedCurveTightness;
|
||||
|
||||
// ........................................................
|
||||
|
||||
@@ -290,7 +294,7 @@ public class PShapeOpenGL extends PShape {
|
||||
|
||||
|
||||
public PShapeOpenGL(PApplet parent, int family) {
|
||||
pg = (PGraphicsOpenGL)parent.g;
|
||||
pg = PGraphicsOpenGL.pgCurrent;
|
||||
pgl = PGraphicsOpenGL.pgl;
|
||||
context = pgl.createEmptyContext();
|
||||
|
||||
@@ -321,7 +325,7 @@ public class PShapeOpenGL extends PShape {
|
||||
this.tessellated = false;
|
||||
|
||||
if (family == GEOMETRY || family == PRIMITIVE || family == PATH) {
|
||||
inGeo = pg.newInGeometry(PGraphicsOpenGL.RETAINED);
|
||||
inGeo = PGraphicsOpenGL.newInGeometry(pg, PGraphicsOpenGL.RETAINED);
|
||||
}
|
||||
|
||||
// Style parameters are retrieved from the current values in the renderer.
|
||||
@@ -356,6 +360,10 @@ public class PShapeOpenGL extends PShape {
|
||||
sphereDetailU = pg.sphereDetailU;
|
||||
sphereDetailV = pg.sphereDetailV;
|
||||
|
||||
bezierDetail = pg.bezierDetail;
|
||||
curveDetail = pg.curveDetail;
|
||||
curveTightness = pg.curveTightness;
|
||||
|
||||
// The rect and ellipse modes are set to CORNER since it is the expected
|
||||
// mode for svg shapes.
|
||||
rectMode = CORNER;
|
||||
@@ -1061,24 +1069,23 @@ public class PShapeOpenGL extends PShape {
|
||||
}
|
||||
|
||||
inGeo.addVertex(x, y, z,
|
||||
fcolor,
|
||||
normalX, normalY, normalZ,
|
||||
u, v,
|
||||
scolor, sweight,
|
||||
ambientColor, specularColor, emissiveColor, shininess,
|
||||
vertexCode());
|
||||
fcolor,
|
||||
normalX, normalY, normalZ,
|
||||
u, v,
|
||||
scolor, sweight,
|
||||
ambientColor, specularColor, emissiveColor, shininess,
|
||||
VERTEX, vertexBreak());
|
||||
|
||||
markForTessellation();
|
||||
}
|
||||
|
||||
|
||||
protected int vertexCode() {
|
||||
int code = VERTEX;
|
||||
protected boolean vertexBreak() {
|
||||
if (breakShape) {
|
||||
code = BREAK;
|
||||
breakShape = false;
|
||||
return true;
|
||||
}
|
||||
return code;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -1382,7 +1389,10 @@ public class PShapeOpenGL extends PShape {
|
||||
@Override
|
||||
public void bezierDetail(int detail) {
|
||||
bezierDetail = detail;
|
||||
pg.bezierDetail(detail);
|
||||
if (0 < inGeo.codeCount) {
|
||||
markForTessellation();
|
||||
}
|
||||
//pg.bezierDetail(detail); // setting the detail in the renderer, WTF??
|
||||
}
|
||||
|
||||
|
||||
@@ -1414,8 +1424,15 @@ public class PShapeOpenGL extends PShape {
|
||||
inGeo.setNormal(normalX, normalY, normalZ);
|
||||
inGeo.addBezierVertex(x2, y2, z2,
|
||||
x3, y3, z3,
|
||||
x4, y4, z4,
|
||||
fill, stroke, bezierDetail, vertexCode(), kind);
|
||||
x4, y4, z4, vertexBreak());
|
||||
|
||||
// inGeo.addVertex(x2, y2, z2, BEZIER_VERTEX, vertexBreak());
|
||||
// inGeo.addVertex(x3, y3, z3, BEZIER_VERTEX, false);
|
||||
// inGeo.addVertex(x4, y4, z4, BEZIER_VERTEX, false);
|
||||
//// inGeo.addBezierVertex(x2, y2, z2,
|
||||
// x3, y3, z3,
|
||||
// x4, y4, z4,
|
||||
// fill, stroke, bezierDetail, vertexCode(), kind);
|
||||
}
|
||||
|
||||
|
||||
@@ -1441,8 +1458,12 @@ public class PShapeOpenGL extends PShape {
|
||||
ambientColor, specularColor, emissiveColor, shininess);
|
||||
inGeo.setNormal(normalX, normalY, normalZ);
|
||||
inGeo.addQuadraticVertex(cx, cy, cz,
|
||||
x3, y3, z3,
|
||||
fill, stroke, bezierDetail, vertexCode(), kind);
|
||||
x3, y3, z3, vertexBreak());
|
||||
// inGeo.addVertex(cx, cy, cz, QUADRATIC_VERTEX, vertexBreak());
|
||||
// inGeo.addVertex(x3, y3, z3, QUADRATIC_VERTEX, false);
|
||||
// inGeo.addQuadraticVertex(cx, cy, cz,
|
||||
// x3, y3, z3,
|
||||
// fill, stroke, bezierDetail, vertexCode(), kind);
|
||||
}
|
||||
|
||||
|
||||
@@ -1456,14 +1477,20 @@ public class PShapeOpenGL extends PShape {
|
||||
@Override
|
||||
public void curveDetail(int detail) {
|
||||
curveDetail = detail;
|
||||
pg.curveDetail(detail);
|
||||
// pg.curveDetail(detail);
|
||||
if (0 < inGeo.codeCount) {
|
||||
markForTessellation();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void curveTightness(float tightness) {
|
||||
curveTightness = tightness;
|
||||
pg.curveTightness(tightness);
|
||||
// pg.curveTightness(tightness);
|
||||
if (0 < inGeo.codeCount) {
|
||||
markForTessellation();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1483,8 +1510,10 @@ public class PShapeOpenGL extends PShape {
|
||||
inGeo.setMaterial(fillColor, strokeColor, strokeWeight,
|
||||
ambientColor, specularColor, emissiveColor, shininess);
|
||||
inGeo.setNormal(normalX, normalY, normalZ);
|
||||
inGeo.addCurveVertex(x, y, z,
|
||||
fill, stroke, curveDetail, vertexCode(), kind);
|
||||
inGeo.addCurveVertex(x, y, z, vertexBreak());
|
||||
// inGeo.addVertex(x, y, z, CURVE_VERTEX, vertexBreak());
|
||||
// inGeo.addCurveVertex(x, y, z,
|
||||
// fill, stroke, curveDetail, vertexCode(), kind);
|
||||
}
|
||||
|
||||
|
||||
@@ -1856,7 +1885,7 @@ public class PShapeOpenGL extends PShape {
|
||||
} else if (this.stroke != stroke) {
|
||||
if (this.stroke) {
|
||||
// Disabling stroke on a shape previously with
|
||||
// stroke needs a re-tesellation in order to remove
|
||||
// stroke needs a re-tessellation in order to remove
|
||||
// the additional geometry of lines and/or points.
|
||||
markForTessellation();
|
||||
stroke = false;
|
||||
@@ -1977,7 +2006,7 @@ public class PShapeOpenGL extends PShape {
|
||||
root.setModifiedLineAttributes(firstLineVertex, lastLineVertex);
|
||||
} else if (is2D()) {
|
||||
// Changing the stroke weight on a 2D shape needs a
|
||||
// re-tesellation in order to replace the old line
|
||||
// re-tessellation in order to replace the old line
|
||||
// geometry.
|
||||
markForTessellation();
|
||||
}
|
||||
@@ -1991,7 +2020,7 @@ public class PShapeOpenGL extends PShape {
|
||||
root.setModifiedPointAttributes(firstPointVertex, lastPointVertex);
|
||||
} else if (is2D()) {
|
||||
// Changing the stroke weight on a 2D shape needs a
|
||||
// re-tesellation in order to replace the old point
|
||||
// re-tessellation in order to replace the old point
|
||||
// geometry.
|
||||
markForTessellation();
|
||||
}
|
||||
@@ -2027,7 +2056,7 @@ public class PShapeOpenGL extends PShape {
|
||||
} else {
|
||||
if (is2D() && strokeJoin != join) {
|
||||
// Changing the stroke join on a 2D shape needs a
|
||||
// re-tesellation in order to replace the old join
|
||||
// re-tessellation in order to replace the old join
|
||||
// geometry.
|
||||
markForTessellation();
|
||||
}
|
||||
@@ -2051,7 +2080,7 @@ public class PShapeOpenGL extends PShape {
|
||||
} else {
|
||||
if (is2D() && strokeCap != cap) {
|
||||
// Changing the stroke cap on a 2D shape needs a
|
||||
// re-tesellation in order to replace the old cap
|
||||
// re-tessellation in order to replace the old cap
|
||||
// geometry.
|
||||
markForTessellation();
|
||||
}
|
||||
@@ -2311,6 +2340,44 @@ public class PShapeOpenGL extends PShape {
|
||||
markForTessellation();
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////
|
||||
|
||||
//
|
||||
|
||||
// Vertex codes
|
||||
|
||||
@Override
|
||||
public int[] getVertexCodes() {
|
||||
if (family == GROUP) return null;
|
||||
else {
|
||||
if (inGeo.codes == null) {
|
||||
return null;
|
||||
}
|
||||
if (inGeo.codes.length != inGeo.codeCount) {
|
||||
inGeo.codes = PApplet.subset(inGeo.codes, 0, inGeo.codeCount);
|
||||
}
|
||||
return inGeo.codes;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int getVertexCodeCount() {
|
||||
if (family == GROUP) return 0;
|
||||
else {
|
||||
return inGeo.codeCount;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* One of VERTEX, BEZIER_VERTEX, CURVE_VERTEX, or BREAK.
|
||||
*/
|
||||
@Override
|
||||
public int getVertexCode(int index) {
|
||||
return inGeo.codes[index];
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////
|
||||
|
||||
@@ -2318,6 +2385,7 @@ public class PShapeOpenGL extends PShape {
|
||||
|
||||
// Tessellated geometry getter.
|
||||
|
||||
|
||||
@Override
|
||||
public PShape getTessellation() {
|
||||
updateTessellation();
|
||||
@@ -2413,6 +2481,34 @@ public class PShapeOpenGL extends PShape {
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////
|
||||
|
||||
//
|
||||
|
||||
// Geometry utils
|
||||
|
||||
// http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html
|
||||
@Override
|
||||
public boolean contains(float x, float y) {
|
||||
if (family == PATH) {
|
||||
boolean c = false;
|
||||
for (int i = 0, j = inGeo.vertexCount-1; i < inGeo.vertexCount; j = i++) {
|
||||
if (((inGeo.vertices[3 * i + 1] > y) != (inGeo.vertices[3 * j + 1] > y)) &&
|
||||
(x <
|
||||
(inGeo.vertices[3 * j]-inGeo.vertices[3 * i]) *
|
||||
(y-inGeo.vertices[3 * i + 1]) /
|
||||
(inGeo.vertices[3 * j + 1]-inGeo.vertices[3 * i + 1]) +
|
||||
inGeo.vertices[3 * i])) {
|
||||
c = !c;
|
||||
}
|
||||
}
|
||||
return c;
|
||||
} else {
|
||||
throw new IllegalArgumentException("The contains() method is only implemented for paths.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////
|
||||
|
||||
//
|
||||
@@ -2492,7 +2588,7 @@ public class PShapeOpenGL extends PShape {
|
||||
protected void tessellate() {
|
||||
if (root == this && parent == null) {
|
||||
if (tessGeo == null) {
|
||||
tessGeo = pg.newTessGeometry(PGraphicsOpenGL.RETAINED);
|
||||
tessGeo = PGraphicsOpenGL.newTessGeometry(pg, PGraphicsOpenGL.RETAINED);
|
||||
}
|
||||
tessGeo.clear();
|
||||
|
||||
@@ -2532,12 +2628,13 @@ public class PShapeOpenGL extends PShape {
|
||||
tessellator.setInGeometry(inGeo);
|
||||
tessellator.setTessGeometry(tessGeo);
|
||||
tessellator.setFill(fill || image != null);
|
||||
tessellator.setTexCache(null, null, null);
|
||||
tessellator.setStroke(stroke);
|
||||
tessellator.setStrokeColor(strokeColor);
|
||||
tessellator.setStrokeWeight(strokeWeight);
|
||||
tessellator.setStrokeCap(strokeCap);
|
||||
tessellator.setStrokeJoin(strokeJoin);
|
||||
tessellator.setTexCache(null, null, null);
|
||||
tessellator.setRenderer(pg);
|
||||
tessellator.setTransform(matrix);
|
||||
tessellator.set3D(is3D());
|
||||
|
||||
@@ -2571,9 +2668,16 @@ public class PShapeOpenGL extends PShape {
|
||||
if (normalMode == NORMAL_MODE_AUTO) inGeo.calcQuadStripNormals();
|
||||
tessellator.tessellateQuadStrip();
|
||||
} else if (kind == POLYGON) {
|
||||
boolean bez = inGeo.hasBezierVertex();
|
||||
boolean quad = inGeo.hasQuadraticVertex();
|
||||
boolean curv = inGeo.hasCurveVertex();
|
||||
if (bez || quad) saveBezierVertexSettings();
|
||||
if (curv) saveCurveVertexSettings();
|
||||
if (stroke) inGeo.addPolygonEdges(close);
|
||||
tessellator.tessellatePolygon(solid, close,
|
||||
normalMode == NORMAL_MODE_AUTO);
|
||||
if (bez ||quad) restoreBezierVertexSettings();
|
||||
if (curv) restoreCurveVertexSettings();
|
||||
}
|
||||
} else if (family == PRIMITIVE) {
|
||||
// The input geometry needs to be cleared because the geometry
|
||||
@@ -2720,7 +2824,7 @@ public class PShapeOpenGL extends PShape {
|
||||
x2, y2, 0,
|
||||
x3, y3, 0,
|
||||
x4, y4, 0,
|
||||
fill, stroke);
|
||||
stroke);
|
||||
tessellator.tessellateQuads();
|
||||
}
|
||||
|
||||
@@ -2797,11 +2901,12 @@ public class PShapeOpenGL extends PShape {
|
||||
ambientColor, specularColor, emissiveColor, shininess);
|
||||
inGeo.setNormal(normalX, normalY, normalZ);
|
||||
if (rounded) {
|
||||
inGeo.addRect(a, b, c, d, tl, tr, br, bl,
|
||||
fill, stroke, bezierDetail);
|
||||
saveBezierVertexSettings();
|
||||
inGeo.addRect(a, b, c, d, tl, tr, br, bl, stroke);
|
||||
tessellator.tessellatePolygon(false, true, true);
|
||||
restoreBezierVertexSettings();
|
||||
} else {
|
||||
inGeo.addRect(a, b, c, d, fill, stroke);
|
||||
inGeo.addRect(a, b, c, d, stroke);
|
||||
tessellator.tessellateQuads();
|
||||
}
|
||||
}
|
||||
@@ -2951,10 +3056,23 @@ public class PShapeOpenGL extends PShape {
|
||||
}
|
||||
}
|
||||
|
||||
if (nu < 3 || nv < 2) {
|
||||
nu = nv = 30;
|
||||
}
|
||||
int savedDetailU = pg.sphereDetailU;
|
||||
int savedDetailV = pg.sphereDetailV;
|
||||
if (pg.sphereDetailU != nu || pg.sphereDetailV != nv) {
|
||||
pg.sphereDetail(nu, nv);
|
||||
}
|
||||
|
||||
inGeo.setMaterial(fillColor, strokeColor, strokeWeight,
|
||||
ambientColor, specularColor, emissiveColor, shininess);
|
||||
int[] indices = inGeo.addSphere(r, nu, nv, fill, stroke);
|
||||
tessellator.tessellateTriangles(indices);
|
||||
|
||||
if (savedDetailU != nu || savedDetailV != nv) {
|
||||
pg.sphereDetail(savedDetailU, savedDetailV);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2965,18 +3083,19 @@ public class PShapeOpenGL extends PShape {
|
||||
ambientColor, specularColor, emissiveColor, shininess);
|
||||
|
||||
if (vertexCodeCount == 0) { // each point is a simple vertex
|
||||
if (vertices[0].length == 2) { // tesellating 2D vertices
|
||||
if (vertices[0].length == 2) { // tessellating 2D vertices
|
||||
for (int i = 0; i < vertexCount; i++) {
|
||||
inGeo.addVertex(vertices[i][X], vertices[i][Y], VERTEX);
|
||||
inGeo.addVertex(vertices[i][X], vertices[i][Y], VERTEX, false);
|
||||
}
|
||||
} else { // drawing 3D vertices
|
||||
for (int i = 0; i < vertexCount; i++) {
|
||||
inGeo.addVertex(vertices[i][X], vertices[i][Y], vertices[i][Z], VERTEX);
|
||||
inGeo.addVertex(vertices[i][X], vertices[i][Y], vertices[i][Z],
|
||||
VERTEX, false);
|
||||
}
|
||||
}
|
||||
} else { // coded set of vertices
|
||||
int idx = 0;
|
||||
int code = BREAK;
|
||||
boolean brk = true;
|
||||
|
||||
if (vertices[0].length == 2) { // tessellating a 2D path
|
||||
|
||||
@@ -2984,16 +3103,16 @@ public class PShapeOpenGL extends PShape {
|
||||
switch (vertexCodes[j]) {
|
||||
|
||||
case VERTEX:
|
||||
inGeo.addVertex(vertices[idx][X], vertices[idx][Y], code);
|
||||
code = VERTEX;
|
||||
inGeo.addVertex(vertices[idx][X], vertices[idx][Y], VERTEX, brk);
|
||||
brk = false;
|
||||
idx++;
|
||||
break;
|
||||
|
||||
case QUADRATIC_VERTEX:
|
||||
inGeo.addQuadraticVertex(vertices[idx+0][X], vertices[idx+0][Y], 0,
|
||||
vertices[idx+1][X], vertices[idx+1][Y], 0,
|
||||
fill, stroke, bezierDetail, code);
|
||||
code = VERTEX;
|
||||
brk);
|
||||
brk = false;
|
||||
idx += 2;
|
||||
break;
|
||||
|
||||
@@ -3001,20 +3120,19 @@ public class PShapeOpenGL extends PShape {
|
||||
inGeo.addBezierVertex(vertices[idx+0][X], vertices[idx+0][Y], 0,
|
||||
vertices[idx+1][X], vertices[idx+1][Y], 0,
|
||||
vertices[idx+2][X], vertices[idx+2][Y], 0,
|
||||
fill, stroke, bezierDetail, code);
|
||||
code = VERTEX;
|
||||
brk);
|
||||
brk = false;
|
||||
idx += 3;
|
||||
break;
|
||||
|
||||
case CURVE_VERTEX:
|
||||
inGeo.addCurveVertex(vertices[idx][X], vertices[idx][Y], 0,
|
||||
fill, stroke, curveDetail, code);
|
||||
code = VERTEX;
|
||||
inGeo.addCurveVertex(vertices[idx][X], vertices[idx][Y], 0, brk);
|
||||
brk = false;
|
||||
idx++;
|
||||
break;
|
||||
|
||||
case BREAK:
|
||||
code = BREAK;
|
||||
brk = true;
|
||||
}
|
||||
}
|
||||
} else { // tessellating a 3D path
|
||||
@@ -3023,8 +3141,8 @@ public class PShapeOpenGL extends PShape {
|
||||
|
||||
case VERTEX:
|
||||
inGeo.addVertex(vertices[idx][X], vertices[idx][Y],
|
||||
vertices[idx][Z], code);
|
||||
code = VERTEX;
|
||||
vertices[idx][Z], brk);
|
||||
brk = false;
|
||||
idx++;
|
||||
break;
|
||||
|
||||
@@ -3035,12 +3153,11 @@ public class PShapeOpenGL extends PShape {
|
||||
vertices[idx+1][X],
|
||||
vertices[idx+1][Y],
|
||||
vertices[idx+0][Z],
|
||||
fill, stroke, bezierDetail, code);
|
||||
code = VERTEX;
|
||||
brk);
|
||||
brk = false;
|
||||
idx += 2;
|
||||
break;
|
||||
|
||||
|
||||
case BEZIER_VERTEX:
|
||||
inGeo.addBezierVertex(vertices[idx+0][X],
|
||||
vertices[idx+0][Y],
|
||||
@@ -3051,8 +3168,8 @@ public class PShapeOpenGL extends PShape {
|
||||
vertices[idx+2][X],
|
||||
vertices[idx+2][Y],
|
||||
vertices[idx+2][Z],
|
||||
fill, stroke, bezierDetail, code);
|
||||
code = VERTEX;
|
||||
brk);
|
||||
brk = false;
|
||||
idx += 3;
|
||||
break;
|
||||
|
||||
@@ -3060,22 +3177,61 @@ public class PShapeOpenGL extends PShape {
|
||||
inGeo.addCurveVertex(vertices[idx][X],
|
||||
vertices[idx][Y],
|
||||
vertices[idx][Z],
|
||||
fill, stroke, curveDetail, code);
|
||||
code = VERTEX;
|
||||
brk);
|
||||
brk = false;
|
||||
idx++;
|
||||
break;
|
||||
|
||||
case BREAK:
|
||||
code = BREAK;
|
||||
brk = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
boolean bez = inGeo.hasBezierVertex();
|
||||
boolean quad = inGeo.hasQuadraticVertex();
|
||||
boolean curv = inGeo.hasCurveVertex();
|
||||
if (bez || quad) saveBezierVertexSettings();
|
||||
if (curv) saveCurveVertexSettings();
|
||||
if (stroke) inGeo.addPolygonEdges(close);
|
||||
tessellator.tessellatePolygon(false, close, true);
|
||||
if (bez || quad) restoreBezierVertexSettings();
|
||||
if (curv) restoreCurveVertexSettings();
|
||||
}
|
||||
|
||||
protected void saveBezierVertexSettings() {
|
||||
savedBezierDetail = pg.bezierDetail;
|
||||
if (pg.bezierDetail != bezierDetail) {
|
||||
pg.bezierDetail(bezierDetail);
|
||||
}
|
||||
}
|
||||
|
||||
protected void restoreBezierVertexSettings() {
|
||||
if (savedBezierDetail != bezierDetail) {
|
||||
pg.bezierDetail(savedBezierDetail);
|
||||
}
|
||||
}
|
||||
|
||||
protected void saveCurveVertexSettings() {
|
||||
savedCurveDetail = pg.curveDetail;
|
||||
savedCurveTightness = pg.curveTightness;
|
||||
if (pg.curveDetail != curveDetail) {
|
||||
pg.curveDetail(curveDetail);
|
||||
}
|
||||
if (pg.curveTightness != curveTightness) {
|
||||
pg.curveTightness(curveTightness);
|
||||
}
|
||||
}
|
||||
|
||||
protected void restoreCurveVertexSettings() {
|
||||
if (savedCurveDetail != curveDetail) {
|
||||
pg.curveDetail(savedCurveDetail);
|
||||
}
|
||||
if (savedCurveTightness != curveTightness) {
|
||||
pg.curveTightness(savedCurveTightness);
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
Reference in New Issue
Block a user