Index: src/CodeSwarmConfig.java =================================================================== --- src/CodeSwarmConfig.java (revision 285) +++ src/CodeSwarmConfig.java (working copy) @@ -85,6 +85,8 @@ public static final String FILE_LIFE_KEY = "FileLife"; /** How long to keep people alive */ public static final String PERSON_LIFE_KEY = "PersonLife"; + /** Boolean value, controls video displaing on window */ + public static final String SHOW_VIDEO = "ShowVideo"; /** Boolean value, controls using the OpenGL library (experimental) */ public static final String USE_OPEN_GL = "UseOpenGL"; /** Percentage of life to highlight */ Index: src/code_swarm.java =================================================================== --- src/code_swarm.java (revision 285) +++ src/code_swarm.java (working copy) @@ -48,6 +48,7 @@ import processing.core.PApplet; import processing.core.PFont; +import processing.core.PGraphics; import processing.core.PImage; /** @@ -92,6 +93,7 @@ PFont font; PFont boldFont; PImage sprite; + PGraphics graph; // Graphics state variables boolean looping = true; @@ -104,6 +106,8 @@ boolean showEngine = false; boolean showHelp = false; boolean takeSnapshots = false; + boolean showVideo = true; + boolean useOpenGL = false; boolean showDebug = false; boolean drawNamesSharp = false; boolean drawNamesHalos = false; @@ -189,15 +193,26 @@ } maxBackgroundThreads=cfg.getIntProperty(CodeSwarmConfig.MAX_THREADS_KEY,4); + if (maxBackgroundThreads <= 0) { maxBackgroundThreads = 4; } + backgroundExecutor = new ThreadPoolExecutor(1, maxBackgroundThreads, Long.MAX_VALUE, TimeUnit.NANOSECONDS, new ArrayBlockingQueue(4 * maxBackgroundThreads), new ThreadPoolExecutor.CallerRunsPolicy()); + if (cfg.getBooleanProperty(CodeSwarmConfig.SHOW_VIDEO, showVideo)) { + showVideo = true; + } else { + showVideo = false; + } + if (cfg.getBooleanProperty(CodeSwarmConfig.USE_OPEN_GL, false)) { - size(width, height, OPENGL); + useOpenGL = true; + size( showVideo? width: 1, showVideo? height: 1, OPENGL); + } else { - size(width, height); + useOpenGL = false; + size( showVideo? width: 1, showVideo? height: 1); } if (cfg.getBooleanProperty(CodeSwarmConfig.SHOW_LEGEND, false)) { @@ -379,9 +394,26 @@ System.exit(1); } - smooth(); - frameRate(FRAME_RATE); + if (true == useOpenGL && false == showVideo) { + System.out.println( + "It's not possible to use createGraphics() with the OPENGL renderer, because it doesn't allow offscreen use."); + System.out.println("http://dev.processing.org/reference/core/javadoc/processing/core/PApplet.html"); + System.exit(1); + } + if (true == showVideo) { + graph = this.g; + + } else { + graph = this.createGraphics(code_swarm.width, code_swarm.height, /*OpenGL is coming*/ JAVA2D); + } + + graph.smooth(); + + if ( true == showVideo ) { + frameRate(FRAME_RATE); + } + // init data structures nodes = new HashMap(); edges = new HashMap, Edge>(); @@ -420,7 +452,7 @@ font = createFont(fontName, fontSize); boldFont = createFont(fontNameBold, fontSizeBold); - textFont(font); + graph.textFont(font); String SPRITE_FILE = cfg.getStringProperty(CodeSwarmConfig.SPRITE_FILE_KEY); // Create the file particle image @@ -453,7 +485,8 @@ */ public void draw() { long start = System.currentTimeMillis(); - background(background); // clear screen with background color + graph.beginDraw();//beginFrame + graph.background(background); // clear screen with background color this.update(); // update state to next frame @@ -480,7 +513,7 @@ node.draw(); } - textFont(font); + graph.textFont(font); // Show the physics engine name if (showEngine) { @@ -517,6 +550,8 @@ dumpFrame(); } + graph.endDraw(); + // Stop animation when we run out of data AND all nodes are dead if (eventsQueue.isEmpty()) { coolDown = true; @@ -552,24 +587,24 @@ * Surround names with aura */ public void drawPeopleNodesBlur() { - colorMode(HSB); + graph.colorMode(HSB); // First draw the name for (PersonNode p : livingPeople) { - fill(hue(p.flavor), 64, 255, p.life); + graph.fill(hue(p.flavor), 64, 255, p.life); p.draw(); } // Then blur it - filter(BLUR, 3); + graph.filter(BLUR, 3); } /** * Draw person's name */ public void drawPeopleNodesSharp() { - colorMode(RGB); + graph.colorMode(RGB); for (PersonNode p : livingPeople) { - fill(lerpColor(p.flavor, color(255), 0.5f), max(p.life - 50, 0)); + graph.fill(lerpColor(p.flavor, color(255), 0.5f), max(p.life - 50, 0)); p.draw(); } } @@ -578,13 +613,13 @@ * Draw date in lower-right corner */ public void drawDate() { - fill(255); + graph.fill(255); String dateText = formatter.format(prevDate); - textAlign(RIGHT, BASELINE); - textSize(font.size); + graph.textAlign(RIGHT, BASELINE); + graph.textSize(font.size); if (coolDown) dateText = "End of history: " + dateText; - text(dateText, width - 1, height - textDescent()); + graph.text(dateText, width - 1, height - graph.textDescent()); } /** @@ -593,7 +628,7 @@ public void drawHistory() { int x = 0; int heightMinusThree = height - 3; - rectMode(CORNERS); + graph.rectMode(CORNERS); for (ColorBins cb : history) { if (cb.totalCount > 0) { @@ -602,8 +637,8 @@ for (int k = 0; k < cb.keyCount; ++k) { int color = cb.keys[k]; endY += cb.colorMap.get(color); - stroke(color, 255); // 200 (nicer) vs. 255 (faster) - rect(x, heightMinusThree - startY, x, heightMinusThree - endY); + graph.stroke(color, 255); // 200 (nicer) vs. 255 (faster) + graph.rect(x, heightMinusThree - startY, x, heightMinusThree - endY); startY = endY; } } @@ -616,26 +651,26 @@ */ public void drawLoading() { - noStroke(); - textFont(font, 20); - textAlign(LEFT, TOP); - fill(255, 200); - text(loadingMessage, 0, 0); + graph.noStroke(); + graph.textFont(font, 20); + graph.textAlign(LEFT, TOP); + graph.fill(255, 200); + graph.text(loadingMessage, 0, 0); } /** * Show color codings */ public void drawLegend() { - noStroke(); - textFont(font); - textAlign(LEFT, TOP); - fill(255, 200); - text("Legend:", 0, 0); + graph.noStroke(); + graph.textFont(font); + graph.textAlign(LEFT, TOP); + graph.fill(255, 200); + graph.text("Legend:", 0, 0); for (int i = 0; i < colorAssigner.tests.size(); i++) { ColorTest t = colorAssigner.tests.get(i); - fill(t.c1, 200); - text(t.label, font.size, (i + 1) * font.size); + graph.fill(t.c1, 200); + graph.text(t.label, font.size, (i + 1) * font.size); } } @@ -643,10 +678,10 @@ * Show physics engine name */ public void drawEngine() { - fill(255); - textAlign(RIGHT, BASELINE); - textSize(10); - text(physicsEngineSelection, width-1, height - (textDescent() * 5)); + graph.fill(255); + graph.textAlign(RIGHT, BASELINE); + graph.textSize(10); + graph.text(physicsEngineSelection, width-1, height - (graph.textDescent() * 5)); } /** @@ -654,41 +689,41 @@ */ public void drawHelp() { int line = 0; - noStroke(); - textFont(font); - textAlign(LEFT, TOP); - fill(255, 200); - text("Help on keyboard commands:", 0, 10*line++); - text("space bar : pause", 0, 10*line++); - text(" a : show name halos", 0, 10*line++); - text(" b : show debug", 0, 10*line++); - text(" d : show date", 0, 10*line++); - text(" e : show edges", 0, 10*line++); - text(" E : show physics engine name", 0, 10*line++); - text(" f : draw files fuzzy", 0, 10*line++); - text(" h : show histogram", 0, 10*line++); - text(" j : draw files jelly", 0, 10*line++); - text(" l : show legend", 0, 10*line++); - text(" p : show popular", 0, 10*line++); - text(" q : quit code_swarm", 0, 10*line++); - text(" s : draw names sharp", 0, 10*line++); - text(" S : draw files sharp", 0, 10*line++); - text(" minus : previous physics engine", 0, 10*line++); - text(" plus : next physics engine", 0, 10*line++); - text(" ? : show help", 0, 10*line++); + graph.noStroke(); + graph.textFont(font); + graph.textAlign(LEFT, TOP); + graph.fill(255, 200); + graph.text("Help on keyboard commands:", 0, 10*line++); + graph.text("space bar : pause", 0, 10*line++); + graph.text(" a : show name halos", 0, 10*line++); + graph.text(" b : show debug", 0, 10*line++); + graph.text(" d : show date", 0, 10*line++); + graph.text(" e : show edges", 0, 10*line++); + graph.text(" E : show physics engine name", 0, 10*line++); + graph.text(" f : draw files fuzzy", 0, 10*line++); + graph.text(" h : show histogram", 0, 10*line++); + graph.text(" j : draw files jelly", 0, 10*line++); + graph.text(" l : show legend", 0, 10*line++); + graph.text(" p : show popular", 0, 10*line++); + graph.text(" q : quit code_swarm", 0, 10*line++); + graph.text(" s : draw names sharp", 0, 10*line++); + graph.text(" S : draw files sharp", 0, 10*line++); + graph.text(" minus : previous physics engine", 0, 10*line++); + graph.text(" plus : next physics engine", 0, 10*line++); + graph.text(" ? : show help", 0, 10*line++); } /** * Show debug information about all drawable objects */ public void drawDebugData() { - noStroke(); - textFont(font); - textAlign(LEFT, TOP); - fill(255, 200); - text("Nodes: " + nodes.size(), 0, 0); - text("People: " + people.size(), 0, 10); - text("Queue: " + eventsQueue.size(), 0, 20); - text("Last render time: " + lastDrawDuration, 0, 30); + graph.noStroke(); + graph.textFont(font); + graph.textAlign(LEFT, TOP); + graph.fill(255, 200); + graph.text("Nodes: " + nodes.size(), 0, 0); + graph.text("People: " + people.size(), 0, 10); + graph.text("Queue: " + eventsQueue.size(), 0, 20); + graph.text("Last render time: " + lastDrawDuration, 0, 30); } /** @@ -696,11 +731,11 @@ */ public void drawPopular() { CopyOnWriteArrayList al=new CopyOnWriteArrayList(); - noStroke(); - textFont(font); - textAlign(RIGHT, TOP); - fill(255, 200); - text("Popular Nodes (touches):", width-120, 0); + graph.noStroke(); + graph.textFont(font); + graph.textAlign(RIGHT, TOP); + graph.fill(255, 200); + graph.text("Popular Nodes (touches):", width-120, 0); for (FileNode fn : nodes.values()) { if (fn.qualifies()) { // Insertion Sort @@ -726,7 +761,7 @@ FileNode n = it.next(); // Limit to the top 10. if (i <= 10) { - text(n.name + " (" + n.touches + ")", width-100, 10 * i++); + graph.text(n.name + " (" + n.touches + ")", width-100, 10 * i++); } else if (i > 10) { break; } @@ -758,7 +793,7 @@ public void dumpFrame() { if (frameCount < maxFramesSaved) { final String outputFileName = insertFrame(SCREENSHOT_FILE); - final PImage image = get(); + final PImage image = graph.get(); backgroundExecutor.execute(new Runnable() { public void run() { @@ -1159,10 +1194,10 @@ * @param blue */ public void drawPoint (int x, int y, int red, int green, int blue) { - noStroke(); - colorMode(RGB); - stroke(red, green, blue); - point(x, y); + graph.noStroke(); + graph.colorMode(RGB); + graph.stroke(red, green, blue); + graph.point(x, y); } /** @@ -1176,11 +1211,11 @@ * @param blue */ public void drawLine (int fromX, int fromY, int toX, int toY, int red, int green, int blue) { - noStroke(); - colorMode(RGB); - stroke(red, green, blue); - strokeWeight(1.5f); - line(fromX, fromY, toX, toY); + graph.noStroke(); + graph.colorMode(RGB); + graph.stroke(red, green, blue); + graph.strokeWeight(1.5f); + graph.line(fromX, fromY, toX, toY); } } @@ -1320,9 +1355,9 @@ */ public void draw() { if (life > 240) { - stroke(255, life); - strokeWeight(0.35f); - line(nodeFrom.mPosition.x, nodeFrom.mPosition.y, nodeTo.mPosition.x, nodeTo.mPosition.y); + graph.stroke(255, life); + graph.strokeWeight(0.35f); + graph.line(nodeFrom.mPosition.x, nodeFrom.mPosition.y, nodeTo.mPosition.x, nodeTo.mPosition.y); } } @@ -1379,7 +1414,7 @@ name = fe.path + fe.filename; touches = fe.weight; life = FILE_LIFE_INIT; - colorMode(RGB); + graph.colorMode(RGB); minBold = (int)(FILE_LIFE_INIT * ((100.0f - HIGHLIGHT_PCT)/100)); nodeHue = colorAssigner.getColor(name); mass = FILE_MASS; @@ -1404,13 +1439,13 @@ } /** TODO : this would become interesting on some special event, or for special materials - * colorMode( RGB ); fill( 0, life ); textAlign( CENTER, CENTER ); text( name, x, y ); + * colorMode( RGB ); graph.fill( 0, life ); graph.textAlign( CENTER, CENTER ); graph.text( name, x, y ); * Example below: */ if (showPopular) { - textAlign( CENTER, CENTER ); + graph.textAlign( CENTER, CENTER ); if (this.qualifies()) { - text(touches, mPosition.x, mPosition.y - (8 + (int)Math.sqrt(touches))); + graph.text(touches, mPosition.x, mPosition.y - (8 + (int)Math.sqrt(touches))); } } } @@ -1458,45 +1493,45 @@ } public void drawSharp() { - colorMode(RGB); - fill(nodeHue, life); + graph.colorMode(RGB); + graph.fill(nodeHue, life); float w = 3; if (life >= minBold) { - stroke(255, 128); + graph.stroke(255, 128); w *= 2; } else { - noStroke(); + graph.noStroke(); } - ellipseMode(CENTER); - ellipse(mPosition.x, mPosition.y, w, w); + graph.ellipseMode(CENTER); + graph.ellipse(mPosition.x, mPosition.y, w, w); } public void drawFuzzy() { - tint(nodeHue, life); + graph.tint(nodeHue, life); float w = 8 + (sqrt(touches) * 4); // not used float dubw = w * 2; float halfw = w / 2; if (life >= minBold) { - colorMode(HSB); - tint(hue(nodeHue), saturation(nodeHue) - 192, 255, life); + graph.colorMode(HSB); + graph.tint(hue(nodeHue), saturation(nodeHue) - 192, 255, life); // image( sprite, x - w, y - w, dubw, dubw ); } // else - image(sprite, mPosition.x - halfw, mPosition.y - halfw, w, w); + graph.image(sprite, mPosition.x - halfw, mPosition.y - halfw, w, w); } public void drawJelly() { - noFill(); + graph.noFill(); if (life >= minBold) - stroke(255); + graph.stroke(255); else - stroke(nodeHue, life); + graph.stroke(nodeHue, life); float w = sqrt(touches); - ellipseMode(CENTER); - ellipse(mPosition.x, mPosition.y, w, w); + graph.ellipseMode(CENTER); + graph.ellipse(mPosition.x, mPosition.y, w, w); } } @@ -1528,16 +1563,16 @@ */ public void draw() { if (isAlive()) { - textAlign(CENTER, CENTER); + graph.textAlign(CENTER, CENTER); /** TODO: proportional font size, or light intensity, or some sort of thing to disable the flashing */ if (life >= minBold) - textFont(boldFont); + graph.textFont(boldFont); else - textFont(font); + graph.textFont(font); - text(name, mPosition.x, mPosition.y); + graph.text(name, mPosition.x, mPosition.y); } } @@ -1547,8 +1582,8 @@ } public void addColor(int c) { - colorMode(RGB); - flavor = lerpColor(flavor, c, 1.0f / colorCount); + graph.colorMode(RGB); + flavor = graph.lerpColor(flavor, c, 1.0f / colorCount); colorCount++; } } Index: data/sample.config =================================================================== --- data/sample.config (revision 285) +++ data/sample.config (working copy) @@ -49,7 +49,7 @@ ColorAssign10=".*src9.*", 238,68,119, 238,68,119 # Save each frame to an image? -TakeSnapshots=false +TakeSnapshots=true # Where to save each frame SnapshotLocation=frames/code_swarm-#####.png @@ -81,7 +81,7 @@ ShowEdges=false # Turn on Debug counts. -ShowDebug=false +ShowDebug=true # Natural distance of files to people EdgeLength=25 @@ -121,5 +121,9 @@ # Force calculation algorithms ("PhysicsEngineLegacy", "PhysicsEngineSimple"...) : PhysicsEngineSelection=PhysicsEngineLegacy +# Render video to window +# Can be used with TakeSnapshots=true for headless mode +ShowVideo=false + # OpenGL is experimental. Use at your own risk. UseOpenGL=false