Blog

Juan Mellado, 23 Noviembre, 2011 - 17:18

DartDart es el nombre de un nuevo lenguaje de programación creado por Google que se plantea como una alternativa de futuro a JavaScript. Siempre he pensado que el atributo "type" de la etiqueta "script" estaba para algo más que tomar un valor por defecto, y parece que al fin alguien se lo ha tomado en serio.

¿Pero realmente necesitamos un nuevo lenguaje de programación? Pues como siempre la respuesta depende de como le duela a cada uno. Para validar formularios, realizar efectos o hacer alguna que otra librería independiente tenemos más que suficiente con JavaScript. Pero para desarrollos que impliquen una mayor complejidad, y sobre bastante miles de líneas de código, entonces estamos necesitando claramente otro lenguaje. En particular con las características deseables de un lenguaje orientado a objetos, en vez de estar siempre tratando de emular estas características en JavaScript. Y todo esto naturalmente partiendo de la base de que a futuro sigamos queriendo ejecutar (mucho) código en el cliente.

Cuestiones filosóficas aparte, siendo muy simplista, la idea es que Dart recupera para la web las palabras reservadas interface y class, con sus constructores, métodos y variables de instancia. Pero eso es sólo una pequeña parte, claro. También proporciona un punto de entrada a las aplicaciones a través de una clásica función main, la posibilidad de importar librerías con #import, incluir código con source, y colecciones que pueden tiparse como los templates de C++ o los generics de Java. Suena todo bastante familiar, ¿no?

main() {
  print('Hello, Dart!');
}

Dart es un lenguaje orientado a objetos basado en clases que soporta herencia simple, no múltiple, y que encapsula el código de forma modular en unidades a las que llama librerías. Proporciona mecanismos para declarar elementos públicos y privados, aunque curiosamente distinguidos por la nomenclatura de su nombre, no por un atributo modificador. Si empieza por "_" entonces es privado. Además soporta la concurrencia mediante un mecanismo propio de ejecución aislada (isolation) con intercambio de mensajes, sin memoria compartida. Y permite realizar una programación mixta en cuanto a comprobación de tipos se refiere. Pudiendo realizarse una versión inicial débilmente tipada e ir haciéndola más fuerte a medida que avanza el desarrollo. Pueden consultarse todos los detalles en el borrador actual que contiene las especificaciones del lenguaje.

Para probar Dart a día de hoy hay dos formas:

1) Utilizar el Dartboard, una pequeña aplicación web con un cuadro de texto donde se puede introducir código, compilarlo y ejecutarlo. Evidentemente el código se compila y ejecuta en un servidor remoto.

2) Utilizar el Dart Editor, una aplicación de escritorio basada en Eclipse que incorpora todas las características propias de este conocido entorno de desarrollo. En este caso el código se compila a JavaScript y se puede ejecutar desde una página HTML ordinaria directamente desde el navegador. Esta opción es similar a GWT, que acepta código en Java y genera JavaScript.

Por su parte, a futuro Dart se podrá ejecutar de dos formas:

1) Mediante un nuevo tipo MIME "application/dart" que se ejecutará de forma nativa en el navegador, de forma similar a como actualmente se ejecuta el código "application/javascript".

2) Mediante una máquina virtual en un PC local. Algo que en realidad ya puede hacerse hoy en día gracias a las herramientas de líneas de comandos ya disponibles.

Naturalmente hoy en día un lenguaje no es nada si no viene acompañado de unas buenas librerías, máxime si su ejecución ha de realizarse en un navegador donde se dispone de APIs ya establecidos. Dart en ese aspecto apenas tiene dos librerías básicas, una core y otra dom. La librería de acceso a DOM está lo suficientemente desarrollada para manipular una página web de forma dinámica, permitiendo ya actualmente acceso a los objetos de tipo canvas por ejemplo.

#library('example');
#import('dart:dom');

main() {
  new Example();
}

class Example {
  CanvasRenderingContext2D ctx;

  Example() {
    var doc = window.document;
    HTMLCanvasElement canvas = doc.getElementById("canvas");
    ctx = canvas.getContext("2d");

    render();
  }
 
  void render() {
    ctx.clearRect(0, 0, 800, 600);
...
  }
}

He estado probando el Dart Editor y compilando los ejemplos. Iba a subir uno de ellos a la web, pero finalmente he desistido porque la versión actual genera como resultado de la compilación ficheros JavaScript de varios megas, y no merece la pena.

¿Sobrevivirá este lenguaje y se popularizará? Pues no tengo ni idea. A priori resulta difícil aceptar que el resto de navegadores vaya a adoptar una especificación muy concreta de Google, y mucho menos hacer un desarrollo propio para soportarlo, pero peores cosas se han visto. La gran ventaja con la que cuenta Google en este sentido es que Dart es un proyecto de código abierto. En cualquier caso no es el primer intento por parte de Google de crear un nuevo lenguaje de programación, ahí está Go por ejemplo, cuya primera versión definitiva está prevista que aparezca el año que viene. El tiempo dirá.

