abe.blog()

abe.blog.put ( graphics ) abe.blog.put ( code ) return true

To content | To menu | To search

Actually on abe.blog()

New WebSite / Nouveau Site

After a long time on dotclear it was time to switch, here my new website : From Bits To Pixels

Après un long moment sous dotcleat il était temps de changer, voici mon nouveau site : From Bits To Pixels

Setup Gedit as a Flash developpement tool

I primarily write this post as a reminder of all the search I go through in order to optimize my daily work with ActionScript (and some other languages) in Gedit.

There's not plenty of examples through the web on how to develop actionscript under Gedit, below are the few ones that are relevant :

  • This post or this post provides a *.lang file to add the syntax colouring for ActionScript.
  • This post show how to compile a file using the External Tools plug-in as I'll do myself later in this post.
  • And there's this plug-in listed in the Gedit2 list of third-party plug-ins, Automatic compilation for SWFTools, which says: Automatically call swfc compilation for saved file, if it has ".swfc" extension. But that's not what I am looking for.

Color syntax

First I really wasn't satisfied with the current syntax colouring files available on the web. ActionScript is quite verbose sometimes and it's good to have a proper way to visually recognize each elements. So I recreated my own language file based on the javascript one.

This one supports :

  • Typing (var, arguments, returns)
  • E4X (both declarations and access)
  • RegExp
  • Metadata
  • ASDoc comments
  • Conditional Compilation

The only case I wasn't able to fix yet is the ternary operator a ? b : c where c appear as a type.

You can find the language file in the attached files of this post or by clicking this link. You have to put this file in your ~/.local/share/gtksourceview2/language-specs/ directory.

Of course if you find some cases which are not covered by this file, don't hesitate to notice me in the comments.

External Tools setup

Add actionscript support in the External Tools links parser

To allow the output panel of the External Tools plug-in to detect error paths in the mxmlc output and provide the ad-hoc links, open the following file in your favourite text editor :

sudo gedit /usr/lib/gedit-2/plugins/externaltools/linkparsing.py

Then add this declaration at the end of the file :

# as3 'Test.as(8): col: 28'
REGEXP_AS3 = r"""
^(?P<lnk>
    (?P<pth> .*\.[aA][sS] )
    \(
    (?P<ln> \d+ )\)
)\:\s
"""

And finally add a self.add_regexp(REGEXP_AS3) in the init method of the LinkParser class.

That's it.

Advanced compilation script

This part is a bit harder. It use the same technique as This post on Experimentalized but with a more complex setup. This setup is designed to allow to compile both files that are in a structured project and files that are not.

The thing is, I prefer having all my main classes (the files to compile) at the root of a src folder in my project folder, then having a bin and a build directory at the same level. And still, there's always some times when I need to quickly test something without bothering about if the file is within a project or not, and where it is in the project.

Each build I need to setup will be stored in the build folder. Each including a common configuration file with some predefined setup such as common dependencies and differentiated options sets for release and debug builds. This way, all the compiled file in the project share the same settings.

The script will first check for the existence of the various folders and files, if they don't exist they're created. And then the build file is launched. The cool thing is when you have generated the build file the first time, you can modify it and it will be executed each time you launch the script. It allow you to have a really minimal setup which can works for all files, and, without losing the advantage of having a compilation command on a key short-cut, changing completely the setup of your build (with generation of the locale files or application signing in case of an AIR application).

Here what the tool file looks like :

#!/bin/sh
dir=$GEDIT_CURRENT_DOCUMENT_DIR
file=$GEDIT_CURRENT_DOCUMENT_NAME
file_base=${file%as}
ext='swf'
build_ext='build.sh'
report_ext='xml'

# avoid to process on something else that *.as files
if [ ${file%.*} != ".as" ]
then
	echo "Can't proceed on file $file, it must be an actionscript file"
	return
fi

# cut the path just before a src dir
src=${dir%/src*}

