Efficient pixel scaling

edited January 2018 in How To...

Hello,

I need a good method of pixel scaling (not hqx, just plain old pixel size), preferably not using scale() because my program is using shapes (ellipse() etc.). It also needs to run smoothly with at least 25 fps (because this is for a game). I can use different renderers than JAVA2D, if necessary.

I can't use things like textSize() because I'm using a .vlw font and it would blur the font out.

Tagged:

Answers

  • Why won't scale work? What have you tried so far?

  • @KevinWorkman scale() won't work, because it scales shapes - I want that "retro-feeling" pixel scaling, not shapes having even more detail.

    I tried using surface.setResizable(true) and surface.setSize(width*2, height*2) after my main sketch's drawing code, then checking every pixel's color, drawing a rectangle for every pixel but twice the size and position and the original pixel's color on a different PSurface, calling background(0) to clear the screen, and then drawing the surface, but it's painfully slow.

  • Draw to a buffer (the createGraphics() function is your friend here) and then draw your scene to that buffer. Make it small, so 1 block = 1 pixel.

    Then draw that buffer to the screen at the screen's size. This will basically be like drawing a small image to the screen and blowing it up. You'll probably have to play with your settings to get the right resizing effect.

  • I've added a pixel graphics bit to the 'blurry graphics' part of Common Questions

  • @KevinWorkman Thank you for your answer, it worked perfectly :)

  • edited January 2018

    Note that you can resize a PGraphics buffer only once by drawing it into a new scaled buffer. This has some advantages:

    1. avoids using the five-argument version of image(img, x, y, w, h) every frame, which is processing-intensive
    2. does not require the textureSampling resize magic hack
    3. because it uses noSmooth instead of textureSampling, works in default renderer, not just P2D

    Here is a quick example:

    // PixelFace
    // scaling up a small PGraphics for pixel-aesthetic display in a larger sketch.
    // 2018-01-27 Jeremy Douglass - Processing 3.3.6
    
    PGraphics pg;
    PGraphics sized;
    void setup() {
      size(200, 200);
      noSmooth();
      pg = createGraphics(32, 32);
      face(pg);
      sized = createGraphics(width, height);
      sized.beginDraw();
      sized.image(pg, 0, 0, sized.width, sized.height);
      sized.endDraw();
    }
    void draw() {
      background(255);
      //image(pg, 0, 0, width, height);
      image(sized, 0, 0);
      image(pg, 0, 0);
    }
    void face(PGraphics pg) {
      pg.beginDraw();
      pg.noSmooth();
      pg.background(192);
      pg.noFill();
      pg.rect(0, 0, 31, 31);     // head
      pg.set(10, 10, color(0));  // eye
      pg.set(21, 10, color(0));  // eye
      pg.ellipse(15, 15, 6, 6);  // nose
      pg.line(10, 21, 21, 21);   // mouth
      pg.rect(27, 10, 2, 8);     // ear
      pg.endDraw();
    }
    

    PixelFace--screenshot

  • By 'only once' do you mean once per frame? If it's literally only once then if be no good for animation (which I assume the OP wants)

  • edited January 2018

    I meant once only ever during the sketch lifetime. I didn't see anything in the question about animation, I was just responding to the part about needing good fps performance. I was assuming that this was for static assets -- tiles etc.

    If the whole sketch just involves drawing to a single buffer (a mini-screen) then it is fine to just render the buffer with image(buffer, x, y, w, h) each frame. My sketch also shows that as an alternative in draw, commented out (although it sounds like OP had worked that out or something like it already).

    However: if you are draw-time resizing with 5, 10 or 20 different static resources, each requiring their own resize every frame, or if you are drawing the same static resource many times, which is quite common in games (e.g. many ghosts, many bricks, many space invaders) THEN it is really better for performance to resize the base asset only once during the lifetime of the sketch and use (img, x, y). A loop with image(buffer, x, y, w, h) in it -- e.g. over an array of enemies -- is a terrible idea.

    On the other hand, if in order to draw continuous animation (of a moving ghost, or of a changing screen) you are updating the buffer every frame then drawing to a resize-buffer THEN drawing to the screen, every frame -- then that extra copy won't increase performance. Performance will get worse.

    ...in that case, the best thing for performance would be not drawing or resizing resources at all (if possible). It is better to store those assets (bricks, invaders, etc.) in sprite sheets and/or load pre-upscaled graphics (if the game has a fixed window size).

  • I read the fps as indicating animation.

    But we are both just assuming without more information.

    There is more info here: https://forum.processing.org/two/discussion/25848/do-things-on-a-thread-separate-of-draw

Sign In or Register to comment.