Updates

GML Field Recorder Challenge Deadline Extended!

September 08, 2011

The GML Field Recorder Challenge has been extended by two months until Nov. 1. All entries should be emailed to challenge[at]graffitimarkuplanguage[dot]com before this date.

The GML Field Recorder Challenge is a friendly competition to create an easily reproducible DIY device for unobtrusively recording graffiti motion data during a graffiti writer’s normal practice in the city. For full details go to http://www.graffitimarkuplanguage.com/challenges/gml-field-recorder-challenge/

Recording GML

July 09, 2011

Recording GML basics

To record GML, you can use a GmlRecorder object.
The simplest constructor of this object takes a single argument which is a 3D vector giving information about the drawing surface.
For instance, if you’re drawing on a flat screen which size is 800×600, creating a new GmlRecorder will look like this:

import gml4u.brushes.*;
import gml4u.recording.*;
import gml4u.test.*;
import gml4u.utils.*;
import gml4u.drawing.*;
import gml4u.events.*;
import gml4u.model.*;

// Declare a GML recorder object
GmlRecorder recorder;

void setup() {
	Vec3D screen = new Vec3D(800, 600, 0);
	recorder = new GmlRecorder(screen);
}

The recorder has 3 different methods that you have to use to record a stroke.
When the drawing of a stroke starts, you have to call the beginStroke method which takes a single argument being a unique ID that you will use when adding points and at the end of the stroke.
Having an ID allows you to draw several strokes in the meantime when needed without messing up points and strokes

recorder.beginStroke(666);

When adding points to a stroke, you need to use a minim of two arguments.
First argument is the unique ID we mentionned above.
Second argument is the coordinates of the point, which have to fit within 0 and 1.
Each value between 0 and 1 has to be the ratio of the point’s coordinates on each axis.
If you screen vector is 800x600x100 and the current coordinates of your point are 400,400, 25, then your point coordinates will be 0.5, 0.66, 0.25

recorder.addPoint(666, new Vec3D(0.5, 0.66, 0.25));

When the drawing of the stroke ends, just call this method with the ID

recorder.endStroke(666);

The recorder handles a Gml object and a temporary stroke list in parallel.
When a stroke ends, it is moved from the temporary list to the Gml object.

Alternatively, you can use the endStrokes() method which will stop all recordings in one shot:

recorder.endStrokes();

Advanced beginStroke

If you intend to work with several layers, you can call the beginStroke method with an extra parameter to store this info along with the stroke information.

recorder.beginStroke(666, 1);

Note: there is a third parameter that you can use which will be covered when we’ll talk about brushes later on.

Advanced GmlPoints

The recorder also has addPoint methods which will accept more complex GmlPoint
addPoint(int sessionID, Vec3D v, final float time);
Takes a 3rd argument to store time information

addPoint(int sessionID, Vec3D v, final float time, final float pressure, final Vec3D rotation, final Vec3D direction);
Takes even more arguments

  • Time
  • Pressure: think spray can of flow pen
  • Rotation: orientation of the tool (ie: spray can)
  • Direction: direction of the tool (between two points)

The recorder also includes several useful methods:


recorder.clear()
// Removes all strokes, the Gml ones and the temporary ones.


recorder.removeLastStroke(layer)
// Removes the last stroke from the given layer


recorder.getStrokes()
// Retrieves a list of GmlStrokes (both Gml strokes and temporary strokes)


recorder.getGml()
// Returns a copy of the Gml object used by the recorder


recorder.setGml(gml);
// Will replace the recorder's gml file with this one.
// Can be used to continue drawing from an existing Gml file.

Optimizing recording

Your recording device may send way more points than needed to render a stroke correctly.
If you want to limit the number of points, you may add limitations to the GmlRecorder by adding two extra arguments:


float minimumStrokeLength = 0.01f; // Default value when omitted
float minimumPointsDistance = 0.001f; // Default value when omitted
recorder = new GmlRecorder(screen, minimumStrokeLength, minimumPointsDistance);

By doing so:
When a stroke ends, it will only be recorded in the Gml object if longer than the value you defined.
When adding a point to a stroke, it will only be added if the distance between this point and the last point of the stroke is greater than the value you defined.

