Star Wars Tatooine Landscape

Hello folks!

Star Wars Tatooine Landscape

Started as a sketch to explore Processing image scaling and rendering.

Details
  • resizing with image(img, a, b, c, d)
  • resizing the sketch window
  • resizing PGraphics layers
  • drawing into larger PGraphics layers using scaled drawing parameters
  • static and animated PGraphics layer compositing
  • renderer performance with JAVA2D and P2D
  • smoothing / antialiasing behavior
  • noSmooth() added to settings. Comment this for testing with default smooth()
  • anything I missed

Keys:

  • 1 reset to 1x
  • 3 toggle 3x mode between image resizing and resized PGraphics layers
  • s toggle smoothing / antialiasing
  • d toggle debug timing output
  • lots of combinations there to explore!

Renderer:

  • edit RENDERER in the code to switch between JAVA2D and P2D
// canvasScaleTest
// Author: GLV
// Version 1.4.0
// Date 2026-07-02
// Time 18:00

PGraphics pgSun, pgSand, pgText, pgBackground;

int w, h;

int canvasScale = 1;   // Sketch size and PGraphics size scale
int imageScale = 1;    // image() scale

String RENDERER = JAVA2D;
//String RENDERER = P2D;

float ySunBase;
float sandCol;

void settings()
{
  w = 16*30;
  h = 9*30;
  size(w, h, RENDERER);
  noSmooth(); // Comment this out for testing
}

void setup()
{
  makeImages();
  
  key = '3';
  keyPressed();
}

boolean debug = false;
int t0, t1, t2;

void draw()
{
  if (debug)
    t0 = millis();

  updateSunValues();
  makeSun(); // Update every frame
  makeSand();
  //makeText();

  if (debug)
    t1 = millis();

  if (scaleImage)
  {
    image(pgBackground, 0, 0, imageScale*w, imageScale*h);
    image(pgSun, 0, 0, imageScale*w, imageScale*h);
    image(pgSand, 0, 0, imageScale*w, imageScale*h);
    image(pgText, 0, 0, imageScale*w, imageScale*h);
  } else
  {
    image(pgBackground, 0, 0);
    image(pgSun, 0, 0);
    image(pgSand, 0, 0);
    image(pgText, 0, 0);
  }

  if (debug)
    t2 = millis();

  if (debug)
    println(t1-t0, t2-t1, t2-t0, frameRate);
}

boolean scaleImage = true;

void keyPressed()
{
  if (key  == 's')
  {
    togSmooth = !togSmooth;
    makeImages();
  }

  if (key == 'd')
    debug = !debug;

  if (key == '1')
  {
    scaleImage = false;
    imageScale = 1;
    canvasScale = 1;
    surface.setSize(w, h);
    makeImages();
  }

  if (key == '3')
  {
    scaleImage = !scaleImage;

    if (scaleImage)
    {
      imageScale = 3;
      canvasScale = 1;
    } else
    {
      imageScale = 1;
      canvasScale = 3;
    }

    surface.setSize(3*w, 3*h);
    makeImages();
  }
}

void updateSunValues()
{
  ySunBase = -50 + (frameCount/2.0)%(h+100);
  //sandCol = 255-(ySunBase+50)*(255.0/(h+100));

  float p = (ySunBase + 50) / (h + 100); //normalize
  //sandCol = 255 * (1 - p);
  sandCol = 255 * (1 - p*p);
  //sandCol = 255 * (1 - p*p*p);
  //println(ySunBase, sandCol);
}

boolean togSmooth;

void makeImages()
{
  pgSun =  createGraphics(canvasScale*w, canvasScale*h, RENDERER);
  pgSand = createGraphics(canvasScale*w, canvasScale*h, RENDERER);
  pgText = createGraphics(canvasScale*w, canvasScale*h, RENDERER);
  pgBackground = createGraphics(canvasScale*w, canvasScale*h, RENDERER);

  if (togSmooth)
  {
    pgSun.smooth(4);  //See reference
    pgSand.smooth(4);
    pgText.smooth(4);
  } else
  {
    pgSun.noSmooth();
    pgSand.noSmooth();
    pgText.noSmooth();
  }

  updateSunValues();
  makeSun();
  makeSand();
  makeText();
  makeGradientBackground();
}

void makeSun()
{
  int xSun   = 2*pgSun.width/3;
  float ySun = canvasScale*ySunBase;
  int offSet = canvasScale*40;

  pgSun.beginDraw();
  pgSun.clear();

  float aSun = constrain(sandCol, 0, 255); //Use as alpha or brightness
  //pgSun.fill(255, aSun);
  pgSun.fill(aSun, aSun, aSun);
  pgSun.noStroke();
  pgSun.circle(xSun, ySun, canvasScale*20);

  //pgSun.fill(255, 0, 0, aSun);
  pgSun.fill(aSun, 0, 0);
  pgSun.noStroke();
  pgSun.circle(xSun+offSet, ySun+offSet, canvasScale*20);

  pgSun.endDraw();
}

void makeSand()
{
  float amp = 10; //amplitude
  float ps = 0;   //phase shift

  float col = sandCol;
  //if(d)
  //  println(col);

  pgSand.beginDraw();
  pgSand.clear();

  pgSand.noStroke();
  //pgSand.fill(0.5*col, 0.25*col, 0);
  pgSand.fill(0.75*col, 0.60*col, 0.35*col);
  pgSand.beginShape();
  for (int i = 0; i<=pgSand.width; i+=canvasScale*10)
  {
    float th = i*(TAU/pgSand.width) + ps;
    float x = i;
    float y = canvasScale*amp*sin(th);
    pgSand.vertex(x, y+ 3*pgSand.height/4);
  }
  pgSand.vertex(pgSand.width, pgSand.height);
  pgSand.vertex(0, pgSand.height);
  pgSand.endShape(CLOSE);

  pgSand.endDraw();
}

void makeText()
{
  pgText.beginDraw();
  pgText.clear();

  pgText.fill(0);
  pgText.textSize(canvasScale*24);
  pgText.textAlign(LEFT, TOP);
  pgText.text("Tatooine", canvasScale*10, canvasScale*10);

  pgText.endDraw();
}

void makeGradientBackground()
{
  color cTop = color(180, 100, 75);
  color cBottom = color(70, 55, 95);

  pgBackground.beginDraw();
  for (int y = 0; y < pgBackground.height; y++)
  {
    float p = y / float(pgBackground.height - 1);

    //noStroke();
    //fill(lerpColor(cTop, cBottom, p));
    //rect(0, y, width, 1);

    pgBackground.stroke(lerpColor(cTop, cBottom, p));
    pgBackground.line(0, y, pgBackground.width, y);
  }
  pgBackground.endDraw();
}

:)

2 Likes