# test wether the file is in src or not
if [ $dir = $src ]
then 
	project_dir=${dir%/*}
	is_part_of_the_src_tree=0
	src_dir=$dir
	echo "$file is not in a src tree"
else
	project_dir=$src
	is_part_of_the_src_tree=1
	src_dir=$project_dir/src
	echo "$file is in a src tree"
fi

# setup other dir paths
build_dir=$project_dir/build
bin_dir=$project_dir/bin
reports_dir=$project_dir/reports

# test for existence of a bin, reports and build dir in the parent folder
if [ -e $build_dir ]
then
	build_dir_exist=1
else
	build_dir_exist=0
fi

if [ -e $bin_dir ]
then
	bin_dir_exist=1
else
	bin_dir_exist=0
fi

if [ -e $reports_dir ]
then
	reports_dir_exist=1
else
	reports_dir_exist=0
fi

# test whether we need to create bin and build folders
if [ $is_part_of_the_src_tree -eq 1 ]
then
	if [ $bin_dir_exist -eq 0 ]
	then 
		mkdir $bin_dir
		echo "$bin_dir din't exist and was created"
	fi
	
	if [ $build_dir_exist -eq 0 ]
	then 
		mkdir $build_dir
		echo "$build_dir din't exist and was created"
	fi
	
	if [ $reports_dir_exist -eq 0 ]
	then 
		mkdir $reports_dir
		echo "$reports_dir din't exist and was created"
	fi
	
	build=$build_dir/$file_base${build_ext}
	report=$reports_dir/$file_base${report_ext}
	build_commons=$build_dir/build-commons.sh
	output=$bin_dir/$file_base${ext}

elif [ $bin_dir_exist -eq 1 -o $build_dir_exist -eq 1 ]
then
	echo "$file is not in the src tree, but a build or a bin folder exist in the parent folder."
  if [ $bin_dir_exist -eq 0 ]
	then 
		mkdir $bin_dir
		echo "$bin_dir din't exist and was created."
	fi
	
	if [ $build_dir_exist -eq 0 ]
	then 
		mkdir $build_dir
		echo "$build_dir din't exist and was created"
	fi
	
	if [ $reports_dir_exist -eq 0 ]
	then 
		mkdir $reports_dir
		echo "$reports_dir din't exist and was created"
	fi
	
	build=$build_dir/$file_base${build_ext}
	report=$reports_dir/$file_base${report_ext}
	build_commons=$build_dir/build-commons.sh
	output=$bin_dir/$file_base${ext}
	
else
	echo "Builds for $file will be created in the same directory."
	report=$dir/$file_base${report_ext}
	build=$dir/$file_base${build_ext}
	build_commons=$dir/build-commons.sh
	output=$dir/$file_base${ext}

fi

# test whether the builds file exist or not, and then create it if they don't
if [ ! -e $build_commons ] 
then
	echo "
flex4=PATH/TO/YOUR/SDK\n\
mxmlc=\$flex4/bin/mxmlc\n\

\n\
# Here you can modify the default setups availables in your build files
# hint : use 4 backslash in the generator to display 1 in the generated ;)
default_options=\"-source-path+=$src_dir\" \n\
\n\
defaults_debug=\"-debug=true \$default_options\" \n\
\n\
defaults_release=\"\$default_options\" \n\ " > $build_commons
	echo "$build_commons didn't exist and was created"
fi

if [ ! -e $build ] 
then
	echo "#!/bin/sh \n\
. $build_commons \n\
\n\
echo 'Start compilation'\n\
\$mxmlc \$defaults_debug \\\\\n    -output $output \\\\\n    -link-report $report \\\\\n    -- $dir/$file \n\
\n\
gnome-open $dir/$file" > $build
	echo "$build didn't exist and was created"
fi

sh $build

You just have to create a new tools in the External Tools plug-in configuration dialog and paste the code above inside and then assigning it to the shortcut of your choice.

What does this script do ?
  1. We verify that the file to compile is part of a src folder, either at its root or in one of its sub-folders. The test is done by splitting the string before src, if the two strings are equals, the split failed and their is no src in the path.
  2. Then we check for the bin, build and reports folders in the parent directory of the current file directory. If they exists, even if the file isn't in the src tree, the build files will be created in that place. It allow you to compile files that exists in a folder in your project root. An examples folder for instance. If they don't exists, we will place the build and output files in the same folder than the compiled file.
  3. We can now check for the build files existence and create it if they don't.
  4. Finally we execute the main build file as we have made sure that it exist in the right place. And after the compilation, we open the file using the gnome-open command (For that, I recommend you to download a standalone debug version of the Flash Player and make the association within a Nautilus window).

You can notice that I automatically generates a report for each compilation using the -link-report option of mxmlc. I use the generated report as the source for the localisation generation. This is explain later in this post.

Other plug-ins that are pretty useful

Native
  • Snippets to easily create templates.
  • FileBrowser.
  • Sort to order the import mess from time to time.
From the gedit-plugins package

This package can be installed with :

sudo apt-get install gedit-plugins
  • Code Completion which complete with the words in all the active documents.
  • Bracket Completion.
  • Code Comment.
  • Color Picker.
  • Terminal.
  • Session Saver.
Third party
  • Line Tools which add support for delete/duplicate and move up or down lines.
  • Symbol Browser which use CTags to parse code and provide a raw outline of the file content.
  • File Search which allow to search a string in a set of files, and display the results with direct links in a tab in the bottom panel, really useful for refactoring ;).
  • Regex Search & Replace.
  • Right Pane because with all this plug-in you will need extra space to avoid to switch from panel tabs all the time.
  • Split View 3 to split a document view in two with the same or a different document in each part.

Symbol Browser setup

First things first, the Symbol Plugin require the exuberant-ctags package which can be installed with.

sudo apt-get install exuberant-ctags

This is what I can see in my Symbol Browser panel with the file in the previous screenshot.

To get the same results you can just download the ctags and the symbols.zip files at the end of this post. The former must be renamed to .ctags and placed in your home directory, the latter must be unzipped and then placed in the ~/.gnome2/gedit/ directory.

The CTags file also contains definitions for CSS, SCSS (Sassy CSS) and PixelBender Kernel files.

Other useful scripts

Localisation file generation

I use gettext to handle localisation. Based on the excellent post of Alessandro Crugnola and its actionscript3gettext lib.

To install the gettext utilities use the following command :

sudo apt-get install gettext

The process of generating the localisation is in 3 steps :

  1. Generates a *.fil file with all the source files to feed the xgettext utility.
  2. Generates a *.pot file with the xgettext utility.
  3. Generates the *.mo file which will contains the localisations to load in your application.

For the first step I use a small script I made myself and which can be found here. I simply create a symbolic link named asgettext in my ~/bin folder to use it freely from my Gedit script. The asgettext.py script takes a *.xml report file and generates the *.fil file with the path to all the source files compiled in the *.swf.

Then, here the Gedit script :

#!/bin/sh
dir=$GEDIT_CURRENT_DOCUMENT_DIR
file=$GEDIT_CURRENT_DOCUMENT_NAME
file_base=${file%as}
report_ext='xml'
fil_ext='fil'
pot_ext='pot'

# cut the path just before a src dir
src=${dir%/src*}

# test wether the file is in src or not
if [ $dir = $src ]
then 
	project_dir=${dir%/*}
	is_part_of_the_src_tree=0
	echo "$file is not in a src tree"
else
	project_dir=$src
	is_part_of_the_src_tree=1
	echo "$file is in a src tree"
fi

# setup other dir paths
locales_dir=$project_dir/bin/locales
reports_dir=$project_dir/reports

# test for existence of a report for this file dir in the project folder 
if [ -e $reports_dir ]
then
	reports_dir_exist=1
	report=$reports_dir/$file_base${report_ext}
else
	reports_dir_exist=0
	report=$dir/$file_base${report_ext}
fi

# if the file can't be found we exit
if [ ! -e $report ]
then
	echo "Can't find any report file for $file"
	echo "Exit"
	exit
fi

if [ -e $locales_dir ]
then
	locales_dir_exist=1
else
	locales_dir_exist=0
fi

# test whether we need to create the locales folders
if [ $is_part_of_the_src_tree -eq 1 ]
then
	if [ $locales_dir_exist -eq 0 ]
	then 
		mkdir $locales_dir
		echo "$locales_dir din't exist and was created"
	fi
		
	fil=$locales_dir/$file_base${fil_ext}
	locale=$locales_dir/$file_base${pot_ext}

elif [ $locales_dir_exist -eq 1 ]
then
	echo "$file is not in the src tree, but a locales dir exist in the parent folder."
	
	fil=$locales_dir/$file_base${fil_ext}
	locale=$locales_dir/$file_base${pot_ext}
	
else
	echo "Locales for $file will be created in the same directory."
	fil=$dir/$file_base${fil_ext}
	locale=$dir/$file_base${pot_ext}
fi

asgettext -o $fil -d $report
xgettext --from-code=UTF-8 -o $locale -L Python -f $fil

This script use the same structure rules as the previous one. It will check for the existence of a *.xml file for the current file either in the reports folder or in the source file's folder itself. If the reports folder have been found, a locales folder is created in the bin dir (if it don't exist yet), else the locales files will be created in the same folder as the current file. Then, all the path are created and both asgettext and xgettext are called with their corresponding arguments.

Finally to generates the *.mo files, you'll need to use whatever *.pot editor, such as PoEdit :

sudo apt-get install poedit
Pixel Bender Kernel compilation

If you use (or want to use) Pixel Bender in Gedit, below a script that compile a *.pbk file to a *.pbj file with the same name in the same folder.

If you don't know how to use Pixel Bender under linux, you can read my previous post Using PixelBender on Linux with Wine and PBDT.

For this script, I previously created a symbolic link to my pbutil file in my ~/bin directory.

#!/bin/sh
DIR=$GEDIT_CURRENT_DOCUMENT_DIR
FILE=$GEDIT_CURRENT_DOCUMENT_NAME
EXT='pbj'
PBJ=${FILE%pbk}${EXT}

if [ ${file%.*} != ".pbk" ]
then
	echo "Can't proceed on file $file, it must be a Pixel Bender Kernel file"
	return
fi

pbutil $DIR/$FILE $DIR/$PBJ

That's all for today. I have some other scripts under the hand but they're not actionscript related, so see you next time.

Edit 15/06/2011 I improved the scripts by testing the extension before doing anything, which was not done before.

Ludum Dare 20 - Rainbow Riding HoodZ

Pfiouu, weekend de fou furieux, 72 heures pour concevoir et réaliser un jeu avec mes compère Mr_Hk_ et Aries, on peut parler d'un sacré challenge.

Un grand merci à Motion Twin pour nous avoir hébergé le temps de la manifestation, ainsi qu'a Valandre et Deepnight qui nous ont accompagné pendant ce week end.

PLAY THE GAME

Voila :).

À bientôt.

Easy Array filtering in AS3 and JS

It's been a while since I wrote about code on this blog but I thought it was worth to share these little experiments with arrays.

A first note about the source of these experiments, I discovered Python and Django a few months ago and really started to like their simplicity, and I'd really want to see some of python sugar such as list comprehension, sequences slicing or decorators in ECMAScript languages (typically AS3 and JS). The latter is one of the sources that lead me to make these experiments. The second source is Hamcrest, and its as3 port, which is a small, but powerful, library of unit test matchers.

The question behind these experiment was the following : How can I make filtering and checking of arrays as easy as writing test with Hamcrest ? And the immediate answer was : With decorator functions !

Arrays in ECMAScript languages

Note : In all the examples I will use JavaScript instead of ActionScript3, but the AS3 versions are pretty much the same, and can be found here.

The Array class provides many method to filter or check its content, such as every and filter, these methods takes a function as its first argument and using them generally leads to write this kind of code :

var f = function( o, i, a ) { return !isNaN( o );  }
if( a.every( f ) )
{
    // do something
}

or even worst :

if( a.every( function( o, i, a ) { return !isNaN( o ); } ) )
{
    // do something
}

Personally I generally try to avoid this way, I prefer to create a private method in my class instead of the anonymous function. But in the end both are quite illegible.

Let's write some code to make this test a little more coder-friendly.

Decorators

Python defines decorators as A function returning another function, usually applied as a function transformation using the @wrapper syntax. In our case, only the first part make sense in an ECMA language, we can write functions that returns functions. If we take the previous example, the 'decorator' function will look like :

function notNaN ()
{
    return function( o, i, a ) { return !isNaN( o ); };
}

Then we can use it in our test :

if( a.every( notNaN() ) )
{
    // do something
}

The test is clearly more explicit than before. But we can do more than that.

Testing values

Let's write some more functions like the notNaN one:

function nan ()
{
    return function( o, i, a ) { return isNaN( o ); };
}
function notNaN ()
{
    return function( o, i, a ) { return !isNaN( o ); };
}
function nullValue ()
{
    return function( o, i, a ) { return o == null; };
}
function notNullValue ()
{
    return function( o, i, a ) { return o != null; };
}
// This one introduce decorators parameters. 
// Since an anonymous function is transformed 
// in a closure with all the context it was defined in,
// such as the call arguments or the locally declared
// variables, we can parametrize the returned function 
// to match a specific value.
function equalTo ( n )
{
    return function( o, i, a ) { return o == n; };
}
// This one introduce nested decorators handling.
// If a value is passed, the not decorator behave as
// a notEqualto decorator.
// If a function is passed, the not decorator simply
// swap the value returned by the function with the
// same arguments.
function not( f ) 
{
    if( f instanceof Function )
        return function( o, i, a ) { return !f( o, i, a ); };
    else
        return function( o, i, a ) { return o != f };
}
// This one works as a succession of && with all the
// arguments as expression.
// As the not decorator, the allOf support both functions
// or values as arguments and behave as an equalTo with values.
function allOf ()
{
    var args = arguments;
    return function( o, i, a )
    {
        var l  = args.length;
        for( var i = 0; i < l; i++ )
        {
            var f = args[i];
            if( f instanceof Function )
            {
                if( !f( o, i, a ) )
                    return false;
            }
            else
            {
                if( c != o )
                    return false;
            }
        }
        return true;
    };
}
// As allOf but with the || operator
function anyOf ()
{
    var args = arguments;
    return function( o, i, a )
    {
        var l  = args.length;
        for( var i = 0; i < l; i++ )
        {
            var f = args[i];
            if( f instanceof Function )
            {
                if( f( o, i, a ) )
                    return true;
            }
            else
            {
                if( c == o )
                    return true;
            }
        }
        return true;
    };
}
// This one test the type of the item using
// the typeof operator
function isA ( type )
{
	return function ( o, i, a ){ return typeof o == type; }
}
// This one test the type of the item using
// the instanceof operator
function instanceOf ( type )
{
	return function ( o, i, a ){ return o instanceof type; }
}

With theses little functions we can start to write tests and filters in a very flexible way :

var a = [ "foo", "bar", 10, {}, null, true ];

console.log( a.every( equalTo( "foo" ) ) ); // false

console.log( a.some( equalTo( "foo" ) ) ); // true

console.log( a.filter( anyOf( equalTo( "foo" ), nullValue() ) ) ); // [ "foo", null ];

console.log( a.filter( allOf( isA( "string" ), equalTo( "foo" ) ) ) ); // [ "foo" ];

console.log( a.filter( anyOf( isA( "string" ), isA( "object" ) ) ) ); // [ "foo","bar", {} ];

Testing item properties

But let's go deeper and implements properties matching :

function hasProperty( name, value )
{
	if( value == undefined )
		return function( o, i, a ) { return o.hasOwnProperty( name ); }
	else
	{
		if( value instanceof Function )
			return function( o, i, a ) { return o.hasOwnProperty( name ) && value( o[name], i, a ); }
		else
			return function( o, i, a ) { return o.hasOwnProperty( name ) && o == value }
	}
}
function hasProperties( dict )
{
	return function( o, i, a )
	{
		for( var j in dict )
		{
			if( !o.hasOwnProperty( j ) )
				return false;
			
			var value = dict[j];
			
			if( value instanceof Function )
			{
				if( !value(o[j],i,a) )
					return false;
			}
			else
			{
				if( o[j] != value )
					return false;
			}
		}
		return true;
	} 
}

And some example to illustrate how to use them :

var a = [ 12, 0, "bar", {'foo':"bar"}, {'foo':"bar", 'bar':new Object() }, {'foo':15} ];

console.log( a.some( hasProperty( "foo" ) ) );
// true		

console.log( a.every( hasProperty( "foo" ) ) );
// false	

console.log( a.filter( hasProperty( "foo" ) ) );
// [{'foo':"bar"},{'foo':"bar",'bar':new Object() }, {'foo':15}]

console.log( a.filter( hasProperty( "foo", allOf( isA("string"), equalTo("bar") ) ) ) );
// [{'foo':"bar"},{'foo':"bar",'bar':new Object() }]

console.log( a.filter( hasProperties( {
    "foo":"bar",
    "bar":isA("object") } ) ) );
// [{'foo':"bar",'bar':new Object() }]

This is a just a small demonstrations of some of the many combinations you can form. With this set (and some more functions such as the equivalents of the numbers and strings matchers in Hamcrest) you can start to write really complex queries over a collection of objects, from a JSON service for example.

Array structure

My last experiment was to check the array structure itself in the same way, I currently wrote three functions in that purpose :

// matchFixed will check for arrays that match exactly
// the conditions and length of the function arguments such as
// [a,b,c]
function matchFixed ()
{
	var struct = arguments; 
	return function( o, i, a ) 
	{
		if( i == 0 && a.length != struct.length )
			return false;
		
		var v = struct[i];
		
		if( v instanceof Function )
			return v( o, i, a );
		else
			return o == v;
	};
}

// matchCycle will check for redundant structure such as
// [a,b,c,a,b,c,...,a,b,c] or likes
function matchCycle ()
{
	var struct = arguments; 
	return function( o, i, a  )
	{
		if( i == 0 && a.length % struct.length != 0 )
			return false;
		
		var i2 = i % struct.length;
		var v = struct[i2];
		
		if( v instanceof Function )
			return v( o, i, a );
		else
			return o == v;
	};
}
// for matchRest( a, b, c ) all arrays starting by a then b
// and then followed by any numbers of c are valid, such as :
// [a,b]
// [a,b,c]
// [a,b,c,c,c,c,c,c]
function matchRest ()
{
	var struct = arguments; 
	return function ( o, i, a) 
	{
		// the last struct argument is the rest and is optionnal
		if( i == 0 && a.length < struct.length - 1 )
			return false;
		
		// lock the struct cursor to the rest arg when reached
		var i2 = Math.min(i, struct.length - 1);
		var v = struct[i2];
		
		if( v instanceof Function )
			return v( o, i, a );
		else
			return o == v;
	};
}

These decorators are really usefull when dealing with functions arguments, for example :

// this function will have three forms : 
// the short form, for single object 
// moveObjects( target, xOffset, yOffset );
// and two long forms to move several objects
// moveObjects( target1, xOffset1, yOffset1, ..., targetN, xOffsetN, yOffsetN );
// moveObjects( xOffset, yOffset, target1, target2, target3, ..., targetN )
function moveObjects ()
{
     if( arguments.every( matchFixed( 
         hasProperties( {"x" : isA("number"), "y" : isA("number") } ), 
         isA("number"),
         isA("number") ) ) )
    {
         // short form case
    }
    else if( arguments.every( matchCycle ( 
         hasProperties( {"x" : isA("number"), "y" : isA("number") } ), 
         isA("number"),
         isA("number") ) ) )
    {
         // cycling long form
    }
    else if( arguments.every( matchRest ( 
         isA("number"),
         isA("number"),
         hasProperties( {"x" : isA("number"), "y" : isA("number") } ) ) ) )
    {
         // with rest long form
    }
    else
    {
         // match none of the forms, should raise an error
    }
}

The function above is not meant to perform well when performance is a requirement, since each check results in many loops and functions calls, but you can really ensure both flexibility in the function usage and robustness with a small amount of effort.

Conclusion

There's probably more to explore in this way, at the time I write this post I've already implemented close to 30 functions in as3 (they can be found here), the one above included, and I don't lack of ideas for new functions. It's clearly not suited to use in a game engine or any other intensive element of your programs, so be careful when using too heavy queries. But who knows, with a bit of inlining...

That's all folks!

UPDATE 29/03/2011 I attached an array.js file to this post which contains all the decorators described above and many more.

Truc à la con

Une petite broutille en passant

Et la Line en HD pour ceux qui seraient tenté par une colo.

Vrac (GIMP 2.7.1)

J'avais pas pris le temps de l'essayer avant, mais j'avais tort. La prochaine version de GIMP est disponible en pre-release (instable, mais vous êtes prévenus :) ) mais malgré l'instabilité (deux trois bugs vraiment chiant) les améliorations dans cette version sont capitales. Jugez plutôt :

  • Gimp voit ainsi son système de calque revu pour y intégrer les groupes de calques (ou dossier de calques)
  • Un mode fenêtre unique fait son apparition, malheureusement ça reste la partie la plus instable mais je reviendrais dessus un peu plus tard.
  • Les dynamiques de brosses sont maintenant complètement découplées de l'outil, il est donc possible de se créer des dynamiques particulières et de permuter entre elle par une simple sélection dans la liste.
  • Un autre système très puissant est introduit dans cette version, et je pense que ça va être une des killer feature de GIMP à l'avenir, c'est le tagging de ressources. Le principe, comme pour les billets de ce blog, on peut tagger un grand nombre de ressources (brosses, dynamiques, palettes, dégradés, motifs, etc...), et donc ensuite filtrer chaque type de ressources selon certain tags. Pour moi, cette solution est clairement la plus pertinente au problème de gestion des ressources d'un graphiste. Il est souvent ardu de nommer/trier/organiser ses outils, ses palettes, etc... ; mais là, avec la possibilité d'avoir une approche multi-dimensionnelle (un outil peut avoir N tags, donc ressortir dans N collections différentes), les possibilités sont infinies.

Certaines de ces fonctions existent, bien sûr, depuis très longtemps dans d'autres logiciels. Reste que GIMP est un peu le seul logiciel libre (avec Krita) qui soit suffisamment avancé dans ce domaine pour constituer un début de concurrences au monopole d'Adobe dans le domaine (Painter ciblant une population très spécifique des utilisateurs de Photoshop et donc ne constitue pas une vraie concurrence à ce dernier sur ses plus gros marchés : traitement photo et infographie), et les évolutions actuelles de GIMP me donnent bon espoir de voir dans le monde de l'image numérique le même phénomène que subit Internet Explorer ces dernières années sur le marché des navigateurs.

Concernant le mode fenêtre unique, qui est pour le moment assez buggé, du moins suffisamment pour vous faire vous arracher les cheveux dans certains cas, il y a quelques points à savoir histoire de tester le logiciel un peu plus sereinement.

  1. Il ne faut jamais, JAMAIS, quitter cette version de GIMP en mode fenêtre unique, sinon, au prochain démarrage, toute votre configuration de fenêtre aura disparut. Il faut donc revenir en mode multi-fenêtres avant de fermer GIMP.
  2. Un bug très gênant est présent entre le panneau Calques et le mode fenêtre unique. En gros, si vous n'ouvrez pas un fichier avant de passer dans ce mode de fenêtre, vous ne verrez aucun calques dans le panneau correspondant. De même, ouvrir un nouveau fichier après le passage en fenêtre unique provoque une instabilité critique (crash & co).
  3. Par rapport à la version précédente, où la fermeture de la fenêtre de la boite à outils fermer le logiciel, dans cette version ceci ferme la fenêtre, donc attention à bien fermer la fenêtre principale (ou utiliser ctrl+Q pour plus de sécurité) sinon il vous faudra reconfigurer tout les panneaux dans la barre d'outil.

Et pour pas "poster à vide" quelques trucs fait avec cette dernière version. Je tiens à préciser que les versions en lien sont les versions à 100% (c'est à dire qu'elles n'ont été réduites à aucun moment). L'encrage à été fait à cette échelle en utilisant une simple brosse de base de 2px, le sketch étant lui même fait direct dans GIMP. J'ai, pour ma part, jamais vu un logiciel de dessin avec une finesse et une netteté de brosse comparable (peut être ArtRage, et donc Painter, mais ça ne m'avais pas fait cet effet), et ça me conforte dans l'idée que le libre, malgré le retard qu'il peut avoir, souvent lié à l'inertie du travail "communautaire", peut - plus que le monde propriétaire, contraint par la nécessité de rentabilité - arriver au summum de la qualité et de la performance.

sketch-romain-gray

Oboro Muramasa (fanart)

Parce que ce jeu me rappelle pourquoi j'ai fait du Jeu Vidéo mon métier...

Une version légèrement désaturée

Et la line, sur format A3, à la plume et au pentel

Une courte pause de publicité

Un court billet pour faire la promo du premier jeu de deux anciens collègues, Skat et Zero, sur iPhone.

donuts-book2

Version Internationale

Version FR & BE

Et parce qu'il y avait la place, deux petits dessins :

arizona-dream-nb-1200

jumpgirl-nb-1000

Paper Stuff 6 : Ink & pencil

Un peu de motivation pour travailler mes encrages, donc on reprend des vieux dessins :)

girls-posesheet-part1-clean-700

girls-posesheet-part2-clean-700

Paper Stuff 5 & Colors DS

misc-01

sm-01

sm-02

Et en bonus quelques conneries faites sur Colors DS

colors_slot0

colors_slot1

Continue reading...

- page 1 of 18

back to top