These values can be adjusted afterward by calling these two methods with a float argument
recorder.setMinStrokeLength();
recorder.setMinPointsDistance();

Recording with devices

It is handy to use a protocol like OSC or TUIO for recording purpose.
Once you have your recorder understanding such protocol, it means that you can interface with any device or installation which can send OSC or TUIO messages.
It also means that you’ll be able to record several strokes in the meantime.

You can check the two examples provided with the library

  • GmlOscRecorder
  • GmlTuioRecorder

| Tags: ,

Saving GML files

As for loading a Gml file, you have two ways to save Gml files.

  • The simple way : the execution of your sketch will hang until the file is saved.
  • The threaded way : won’t block your sketch.

Simple way

import gml4u.brushes.*;
import gml4u.recording.*;
import gml4u.test.*;
import gml4u.utils.*;
import gml4u.drawing.*;
import gml4u.events.*;
import gml4u.model.*;

// Gml object
Gml gml;

void setup() {
	gml = new Gml();
}

void draw() {
	// Add strokes, ... to your Gml object
}

void keyPressed() {
	if (key == 's' || key == 'S') {
		GmlSavingHelper.save(gml, sketchPath+"/gml.xml");
	}
}

The saving is done through the GMLSavingHelper’s save() static method.
This method has two arguments:
- The Gml object to be saved
- The path where is should be saved

Threaded way

import gml4u.brushes.*;
import gml4u.recording.*;
import gml4u.test.*;
import gml4u.utils.*;
import gml4u.drawing.*;
import gml4u.events.*;
import gml4u.model.*;

// Declare a Gml object and GmlParser
Gml gml;
GmlSaver saver;

void setup() {
	// Create and start the thread with a 500ms waiting time, a name and a reference to your sketch (this)
	saver = new GmlSaver(500, "mySaver", this);
	saver.start();
}

void draw() {
	// Add strokes, ... to your Gml object
}

void keyPressed() {
	if (key == 's' || key == 'S') {
		saver.save(gml, sketchPath+"/gml.xml");
	}
}

// Callback function used by the GmlSaver to send the result of the saving
public void gmlEvent(GmlEvent event) {
	if (event instanceof GmlSavingEvent) {
		GmlSavingEvent savingEvent = (GmlSavingEvent) event;
		boolean result = savingEvent.successful;
		String location = savingEvent.location;
		println((result ? "Succeeded" : "Failed")+ " saving Gml file to " + location);
	}
}

Explainations
When the GmlSaver is created, il will try to find a public gmlEvent method with a GmlEvent argument.
If missing or incorrect, depending on your log level (something that we will see later on), the GmlSaver will log an error and nothing more will happen.
This gmlEvent method will be called at the end of the saving.
This method takes a generic argument, which is the GmlEvent class.
This is generic to keep a single entry point and avoid the need to have as many callbacks as event types.
To know which event type was returned, you have to test it using the instanceof comparator against one of the expected classes extending GmlEvent.
Here, we’re expecting a GmlSaving event, so we test if this is correct and create a copy of it to get the results.

if (event instanceof GmlParsingEvent) {
	if (event instanceof GmlSavingEvent) {
		GmlSavingEvent savingEvent = event;
		boolean result = savingEvent.successful;
		String location = savingEvent.location;
		println((result ? "Succeeded" : "Failed") + " saving Gml file to " + location);
	}
}

As seen before for the GmlParsingEvent, this can also be achieved by casting the GmlEvent to a GmlSavingEvent

if (event instanceof GmlSavingEvent) {
	boolean result = ((GmlSavingEvent) event).successful;
	String location = ((GmlSavingEvent) event).location;
	println((result ? "Succeeded" : "Failed")+ " saving Gml file to " + location);
}

| Tags: ,

Brushes and styles

Brushes

You can attach a brush info to give more info about a GmlStroke.
This basically allows you to store information about the tool used to draw and thus reuse this info when you’ll redraw what you captured.


GmlBrush brush = new GmlBrush();

