Skip to content

Instantly share code, notes, and snippets.

@possan
Created March 24, 2020 21:17
Show Gist options
  • Save possan/dbc96257c80072e14a6f0c951fd7d897 to your computer and use it in GitHub Desktop.
Save possan/dbc96257c80072e14a6f0c951fd7d897 to your computer and use it in GitHub Desktop.
Dome projection animation tester
// Install and run processing 3 from processing.org
// Open Sketch menu > Click Import library > Add library...
// Install SelectFile plugin (v0.0.2)
// Install Video plugin (v1.0.1)
// Paste this code and hit Run
import select.files.*;
import processing.video.*;
static int IMAGE_DURATION = 3000;
class TexHolder {
int texWidth = 0;
int texHeight = 0;
float width = 1.0;
float height = 1.0;
PImage image = null;
String path = "";
Movie movie = null;
long imageDeadline = 0;
String statusString = "";
TexHolder(int texWidth, int texHeight) {
this.texWidth = texWidth;
this.texHeight = texHeight;
}
void load(String path, PApplet applet) {
this.path = path;
this.movie = null;
this.image = null;
if (path.toLowerCase().indexOf(".mov") != -1) {
try {
Movie m = new Movie(applet, path);
m.play();
this.movie = m;
}
catch(Exception e) {
println("Exception", e);
}
} else {
try {
PImage t = null;
t = loadImage(path);
this.image = t;
}
catch(Exception e) {
println("Exception", e);
}
this.imageDeadline = millis() + IMAGE_DURATION;
}
}
void update() {
this.width = 1.0;
this.height = 1.0;
if (this.movie != null) {
if (this.movie.available()) {
this.movie.read();
}
this.width = this.movie.width;
this.height = this.movie.height;
this.statusString = "Time " + round(this.movie.time() * 1000.0) + "/" + round(this.movie.duration() * 1000.0) + "ms";
} else if (this.image != null) {
this.width = this.image.width;
this.height = this.image.height;
if (millis() < this.imageDeadline) {
this.statusString = "Still image";
} else {
this.statusString = "Still image (invisible)";
}
} else {
this.statusString = "Not loaded";
}
}
void trigger() {
if (this.movie != null) {
this.movie.jump(0);
this.movie.play();
} else if (this.image != null) {
this.imageDeadline = millis() + IMAGE_DURATION;
}
}
void bind() {
fill(0, 0, 0);
textureWrap(REPEAT);
if (this.image != null) {
if (millis() < this.imageDeadline) {
fill(255, 255, 255);
texture(this.image);
}
}
if (this.movie != null) {
fill(255, 255, 255);
texture(this.movie);
}
}
void drawPreview(int bx, int by, int mult) {
int pw = 100 * mult;
int ph = round(pw / (float)(texWidth / texHeight));
blendMode(BLEND);
fill(0, 0, 0);
rect(bx, by, pw, ph);
blendMode(ADD);
if (this.movie != null) {
image(this.movie, bx, by, pw, ph);
} else if (this.image != null) {
image(this.image, bx, by, pw, ph);
}
}
}
int selectTarget = 0;
TexHolder cylinderTex = new TexHolder(2048, 512);
TexHolder topTex = new TexHolder(512, 512);
float scrollX = 0.0;
float scrollY = 0.0;
float velocityX = 0.0;
float velocityY = 0.0;
void fileSelected(File selection) {
if (selection == null) {
println("Window was closed or the user hit cancel.");
} else {
println("User selected " + selection.getAbsolutePath());
if (selectTarget == 1) {
cylinderTex.load(selection.getAbsolutePath(), this);
}
if (selectTarget == 2) {
topTex.load(selection.getAbsolutePath(), this);
}
}
}
void setup() {
size(1200, 800, P3D);
frameRate(60);
surface.setTitle("Dome Preview");
surface.setResizable(true);
cylinderTex.load("./cylinderdemo.mov", this);
topTex.load("./topdemo2.mov", this);
}
void _drawDomeVertex(float u, float v, float radii, int mapping, float umax, float vmax) {
float lata = u * PI / 50.0f;
float lat_x = -cos(lata);
float lat_y = sin(lata);
float vf = v / 25.0f;
float lon = vf * radii;
float rmult = sin(acos(v / 25.000001));
float x = lat_x * radii * rmult;
float y = lat_y * radii * rmult;
float z = lon;
float tu, tv;
if (mapping == 1) {
tu = 1.0 * u * umax / 100.0f;
tv = 1.0 * vmax * (1.0 - vf);
vertex(x, y, z, tu, tv);
} else {
tu = 1.0 * umax * ((lat_x * rmult * 0.5f) + 0.5f);
tv = 1.0 * vmax * ((lat_y * rmult * 0.5f) + 0.5f);
vertex(x, y, z, tu, tv);
}
}
void _drawDomeShape(int mapping, float radius, float umax, float vmax) {
float G = 1.0;
for (int j=0; j<25; j++) {
for (int i=0; i<100; i++) {
_drawDomeVertex(i, j, radius, mapping, umax, vmax);
_drawDomeVertex(i+G, j, radius, mapping, umax, vmax);
_drawDomeVertex(i+G, j+G, radius, mapping, umax, vmax);
_drawDomeVertex(i, j+G, radius, mapping, umax, vmax);
}
}
}
void drawUI() {
blendMode(BLEND);
pushMatrix();
cylinderTex.drawPreview(200, 20, 3);
fill(255, 255, 0);
text("Cylinder clip (" + cylinderTex.width + "x" + cylinderTex.height + ")", 20, 40);
fill(200, 200, 200);
text(cylinderTex.statusString, 20, 60);
text("[1] - Trigger", 20, 80);
text("[Q] - Load mov/png", 20, 100);
topTex.drawPreview(200, 120, 1);
blendMode(ADD);
fill(255, 255, 0);
text("Topdown clip (" + topTex.width + "x" + topTex.height + ")", 20, 140);
fill(200, 200, 200);
text(topTex.statusString, 20, 160);
text("[2] - Trigger", 20, 180);
text("[W] - Load mov/png", 20, 200);
//text("scroll = " + round(scrollX) + "," + round(scrollY), 20, 300);
popMatrix();
}
void drawTest() {
blendMode(SUBTRACT);
pushMatrix();
beginShape();
cylinderTex.bind();
fill(100, 100, random(255), 0.5);
vertex(300 + random(100), 300, 0, 0);
vertex(600, 250, 1024, 0);
vertex(650, 600, 1024, 512);
vertex(300, 500, 0, 512);
endShape();
beginShape();
topTex.bind();
fill(random(255), 100, 100, 0.5);
vertex(300, 300, 0, 0);
vertex(600 + random(100), 250, 1024, 0);
vertex(650, 600, 1024, 512);
vertex(300, 500, 0, 512);
endShape();
popMatrix();
}
void drawDome() {
blendMode(BLEND);
pushMatrix();
beginCamera();
perspective(45, 1200.0/800.0, 0.1, 1000.0);
camera(
0.0, 200.0, 150.0,
0.0, 0.0, 25.0,
0.0, 1.0, 0.0);
pushMatrix();
rotate(scrollY / 1000.0, 1, 0,0);
rotate(scrollX / 1000.0, 0, 0, 1);
// Render Grid, write Z
blendMode(ADD);
noLights();
noFill();
beginShape(LINES);
stroke(128, 128, 128);
strokeWeight(1);
for (int g=-20; g<=20; g++) {
float x = (float)g * 20.0;
vertex(-400, x, 0);
vertex(400, x, 0);
vertex(x, -400, 0);
vertex(x, 400, 0);
}
endShape();
noStroke();
// Render base color shape, write Z
blendMode(BLEND);
spotLight(255, 255, 255, 300, -150, 140, -1, 0, -0.5, PI/2, 2);
beginShape(QUADS);
fill(80, 80, 80);
_drawDomeShape(0, 100.0, 1.0, 1.0);
endShape();
//fill(100, 255, random(255));
//box(100);
noLights();
// Render layer 1, additive, do not write Z
hint(DISABLE_DEPTH_MASK);
blendMode(ADD);
beginShape(QUADS);
cylinderTex.bind();
_drawDomeShape(1, 101, cylinderTex.width, cylinderTex.height);
endShape();
blendMode(ADD);
beginShape(QUADS);
topTex.bind();
_drawDomeShape(2, 102, topTex.width, topTex.height);
endShape();
hint(ENABLE_DEPTH_MASK);
popMatrix();
endCamera();
popMatrix();
}
void draw() {
cylinderTex.update();
topTex.update();
scrollX += velocityX;
scrollY += velocityY;
velocityX *= 0.95;
velocityY *= 0.95;
background(64);
noStroke();
textSize(14);
drawUI();
//drawTest();
drawDome();
}
void mouseDragged() {
velocityX += mouseX - pmouseX;
velocityY += mouseY - pmouseY;
}
void keyPressed() {
if (key == '1') {
cylinderTex.trigger();
}
if (key == '2') {
topTex.trigger();
}
if (key == 'q') {
selectTarget = 1;
selectInput("Select a .mov or .png", "fileSelected");
}
if (key == 'w') {
selectTarget = 2;
selectInput("Select a .mov or .png", "fileSelected");
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment