endShape()

Shape / Vertex

Description

The companion to beginShape(). Pass CLOSE to close the shape.

Syntax

void endShape() void endShape(int mode)

Parameters

NameTypeDescription
modeintCLOSE to close the shape (optional)

Returns

void

Related

Under the Hood

From Processing.h:

void beginShape(); void endShape(int mode=0); void endShape(bool close=false) { closed=close; } void endShape(int mode=0); inline void PGraphics::endShape(int mode) { if(PApplet::g_papplet) PApplet::g_papplet->endShape(mode); }

Under the Hood

From Processing.cpp:

void PApplet::endShape(int mode){ if(!inShape){return;} bool cl=(mode==CLOSE); int n3 = (int)shapeVerts3D.size(); // -- Explicit shape kinds (QUADS, QUAD_STRIP, TRIANGLES, etc.) ---------- // Draw fill and/or stroke from the collected vertex arrays. if(shapeKind != -1 && n3 > 0){ GLenum gm; switch(shapeKind){ case POINTS: gm=GL_POINTS; break; case LINES: gm=GL_LINES; break; case TRIANGLES: gm=GL_TRIANGLES; break; case TRIANGLE_FAN: gm=GL_TRIANGLE_FAN; break; case TRIANGLE_STRIP:gm=GL_TRIANGLE_STRIP;break; case QUADS: gm=GL_QUADS; break; case QUAD_STRIP: gm=GL_QUAD_STRIP; break; default: gm=GL_POLYGON; break; } if(doFill && shapeKind != POINTS && shapeKind != LINES){ glEnable(GL_POLYGON_OFFSET_FILL); glPolygonOffset(1.0f, 1.0f); applyFill(); glBegin(gm); for(auto& v : shapeVerts3D) glVertex3f(v[0], v[1], v[2]); glEnd(); glDisable(GL_POLYGON_OFFSET_FILL); } // POINTS and LINES use stroke color drawn directly if(shapeKind == POINTS){ applyStroke(); glPointSize(strokeW); glBegin(GL_POINTS); for(auto& v : shapeVerts3D) glVertex3f(v[0], v[1], v[2]); glEnd(); restoreLighting(); inShape=false; shape3D=false; shapeVerts.clear(); shapeVerts3D.clear(); return; } if(shapeKind == LINES){ applyStroke(); glLineWidth(strokeW); glBegin(GL_LINES); for(auto& v : shapeVerts3D) glVertex3f(v[0], v[1], v[2]); glEnd(); restoreLighting(); inShape=false; shape3D=false; shapeVerts.clear(); shapeVerts3D.clear(); return; } // Draw stroke outlines -- shapeVerts was collected in vertex() if(doStroke && !shapeVerts.empty()){ applyStroke(); glLineWidth(strokeW); int n=(int)shapeVerts.size(); // Use 3D verts for correct depth in transformed space auto lv=[&](int i)->std::array<float,3>{ return shapeVerts3D[i]; }; switch(shapeKind){ case TRIANGLE_STRIP: glBegin(GL_LINES); for(int i=0;i+2<n;i++){ auto a=lv(i),b=lv(i+1),c=lv(i+2); glVertex3f(a[0],a[1],a[2]);glVertex3f(b[0],b[1],b[2]); glVertex3f(b[0],b[1],b[2]);glVertex3f(c[0],c[1],c[2]); glVertex3f(c[0],c[1],c[2]);glVertex3f(a[0],a[1],a[2]); } glEnd(); break; case TRIANGLE_FAN: glBegin(GL_LINES); for(int i=1;i+1<n;i++){ auto a=lv(0),b=lv(i),c=lv(i+1); glVertex3f(a[0],a[1],a[2]);glVertex3f(b[0],b[1],b[2]); glVertex3f(b[0],b[1],b[2]);glVertex3f(c[0],c[1],c[2]); glVertex3f(c[0],c[1],c[2]);glVertex3f(a[0],a[1],a[2]); } glEnd(); break; case TRIANGLES: glBegin(GL_LINES); for(int i=0;i+2<n;i+=3){ auto a=lv(i),b=lv(i+1),c=lv(i+2); glVertex3f(a[0],a[1],a[2]);glVertex3f(b[0],b[1],b[2]); glVertex3f(b[0],b[1],b[2]);glVertex3f(c[0],c[1],c[2]); glVertex3f(c[0],c[1],c[2]);glVertex3f(a[0],a[1],a[2]); } glEnd(); break; case QUADS: glBegin(GL_LINES); for(int i=0;i+3<n;i+=4){ auto a=lv(i),b=lv(i+1),c=lv(i+2),d=lv(i+3); glVertex3f(a[0],a[1],a[2]);glVertex3f(b[0],b[1],b[2]); glVertex3f(b[0],b[1],b[2]);glVertex3f(c[0],c[1],c[2]); glVertex3f(c[0],c[1],c[2]);glVertex3f(d[0],d[1],d[2]); glVertex3f(d[0],d[1],d[2]);glVertex3f(a[0],a[1],a[2]); } glEnd(); break; case QUAD_STRIP: glBegin(GL_LINES); for(int i=0;i+3<n;i+=2){ auto a=lv(i),b=lv(i+1),c=lv(i+3),d=lv(i+2); glVertex3f(a[0],a[1],a[2]);glVertex3f(b[0],b[1],b[2]); glVertex3f(b[0],b[1],b[2]);glVertex3f(c[0],c[1],c[2]); glVertex3f(c[0],c[1],c[2]);glVertex3f(d[0],d[1],d[2]); glVertex3f(d[0],d[1],d[2]);glVertex3f(a[0],a[1],a[2]); } glEnd(); break; default: glBegin(cl?GL_LINE_LOOP:GL_LINE_STRIP); for(auto& v:shapeVerts3D)glVertex3f(v[0],v[1],v[2]); glEnd(); break; } } restoreLighting(); inShape=false; shape3D=false; shapeVerts.clear(); shapeVerts3D.clear(); return; } if(shapeVerts.empty()){inShape=false;return;} // Default beginShape() / endShape(CLOSE) path. // Use stencil buffer to fill arbitrary (including concave) polygons correctly. // This matches Java Processing's polygon fill behavior. if(shapeKind==-1 || shapeKind==CLOSE){ if(doFill && shapeVerts.size()>=3){ glDisable(GL_CULL_FACE); // Step 1: Write polygon to stencil buffer using odd-even fill rule glEnable(GL_STENCIL_TEST); glClear(GL_STENCIL_BUFFER_BIT); glStencilFunc(GL_ALWAYS, 0, ~0); glStencilOp(GL_KEEP, GL_KEEP, GL_INVERT); // toggle stencil bit glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); // don't write color glBegin(GL_TRIANGLE_FAN); for(auto& v : shapeVerts3D) glVertex3f(v[0], v[1], v[2]); glEnd(); glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); // Step 2: Draw fill color only where stencil != 0 glStencilFunc(GL_NOTEQUAL, 0, ~0); glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); applyFill(); // Draw a bounding quad covering the shape float minx=shapeVerts3D[0][0], maxx=minx; float miny=shapeVerts3D[0][1], maxy=miny; float minz=shapeVerts3D[0][2], maxz=minz; for(auto& v:shapeVerts3D){ minx=std::min(minx,v[0]); maxx=std::max(maxx,v[0]); miny=std::min(miny,v[1]); maxy=std::max(maxy,v[1]); minz=std::min(minz,v[2]); maxz=std::max(maxz,v[2]); } float mz=(minz+maxz)*0.5f; glBegin(GL_QUADS); glVertex3f(minx,miny,mz); glVertex3f(maxx,miny,mz); glVertex3f(maxx,maxy,mz); glVertex3f(minx,maxy,mz); glEnd(); glDisable(GL_STENCIL_TEST); } if(doStroke){ applyStroke(); glLineWidth(strokeW); glBegin(cl ? GL_LINE_LOOP : GL_LINE_STRIP); // Use 3D coords so transforms (rotateX/Y) are respected for(auto& v : shapeVerts3D) glVertex3f(v[0], v[1], v[2]); glEnd(); restoreLighting(); } } inShape=false; shapeVerts.clear(); shapeVerts3D.clear(); }