This constructor without arguments will create a new GmlBrush using the default brush from GML4U (curve).
You can add as many parameter to it, just knowing it only accepts 6 kind of object:

Vec3D
String
Integer
Float
Long
Color

When adding a parameter, you have to give it a name (String) that you can use later on when you want to retrieve a specific parameter.


brush.set("alpha", 128);
brush.set("cap", "fat");

When retrieving a parameter, you’ll have to know his type and cast it to get the correct value because the brush’s get method returns generic objects.


String capType = (String) brush.get("cap");
int alphaChannel = (int) brush.get("alpha");

When saving as a GML file, your brush information will be automatically saved to the correct format. Same thing when loading the saved file.

There are already a few predefined brushes that you can use without having to create custom ones.

You can get a list of pre-existing brushes through the GmlBrushManager

import gml4u.brushes.*;
import gml4u.recording.*;
import gml4u.test.*;
import gml4u.utils.*;
import gml4u.drawing.*;
import gml4u.events.*;
import gml4u.model.*;

GmlBrushManager brushManager = new GmlBrushManager();

void setup() {
	for (String styleId : brushManager.getStyles()) {
		println(styleId);
	}
}

At the time being, you should get this as output:

GML4U_STYLE_CURVES0000
GML4U_STYLE_BOXES0000
GML4U_STYLE_MESH0000

Forcing styles

(Maybe take a look at the “Drawing Gml” tutorial first)
You may bypass the GmlStroke brush information by explicitely passing a style information to the GmlBrushManager’s draw method.

By default, the GmlBrushManager contains a certain number of predefined GmlStrokeDrawers.
You can make reference those styles using one of these parameters:
GML4U_STYLE_CURVES0000
GML4U_STYLE_BOXES0000
GML4U_STYLE_MESH0000

So, if you want to use boxes rather than a simple curve stroke, you can call the GmlBrushManager with an extra parameter.

import gml4u.brushes.*;
import gml4u.recording.*;
import gml4u.test.*;
import gml4u.utils.*;
import gml4u.drawing.*;
import gml4u.events.*;
import gml4u.model.*;

GmlBrushManager brushManager = new GmlBrushManager();
Gml gml;

void setup() {
	// ie: Load a Gml file
}

void draw() {
	brushManager.draw(g, gml, 600, "GML4U_STYLE_BOXES0000");
}

Here is another example which allows you to loop through all the registered styles easily using the + and – keys while your sketch is running.

import gml4u.brushes.*;
import gml4u.recording.*;
import gml4u.test.*;
import gml4u.utils.*;
import gml4u.drawing.*;
import gml4u.events.*;
import gml4u.model.*;

GmlBrushManager brushManager = new GmlBrushManager();
Gml gml;
int currentStyle = 0;

void setup() {
	// ie: Load a Gml file
}

void draw() {
	brushManager.draw(g, gml, 600, GmlBrushManager.get(currentStyle);
}

void keyPressed() {
	if (key == '-') {
		currentStyle--;
		if (currentStyle < 0) currentStyle = GmlBrushManager.size()-1;
	}
	else if (key == '+') {
		currentStyle++;
		if (currentStyle == GmlBrushManager.size()) currentStyle = 0;
		}
	}
}

| Tags: ,

Custom styles

You may add custom styles to the GmlBrushManager by creating your own classes extending the GmlStrokeDrawerBasic or GmlStrokeDrawer classes.

GmlStrokeDrawerBasic
This is an abstract class extending GmlStrokeDrawer.
It has a single abstract draw method that you have to implement as follow with your own way to draw points, given the fact that you’ll have 2 GmlPoint available (current and previous ones).
For this purpose, you’ll use the standard Processing methods prefixed by “g.”

In this example, we draw a simple line between each point, assuming that we are in 3D mode.

class MyCustomDrawer extends GmlStrokeDrawerBasic {

	public draw(PGraphics g, GmlPoint prev, GmlPoint cur) {
		g.line(prev.x, prev.y, prev.z, cur.x, cur.y, cur.z);
	}
}

Then, in your Processing main program, you’ll create an object of this class, and make it available through the GmlBrushManager.