Temas: Flash Stratos
Juan Mellado, 22 Noviembre, 2011 - 22:51

WebGL Cheat SheetEl lanzamiento de la versión definitiva de Flash 11 hace unas pocas semanas trajo consigo el tan esperado Stage3D, anteriormente conocido como Molehill. O lo que es lo mismo, la posibilidad de aprovechar las capacidades de las GPUs desde Flash. En principio es una alternativa más a otras opciones disponibles actualmente como WebGL, aunque el anuncio por parte de Adobe de renunciar a seguir desarrollando Flash para móviles en favor de su plataforma AIR nos ha dejado despistados a un montón de gente. Pero decisiones empresariales aparte, el API está ahí fuera y es hora de echarle un vistazo.

Siguiendo mi costumbre, he elaborado una pequeña cheat sheet para que me sirva de referencia, igual que la que hice para WebGL.

Lo primero que llama la atención es que es una API de muy bajo nivel. Los que hayan utilizado alguna vez OpenGL, WebGL o DirectX se sentirán cómodos. Pero sinceramente, me esperaba una jerarquía de clases que ofreciera una funcionalidad de más alto nivel para la gestión de escenas, cámaras, colisiones o carga de modelos. Pero no, las clases que hay son para el acceso a bastante bajo nivel. De hecho, ni siquiera han incluido en el runtime el compilador de shaders.

Pero vayamos por partes, las clases básicas de entrada al API son Stage3D y Context3D. La primera clase representa la superficie sobre la que se dibuja, de forma similar al Stage de toda la vida, y que permite además instanciar la segunda clase a través de un evento (para las situaciones de pérdida de contexto). El contexto 3D es el que permite instanciar al resto de clases como los buffers de índices, vértices, texturas o shaders.

public class Example extends Sprite{
  private var stage3D:Stage3D;
  private var context3D:Context3D;

  public function Example(){
    stage3D = this.stage.stage3Ds[0];
    stage3D.addEventListener(Event.CONTEXT3D_CREATE, onContext3DCreate);
    stage3D.requestContext3D(Context3DRenderMode.AUTO);
  }

  private function onContext3DCreated(event:Event):void{
    context3D = Stage3D(event.target).context3D;
  }
...

Context3D es la clase base, muy similar a otras APIs, y permite, entre cosas, establecer el estado del render con las clásicas opciones de configuración del z-buffer, blending o stencil, y el envío al driver de la orden de dibujado de triángulos.

Otras clases básicas son VertexBuffer3D, IndexBuffer3D, Texture, CubeTexture y Program3D. Pero tienen muy poca funcionalidad, apenas dos o tres métodos para inicializar su contenido desde fuentes de distintos tipos como arrays o matrices. El resto de clases son básicamente enumerados con las constantes típicas como Context3DTextureFormat, Context3DVertexBufferFormat, Context3DBlendFactor o Context3DStencilAction. En total son unas nueve clases de este último tipo, pero no ofrecen mayor funcionalidad aparte de exponer las constantes.

var triangles:Vector.<uint> = Vector.<uint>( [ ... ] );
...
indexList = context3D.createIndexBuffer(triangles.length);
indexList.uploadFromVector(triangles, 0, triangles.length);
...           
context3D.setCulling(Context3DTriangleFace.BACK);
...

Por lo que respecta a los shaders, Adobe ha definido un lenguaje propio (otro más) de muy bajo nivel llamado AGAL (Adobe Graphics Assembly Language). Es realmente ensamblador, por lo que las operaciones son de muy bajo nivel. Las instrucciones son opcodes que manipulan directamente los distintos tipos de registros habituales (attribute, constant, temporary, output, varying, sampler).

private const VERTEX_SHADER:String =
  "mov v0, va1"; //Color (v0: varying 0 <= va1: attribute 1)
  "m44 op, va0, vc0 \n" + //Perspectiva (op: output position, vc0: constant 0)
       
private const FRAGMENT_SHADER:String =
  "mov oc, v0"; //oc: output color

El array de bytecodes correspondiente a un shader puede generarse en tiempo de diseño mediante Pixel Bender 3D, que es una ampliación de la versión 2D de Pixel Bender, una tecnología de Adobe para el procesamiento óptimo de imágenes y vídeos independiente de la plataforma hardware utilizada basada en el uso de ficheros XML. Aunque afortunadamente los shaders también pueden compilarse de una forma más conveniente en tiempo de ejecución mediante una clase de utilidad externa llamada AGALMiniAssembler.

private var vertexAssembly:AGALMiniAssembler = new AGALMiniAssembler();
private var fragmentAssembly:AGALMiniAssembler = new AGALMiniAssembler();
private var programPair:Program3D;
...
vertexAssembly.assemble(Context3DProgramType.VERTEX, VERTEX_SHADER, false);
fragmentAssembly.assemble(Context3DProgramType.FRAGMENT, FRAGMENT_SHADER, false);
...
programPair = renderContext.createProgram();
programPair.upload(vertexAssembly.agalcode, fragmentAssembly.agalcode);

Por lo que respecta al bucle principal habitual de Flash, no parece requerir modificación, pudiéndose seguir utilizando el evento ENTER_FRAME por ejemplo.

