@@ -646,7 +646,21 @@ bool PApplet::isAltDown() {
646646
647647void PApplet::windowRatio (int w,int h){if (gWindow )glfwSetWindowAspectRatio (gWindow ,w,h);}
648648void PApplet::pixelDensity (int d){pixelDensityValue=d;}
649- void PApplet::smooth () {smoothing=true ; glEnable (GL_LINE_SMOOTH );glHint (GL_LINE_SMOOTH_HINT ,GL_NICEST );glEnable (GL_POINT_SMOOTH );glHint (GL_POINT_SMOOTH_HINT ,GL_NICEST );glEnable (GL_MULTISAMPLE );}
649+ void PApplet::smooth (int level) {
650+ // The MAIN window's actual MSAA sample count is fixed at window-creation
651+ // time (GLFW_SAMPLES is a window hint, can't change after the window
652+ // exists) -- so smooth(level) can't retroactively change the main
653+ // canvas's hardware sample count the way real Processing's P2D/P3D
654+ // renderers can. What we CAN do: store the requested level (used by
655+ // PGraphics buffers below, which DO get to choose their own sample
656+ // count fresh at creation time), and toggle the same smoothing flags
657+ // smooth() always has, regardless of which level was requested.
658+ smoothing = true ;
659+ smoothLevel = level;
660+ glEnable (GL_LINE_SMOOTH );glHint (GL_LINE_SMOOTH_HINT ,GL_NICEST );
661+ glEnable (GL_POINT_SMOOTH );glHint (GL_POINT_SMOOTH_HINT ,GL_NICEST );
662+ glEnable (GL_MULTISAMPLE );
663+ }
650664void PApplet::noSmooth (){smoothing=false ;glDisable (GL_LINE_SMOOTH );glDisable (GL_POLYGON_SMOOTH );glDisable (GL_POINT_SMOOTH );glDisable (GL_MULTISAMPLE );}
651665void PApplet::hint (int which){
652666 switch (which){
@@ -916,15 +930,33 @@ void PApplet::rect(float x, float y, float w, float h) {
916930 }
917931
918932 if (doStroke) {
919- // Expand stroke outward by half strokeWeight so it sits outside the fill
920- float half = strokeW * 0 .5f ;
933+ // Real Processing centers the stroke ON the rectangle's boundary
934+ // (half the weight extends inward over the fill, half extends
935+ // outward) -- NOT entirely outside it. The previous version drew
936+ // the stroke loop expanded fully outward, which meant increasing
937+ // strokeWeight never visually shrank the filled interior (it
938+ // does in real Processing, since the inward half of a thick
939+ // stroke covers part of the fill), and glLineWidth-rendered
940+ // GL_LINE_LOOP gives flat, unmitered corners at large widths
941+ // (visible gaps/seams at corners instead of a clean joined
942+ // outline). Drawing the stroke as actual filled quad geometry --
943+ // matching real Processing's approach -- fixes both: correct
944+ // centering AND clean mitered corners via overlapping quads.
921945 applyStroke ();
922- glLineWidth (strokeW);
923- glBegin (GL_LINE_LOOP );
924- glVertex2f (x - half, y - half );
925- glVertex2f (x + w + half, y - half );
926- glVertex2f (x + w + half, y + h + half);
927- glVertex2f (x - half, y + h + half);
946+ float half = strokeW * 0 .5f ;
947+ float xo = x - half, yo = y - half; // outer edge
948+ float xi = x + half, yi = y + half; // inner edge (top-left side)
949+ float xow = x + w + half, yoh = y + h + half; // outer edge (bottom-right side)
950+ float xiw = x + w - half, yih = y + h - half; // inner edge (bottom-right side)
951+ glBegin (GL_QUADS );
952+ // Top edge
953+ glVertex2f (xo, yo); glVertex2f (xow, yo); glVertex2f (xow, yi); glVertex2f (xo, yi);
954+ // Bottom edge
955+ glVertex2f (xo, yih); glVertex2f (xow, yih); glVertex2f (xow, yoh); glVertex2f (xo, yoh);
956+ // Left edge (between top and bottom strips already drawn)
957+ glVertex2f (xo, yi); glVertex2f (xi, yi); glVertex2f (xi, yih); glVertex2f (xo, yih);
958+ // Right edge
959+ glVertex2f (xiw, yi); glVertex2f (xow, yi); glVertex2f (xow, yih); glVertex2f (xiw, yih);
928960 glEnd ();
929961 restoreLighting ();
930962 }
@@ -1044,7 +1076,7 @@ void PApplet::initPhongShader() {
10441076 const char * vs = R"VERT(
10451077varying vec3 vN;
10461078varying vec3 vP;
1047- void PApplet:: main(){
1079+ void main(){
10481080 // gl_NormalMatrix = inverse-transpose of modelview upper 3x3
10491081 vN = gl_NormalMatrix * gl_Normal;
10501082 vP = vec3(gl_ModelViewMatrix * gl_Vertex);
@@ -1058,7 +1090,7 @@ varying vec3 vP;
10581090uniform int uNumLights;
10591091uniform float uLightConc[8];
10601092uniform float uLightCutCos[8];
1061- void PApplet:: main(){
1093+ void main(){
10621094 vec3 N = normalize(vN);
10631095 vec3 V = normalize(-vP);
10641096 vec3 col = gl_Color.rgb * gl_LightModel.ambient.rgb;
@@ -2384,6 +2416,21 @@ void PApplet::drawImage_impl(PImage* img, float x, float y, float w, float h) {
23842416void PApplet::drawPGraphicsRect (PGraphics& pg, float x, float y, float w, float h){
23852417 if (pg.width ==0 ||pg.height ==0 ) return ;
23862418 if (pg.texID ==0 ) return ;
2419+ {
2420+ GLint vp[4 ]; glGetIntegerv (GL_VIEWPORT , vp);
2421+ double mv[16 ], proj[16 ];
2422+ glGetDoublev (GL_MODELVIEW_MATRIX , mv);
2423+ glGetDoublev (GL_PROJECTION_MATRIX , proj);
2424+ fprintf (stderr, " === DEBUG drawPGraphicsRect ===\n " );
2425+ fprintf (stderr, " requested draw rect: x=%.1f y=%.1f w=%.1f h=%.1f\n " , x, y, w, h);
2426+ fprintf (stderr, " pg.width=%d pg.height=%d\n " , pg.width , pg.height );
2427+ fprintf (stderr, " current GL viewport: x=%d y=%d w=%d h=%d\n " , vp[0 ], vp[1 ], vp[2 ], vp[3 ]);
2428+ fprintf (stderr, " logicalW=%d logicalH=%d fbW=%d fbH=%d width=%d height=%d\n " , logicalW, logicalH, fbW, fbH, width, height);
2429+ // proj[0] and proj[5] are the X/Y scale factors of an orthographic
2430+ // projection matrix -- these directly tell us the effective
2431+ // "units per screen pixel" mapping in each axis at draw time.
2432+ fprintf (stderr, " projection matrix scale: proj[0]=%.6f proj[5]=%.6f\n " , proj[0 ], proj[5 ]);
2433+ }
23872434 glEnable (GL_BLEND ); glBlendFunc (GL_SRC_ALPHA ,GL_ONE_MINUS_SRC_ALPHA );
23882435 glEnable (GL_TEXTURE_2D ); glBindTexture (GL_TEXTURE_2D ,pg.texID );
23892436 glColor4f (1 ,1 ,1 ,1 );
@@ -3038,9 +3085,20 @@ void PApplet::run(){
30383085 if (!defaultP3D) setProjection (winWidth, winHeight);
30393086
30403087 this ->setup ();
3041- // 2D sketches: disable MSAA so pixels stay crisp (noSmooth() effect).
3042- // P3D sketches keep MSAA from window creation for smooth 3D edges.
3043- if (!defaultP3D) {
3088+ // Real Processing's actual default is smooth(2) -- antialiased --
3089+ // even for plain 2D sketches (P2D/P3D both default to smooth(2); the
3090+ // legacy JAVA2D software renderer defaults to smooth(3)/bicubic).
3091+ // This previously UNCONDITIONALLY disabled MSAA for every 2D sketch,
3092+ // on the assumption that 2D wants "crisp" pixels by default -- that's
3093+ // backwards from real Processing's actual behavior, and it's why
3094+ // PGraphics buffers (and the main canvas) never looked antialiased
3095+ // even after wiring up multisample framebuffers: GL_MULTISAMPLE was
3096+ // globally disabled the whole time regardless of framebuffer setup.
3097+ // Only disable smoothing if the sketch explicitly called noSmooth()
3098+ // (smoothing==false) BEFORE this point -- otherwise leave the
3099+ // defaults smooth()/setup() already enabled (smooth() runs earlier in
3100+ // PApplet::run(), before this->setup(), as part of normal startup).
3101+ if (!defaultP3D && !smoothing) {
30443102 glDisable (GL_MULTISAMPLE );
30453103 glDisable (GL_POINT_SMOOTH );
30463104 glDisable (GL_LINE_SMOOTH );
0 commit comments