import gml4u.brushes.*;
import gml4u.recording.*;
import gml4u.test.*;
import gml4u.utils.*;
import gml4u.drawing.*;
import gml4u.events.*;
import gml4u.model.*;

GmlBrushManager brushManager = new GmlBrushManager();
Gml gml;

void setup() {
	size(600, 400, P3D);
	// Load a gml file
	
	// Create a custom drawer and register it as default drawer
	MyCustomDrawer customDrawer = new MyCustomeDrawer();
	brushManager.setDefault(customDrawer);
}

void draw() {
	brushManager.draw(g, gml, 600); 
}

This example won’t work and you’ll get an error if you use a 2D renderer.
If you apply the following modifications to your draw method, you will be 2D and 3D compliant.

class MyCustomDrawer extends GmlStrokeDrawerBasic {

	public draw(PGraphics g, GmlPoint prev, GmlPoint cur) {
		if (g.is3D()) {
			g.line(prev.x, prev.y, prev.z, cur.x, cur.y, cur.z);
		}
		else if (g.is2D()) {
			g.line(prev.x, prev.y, cur.x, cur.y);
		}
	}
}

Drawing GmlStrokes individually

You may draw strokes by looping through the Gml’s strokes.
The main advantage of it is that you can change parameters in between (like the color).

import gml4u.brushes.*;
import gml4u.recording.*;
import gml4u.test.*;
import gml4u.utils.*;
import gml4u.drawing.*;
import gml4u.events.*;
import gml4u.model.*;

GmlBrushManager brushManager = new GmlBrushManager();
Gml gml;

void setup() {
	size(600, 400, P3D);
	// Load a gml file
	
	// Create a custom drawer and register it as default drawer
	MyCustomDrawer customDrawer = new MyCustomeDrawer();
	brushManager.setDefault(customDrawer);
}