  ...
  this.stage.addEventListener(Event.ENTER_FRAME, render);
}

private function render(event:Event):void{
  ...
  context3D.drawTriangles(indexList, 0, 12);
  context3D.present();
}

En definitiva, una API más, una opción más a tener en cuenta a la hora de representar 3D en el navegador. Quizás de muy bajo nivel para el concepto que suele tenerse en la cabeza de Flash, percepción que la aparición de ActionScript 3 empezó a modificar y que Stage3D no hace más que confirmar.

Para terminar, revisando la web de Flash, he encontrado un enlace a un proyecto de la propia Adobe llamado Proscenium. Una librería gráfica de alto nivel, a modo de engine 3D, que están desarrollando sobre Stage3D. El inconveniente es que está aún en fase de desarrollo y no tiene soporte, aunque ya permite crear primitivas básicas, cargar modelos de objetos, e incluso gestionar colisiones. No sé como acabará, pero supongo que pretenderá ser una alternativa a motores desarrollados de forma independiente, como por ejemplo el popular Away3D y otros, que la propia Adobe parece estar apoyando.

Juan Mellado, 21 Noviembre, 2011 - 16:50

Opera lanzó hace unas semanas un build especial de su navegador que habilitaba el uso de la función getUserMedia de JavaScript. Esta función permite acceder a la webcam directamente desde JavaScript de forma nativa. He creado una nueva demo de js-aruco, mi detector de marcadores de realidad aumentada, usando esta versión para conseguir que todo el proceso sea 100% JavaScript evitando Flash para la captura de la webcam.


Demo online:
www.inmensia.com/files/aruco/getusermedia/getusermedia.html

Para que la demo funcione hay que realizar dos pasos:

1) Instalar la versión especial del navegador de Opera que se encuentra en el siguiente enlace:
http://labs.opera.com/news/2011/10/19/

2) Permitir el acceso del navegador a la webcam a través de las opciones de configuración a través del siguiente enlace:
opera:config#SecurityPrefs|AllowCameraToCanvasCopy

Por motivos de seguridad, el navegador debería pedir permiso a los usuarios antes de acceder a la webcam, pero este funcionamiento no está todavía implementado. Lo que si está desarrollado es que no se pueda acceder por código. Si se intenta acceder con la función getImageData al contenido del canvas se produce una excepción de seguridad.

Actualizado 28/02/2012: Ahora también se puede ejecutar con Chrome 18 o posterior usando el flag --enable-media-stream en línea de comandos.

Juan Mellado, 17 Septiembre, 2011 - 09:52

Una versión modificada de la demo original escrita por Brandon Jones.

He arreglado un pequeño error en el código original para que las texturas se vean correctamente, ya que con las versiones actuales de Chrome y Firefox apenas se distinguen. Y sobre todo he cambiado los parámetros del shader, para añadir mucho especular y que destaque el normal mapping. Todo el código es JavaScript, el modelo se lee de su formato original en MD5, y se renderiza con WebGL directamente en el navegador.

El modelo 3D es propiedad de id Software.

Temas: Personal
Juan Mellado, 10 Septiembre, 2011 - 10:06

VelitaUna muesca más en el modem para este blog, y ya son seis. Ni muchas ni pocas, simplemente las que son.

Un año este último de bastantes proyectos terminados. Abrir una cuenta en un repositorio público es una de las mejores cosas que he podido hacer. Me ha servido para evitar que el código que suelo escribir en mi tiempo libre acabe perdiéndose en el fondo de algún disco duro. Y sobre todo me ha motivado a limpiarlo y terminarlo, en vez de dejarlo como estaba y pasar a otra cosa en cuanto conseguía mi objetivo.

Proyectos terminados:

- js-lzma: Una versión en JavaScript del algoritmo de descompresión de LZMA.

- js-openctm: Una librería en JavaScript para leer ficheros en formato .CTM

- js-aruco: Un sistema de detección de marcadores para aplicaciones de realidad aumentada escrito totalmente en JavaScript.

- flashcam: Un librería en ActionScript3 para capturar imágenes de una webcam y enviarlas a JavaScript.

- js-javadump: Un parser de ficheros .class de Java escrito en JavaScript. De este proyecto no he escrito nunca en el blog. Es ese tipo de cosas al que me refería antes, que acababan perdiéndose por ahí, y que ahora subo al repositorio.

¿Mucho JavaScript? Pues sí, y parece que la tendencia seguirá siendo la misma. Pero quien sabe, tal vez el próximo año escribamos todos en Dart, ese nuevo lenguaje que ha anunciado Google y del que todavía no se conoce ningún detalle. Son todo especulaciones, pero no estaría mal que anunciasen un lenguaje que cumpliese con el ECMA-262 para ejecutarse directamente en el navegador, pero que suponga una pequeña revolución, como el cambio de AS2 a AS3, con la orientación a objetos, y atraiga a la masa de programadores.