void draw() {
	for (GmlStroke stroke : gml.getStrokes()) {
		// Change colors according to what's stored in the GmlBrush
		GmlBrush brush = stroke.getBrush();
		color(brush.get("color");
		brushManager.draw(g, stroke, 600); 
	}
}

| Tags: ,

Other useful stuff

List files in a directory

If you stored a lot of Gml files in a directory and want to retrieve them easily, you may use
another utility class to get a list witch could be filtered as well using a regular expression.
The static method of the FileUtils class may be used for this purpose.

This will list any file located in the “gml_folder” located at the root of your sketck.

List gmlFiles = FileUtils.scanFolder("gml_folder", "");

To retrieve .gml files only, you may use this in conjunction with a regular expression.

List gmlFiles = FileUtils.scanFolder("gml_folder", ".*\\.gml");

| Tags: ,

Working with time

Timer
To ease the use of time, the library comes with a timer that you can use for both recording and replay.
Here is a timer example that you can adapt to both recording or replay situations.

import gml4u.brushes.*;
import gml4u.recording.*;
import gml4u.test.*;
import gml4u.utils.*;
import gml4u.drawing.*;
import gml4u.events.*;
import gml4u.model.*;

Timer timer = new Timer();

void setup() {
	timer.setStep(10);
	ellipseMode(CENTER);
	fill(255, 0, 0);
}

void draw() {
	// Increments the timer by the interval defined earlier
	timer.tick();
	// Alternatively, you can call the same method and passing the interval that you want
	// timer.tick(10);
	text(""+timer.getTime(), 20, 20);
	if (timer.started()) { // Draws a red circle
		ellipse(10, 10, 10, 10);
	}
	if (timer.paused()) {
		text("||", 5, 5);
	}
}

void keyPressed() {
	if (key == 'a' || key == 'A') {
		// Starts the timer
		timer.start();
	}
	if (key == 'z' || key == 'Z') {
		// Pause/Continue
		timer.pause(!timer.paused());
	}
	if (key == 'e' || key == 'E') {
		// Stops the timer and resets the timer
		timer.stop();
	}
	if (key == 'r' || key == 'R') {
		// Resets the timer (time set to 0)
		timer.reset();
	}
}

Timebox

For some reasons, you may want to draw gml files consecutively but also want them to have the same duration.
To do so, you can timebox the gml by using the static method timebox of the GmlUtils class.
This method takes 3 parameters:
A Gml object you wanna modify
The total duration (in seconds)
A boolean to tell wether you want the time ratio being kept or not.

If true:
If the Gml object has time information, then it will be timeboxed y setting the first point’s time to 0 and mapping every other point between 0 and the target duration according to its original time.
This basically means that the drawing rythme will be kept.
If the Gml object has no time information, then every stroke’s point will be mapped between 0 and the target duration based on an interval calculated using the total number of points in the Gml file.
This means that strokes will be drawn one after the others.

If false:
Will be the same as set to true when the Gml object has no time information.

import gml4u.brushes.*;
import gml4u.recording.*;
import gml4u.test.*;
import gml4u.utils.*;
import gml4u.drawing.*;
import gml4u.events.*;
import gml4u.model.*;

GmlBrushManager brushManager = new GmlBrushManager();
Gml gml;

void setup() {
	size(600, 600);
	// Load a gml file
	
	// Timebox it to 15 seconds
	GmlUtils.timebox(gml, 15, true);
	//GmlUtils.timebox(gml, 15, false);
}

void draw() {
	brushManager.draw(g, gml, 600); 
}

| Tags: ,

GML Recording Machine

June 13, 2011

Muharrem Yildirim has developed the first major contender towards solving the GML Field Recorder Challenge, which is a 1200 euro prize to produce an easily reproducible DIY device that can unobtrusively record graffiti motion data during a graffiti writer’s normal practice in the city. The GML Recording Machine uses a hacked mechanical mouse in combination with an Arduino to measure the length of two strings attached to the graffiti writer’s feet. The motion captured data is stored in an on board SD card and, with a simple script, is later converted to Graffiti Markup Language (.gml) format. An instruction guide for how to build the device from low cost materials will be on Muharrem’s blog shortly.

The GML Recording Machine is an exciting step forward in the development of technologies for real (as opposed to simulated) graffiti.


| Tags: , ,

GML Recording Machine (project added)…

January 29, 2011

The GML Recording Maching, by Muharrem Yildirim and Aytac Kanaci, is a big step forward in the race to solve the GML Challenge. We will post more updates on the project from them as they come in. For more information on the project check out their page at: http://muharrem-yildirim.com/projects/gml-recording-machine/

Comments (1)

Graffiti Analysis & GML @ Transmediale…

January 27, 2011

A new three channel installation of Graffiti Analysis will be on display in the Open Zone at Transmediale (Berlin) from Feb. 1 – 6. If you haven’t already voted for Graffiti Analysis & GML in the Open Web Award, please do so (very few people are voting, so every vote counts a lot). Thanks a lot to everyone that’s taken the time to vote!

In other GML / Transmediale related news, GRL Germany (of no formal connection to GRL or GML) will be presenting their SVG2BVG project as part of Open Design City’s ‘Make Your Own Market’ event in ‘The Open Zone‘. GRL.de writes “SVG2BVG uses a custom software application to detect graffiti tags, and writes the ensuing shape directly to GCode file, allowing it to be sent to a laser cutter… then cuts it into a stencil, sized exactly for the screens on the Berlin U-Bahn.

GRL.de will be releasing GML complaint versions of SVG2BVG and a new Laser Tag shortly.

Graffiti Analysis vs JaydioHead

January 19, 2011

Graffiti Analysis used for music video to Max Tannone's JaydioHead. Video by Justin Wilson here: http://vimeo.com/17533753

| Tags:

Laser Tag For Free Speech At MOCA

Exciting use of Laser Tag to protest censorship issues in the arts at the MOCA in Los Angeles. To read more about the controversy surrounding Jeffrey Deitch’s and MOCA’s decision to remove a mural by BLU see the following:

LA Times
Huffington Post
BoingBoing

| Tags: , , ,

kml2gml Added!

November 28, 2010

kml2gml by YAMAGUCHI Takahiro now updated on the Projects page.

Laser Tag (Touch Designer) Added!

Laser Tag (Touch Designer) by Achim Kern now updated on the Projects page.

Livewriter Added…

November 09, 2010

Livewriter added to the Projects section.

TouchTag (Android) Added…

TouchTag added to the Projects section.

Viscosity SenseWall Added…

Viscosity SenseWall by xDA added in Projects.

More .gml + Flash updates from Turbo Connard…

October 28, 2010

More Flash + .gml from Turbo Connard updated in the Projects section. Source code available here.

Eyewriter Robot – Tempt Font A-Z

October 25, 2010

.gml data designed by TEMPT1 using the EyeWriter.

Via Theo:
“evolution of Golan’s GML Robo Arm: vimeo.com/​8691659

big thanks to Jan and Gijs of Polynorm for amazing code and engineering help and lending us their robot :)”

GML + TEMPT1 + Eyewriter + PrintBall @BLK river Festival

October 23, 2010

From Benjamin Gaulon:

“Using the Graffiti Markup Language (GML) the PrintBall, a Graffiti Robot made of a PaintBall Gun and a custom made Pan&Tilt Unit controlled by a Max/Msp based software, was able to shot a Graffiti created by TEMPT on the EyeWriter (ref. temptTag-2009_8_24_19_15_48).

The EyeWriter project is an ongoing collaborative research effort to empower people who are suffering from ALS with creative technologies.”

Interactive 3D Flash Viewer Added!

Interactive 3D Flash Viewer by Devon O. Wolfgang has been added to the Projects page: http://www.graffitimarkuplanguage.com/interactive-3d-flash-viewer/

GML html5 player Added!

GML html5 player by Developer: Scott Downe has been added to the Projects page:

Graffiti Analysis Flash Added!

Flash source code for use with .gml data by Turbo Connard. English translation of his page here. Project page here: http://www.graffitimarkuplanguage.com/graffiti-analysis-flash-test/

graf2gml Added!

Project: graf2gml
Developer: Andrew Thomas
URL: http://www.hellocatfood.com/2010/10/07/graffiti-analysis-at-inside-out/

graf2gml by Andrew Thomas. An application for converting .graf files (an older format exported by the Linux version of Graffiti Analysis) into .gml:

http://www.graffitimarkuplanguage.com/graf2gml/

Used for an event at the Inside Out Festival:

Cafe Babe Graffiti Viewer for Android Added!

Cafe Babe Graffiti Viewer Android App by Roberto Marquez added to the Projects section: http://www.graffitimarkuplanguage.com/cafe-babe-graffiti-viewer/

Simple AIR GML Recorder Added!


Simple AIR GML Recorder by Cycan[c] Design has been added to the project page (complete with download and source code): http://www.graffitimarkuplanguage.com/simple-air-gml-recorder/

SVG Graffitis Added!

SVG Graffitis by Vincent Hardy has been added to the Projects page: http://www.graffitimarkuplanguage.com/svg-graffitis/




Graffiti Analisys + .gml data from Drawvolution

GML4U Processing Library

September 09, 2010

Jérôme Saint-Clair brings us GML4U which “aims to help the Processing community step into GML”. More from him below…

You are invited to contribute and implement your own custom drawers.
More info soon: stay tuned to @gml4u on Twitter

To start using GML4U, you can check the Tutorial from the top menu.

GML4U provides all the mechanisms to help you in the parsing and drawing of GML content.

You are invited to contribute and implement your own custom drawers.

GML Viscosity by Victor Martins is officially launched!

“GML Viscosity is an experiment. It is application used to draw GML tags on a viscous liquid rendered purely on the GPU side.

What does it do?
- It liquifies your tags, in a way you can hardly read them, but it looks cool.
- It is able to load gml files from the disk or load them directly from the “lots of zeros” book database.”

Application and source code:
Windows Version | MacOSX Version

GML Museum Hack

September 04, 2010

Jérôme Saint-Clair throwing up some GML in the Jeu de Paume. Stay tuned for big updates to his GML4U Processing Library.

| Tags:

Cap Hack How To….

September 01, 2010

Drawvolution just sent over a how to guide for the Cap Hack

Cap Hack…

August 31, 2010


Very cool new spray cap hack from drawvolution for use with Graffiti Analysis. Stay tuned updates.

graffitimarkuplanguage.com is Live!!!