viernes, 22 de abril de 2011

OpenGL-ES2.0 y Monotouch III (AlphaTest y Scissor)

En este tercer tutotrial muestro como realizar AlphaTest y Scissor.

AlphaTest

En la mayoría de motores 3D como sabéis existen dos técnicas a la hora de trabajar con el canal Alpha. Estas son AlphaTest o AlphaBlending.

AlphaTest es la técnica más eficiente y consiste en marcar un umbral para el canal Alpha, si este lo supero el pixel se mostrará y si no lo supera el pixel no se pintará y por lo tanto la imagen será transparente en ese pixel.

AlphaBlending esta técnica es mucho más sofisticada y al mismo tiempo menos eficiente, pero consigue implementar diferentes niveles de alpha de forma que un pixel con alpha 0.7 será más opaco que uno con alpha 0.2.

En este tutorial explico como realizar AlphaTest a través de Fragment shader de OpenGLES2.0.

string fragmentShaderSrc = @"precision mediump float;
varying vec2 vTexCoord;
uniform sampler2D sTexture;
void main()
{
vec4 baseColor = texture2D(sTexture, vTexCoord);

if (baseColor.a < 0.5)
{
discard;
}
else
{
gl_FragColor = vec4(baseColor.xyz,1.0);
}
}";


Lo que hacemos es coger el valor alpha de la textura (que tendrá que ser una textura que albergue canal alpha como PNG) y le hacemos un alphaTest diciendo que si supera nuestro umbral fijado en 0.5f (el canal alpha esta comprendido entre 0 y 1) se le manda al glFragColor y si no se llama a la función discard que descarta el pixel y no lo envia para pintar.

El resultado sería:




Scissor

Scissor es una técnica por la cual le podemos decir al render que no pinte toda la pantalla sino un rectángulo de ella. Un ejemplo sería, imaginaros los tipicos juegos donde tenemos nuestra escena 3d pero esta está rodeada de controles o botones que nos permiten cambiar cosas de la escena. Bien pues la escena 3d no tiene que ocupar toda la pantalla sólo el rectangulo que queda libre dentro del marco de botones.

Para esta técnica sólo necesitamos añadir dos funciones al método de dibujado que nos proporciona la clase iPhoneOSGameView llamado OnRenderFrame.

Primero llamaremos al método GL.Scissor de OpenglES para especificar el rectangulo que limitará el pintado. Y lo segundo que debemos hacer es decirle a OpenglES que active la fase de ScissorTest en el pipeline para que tenga efecto.


...
GL.Scissor(0,0,viewportWidth/2,viewportHeight);
GL.Enable(All.ScissorTest);
...


(Nota. Tener en cuenta que la coordenada (0,0) sería la esquina inferior izquierda de nuestra pantalla)

Resultado sería:

domingo, 17 de abril de 2011

OpenGL-ES2.0 y Monotouch II (textures)

Hoy publico un nuevo ejemplo de cómo cargar y renderizar texturas con Monotouch y OpenGL ES2.0. En el anterior artículo publiqué como crear un poligono en pantalla el ejemplo de hoy es un poco más complejo aunque sólo amplía el código del artículo anterior, por lo que si no lo has leido te recomiendo que lo hagas "OpenGLES2.0 y Monotouch I".

Lo siguiente a cuando ya sabemos crear polígonos es poder aplicarles texturas, para ello es muy importante tener algunos conceptos claros.

Lo primero vamos a crear un square en pantalla esto sería:


public float[] squareVertices = { -0.5f, -0.5f,
   0.5f, -0.5f,
   -0.5f, 0.5f,
   0.5f, 0.5f };


Con esto definimos los cuatro vertices que tendrá nuestro cuadrado.
A la hora de texturizarlo es importante conocer lo que son las coordenadas de texturas. Estas permiten a los polígonos posicionar la textura sobre ellos. Estas suelen llamarse (u,v) o (s,t) y es un vector de 2 float en el que sus valores estan entre [0-1] por cada vertice de nuestro poligono.

Para que la textura cubra totalmente nuestro square debemos definir un array de 4 vectores (u,v) que son las coordenadas de textura de cada vertice.



Las definimos como:

float[] texCoords = new float[] { 0.0f,1.0f,
  1.0f,1.0f,
  0.0f,0.0f,
  1.0f,0.0f
};


Ahora Vamos a definir el Vertex shader y el Fragment shader:

Vertex Shader



string vertexShaderSrc =  @"attribute vec4 aPosition;
attribute vec2 aTexCoord;
varying vec2 vTexCoord;
    void main()                  
    {                        
   vTexCoord = aTexCoord;
       gl_Position = aPosition;
    }";    


Definimos el atributo aTexCoord que es dónde cargaremos las coordenadas de textura del vertice que en ese momento estemos procesando. Pero como la única salida de un Vertex Shader es a través de variables de tipo varying definimos también vTexCoord al que se le copiaran los valores.

Y ahora el Fragment Shader


string fragmentShaderSrc = @"precision mediump float;
varying vec2 vTexCoord;
uniform sampler2D sTexture;
            void main()                                
            {                                        
              gl_FragColor = texture2D(sTexture,vTexCoord);
            }";


En el fragment shader tenemos como variable de entrada vTexCoord que fue pasada por el vertex shader y se define un variable de tipo Uniform que es la que albergará los pixeles de la textura. Finalmente para aplicar la textura llamamos a la función texture2D y el pasamos la textura y las coordenadas de textura que le corresponden y esta pintará correctamente la textura sobre el polígono.

Ahora necesitamos cargar la textura. Para ello desde código OpenGLES2 puro escribimos:


//Generate a texture object
GL.GenTextures(1,ref textureId);

//Bind the texture object
GL.ActiveTexture(All.Texture0);
GL.BindTexture(All.Texture2D, textureId);
GL.Uniform1(textureId,0);

Creamos un objeto textura con la función GenTextures

Y luego muy importante activamos el canal de textura0 que tiene OpenGL-ES, básicamente le estamos diciendo que vamos a trabajar sobre el primer canal le decimos también que es una textura 2D y no una textura cúbica con la función BindTexture y le decimos que la textura cargada será enlazada contra la primera variable de tipo uniform con Uniform1.

Para cargar la textura usaremos las clases que wrapea monotouch sobre IPhone, que es la clase UIImage.


UIImage ui = UIImage.FromFile("mario3.jpg");
CGImage image = ui.CGImage;

CGColorSpace colorspace = CGColorSpace.CreateDeviceRGB();
data = Marshal.AllocHGlobal(image.Height*image.Width*4);
CGContext context = new CGBitmapContext(data,image.Width,image.Height,8,4*image.Width, colorspace,CGImageAlphaInfo.NoneSkipLast);
colorspace.Dispose();
context.ClearRect(new RectangleF(0,0,image.Width,image.Height));
context.DrawImage(new RectangleF(0,0,image.Width,image.Height),image);


(Nota. La imagen debe ser multiplo de 2 para que la cargue opengl-es, es decir, 2-4-8-16-32-64... En otro tutorial explicaré como adaptar nuestra imagen dada la resolución que sea).

Tener en cuenta que la imagen que estoy cargando es un retrato de Mario Bros en formato PNG que como sabeis tiene formato RGBA. de hay que el espacio reservado sea 4(bytes) por image.width para cada fila de nuestra variable data y tantas columnas como image.height.

Una vez la imagen cargada para enlazarla a nuestro objeto textura escribiremos:


GL.TexImage2D(All.Texture2D, 0, (int)All.Rgba, image.Width, image.Height, 0 ,All.Rgba, All.UnsignedByte, data);


Con esto le decimos que es una imagen de tipo RGBA (con canal alpha) y que el contenido son bytes sin signos.

Una vez cargada le aplicamos los filtros y el wrap a la textura:


//Set the filtering mode
GL.TexParameter(All.Texture2D, All.TextureMinFilter, (float)All.Nearest);
GL.TexParameter(All.Texture2D, All.TextureMagFilter, (float)All.Nearest);

//Wrap setting
GL.TexParameter(All.Texture2D, All.TextureWrapS,(int)All.Repeat);
GL.TexParameter(All.Texture2D, All.TextureWrapT,(int)All.Repeat);


En otro tutorial explicaré los filtros posibles, así como los 3 modos de wrap que soporta OpenGL-ES2.0.

Y por último y no menos importante liberar el espacio reservado:

context.Dispose();
Marshal.FreeHGlobal(data);


En el método draw aplicaremos al vertex shader los vértices y las coordenadas de textura de la siguiente forma:

//Active params
GL.EnableVertexAttribArray (0);
GL.EnableVertexAttribArray (1);


//Set params
GL.VertexAttribPointer(0,2,All.Float,false,2*sizeof(float),squareVertices);
GL.VertexAttribPointer(1,2,All.Float,false,2*sizeof(float),texCoords);


Y listo, si quereis probarlo sólo necesitais tener monodevelop con Monotouch instalado en vuestro MacOSX. Crear un proyecto de tipo Monotouch OpenGL y modificar el código de la clase llamada EAGLView.cs por:




#define OPENGLES2


using System;
using OpenTK.Platform.iPhoneOS;
using MonoTouch.CoreAnimation;
using OpenTK;

#if OPENGLES2
using OpenTK.Graphics.ES20;
#else
using OpenTK.Graphics.ES11;
#endif
using MonoTouch.Foundation;
using MonoTouch.ObjCRuntime;
using MonoTouch.OpenGLES;
using System.Text;
using System.Drawing;
using OpenTK.Platform;
using MonoTouch.CoreGraphics;
using MonoTouch.UIKit;
using System.Runtime.InteropServices;

namespace Texturing
{
public partial class EAGLView : iPhoneOSGameView
{
int viewportWidth, viewportHeight;
int program;

float[] squareVertices = { -0.5f,-0.5f,
   0.5f,-0.5f,
   -0.5f,0.5f,
   0.5f,0.5f
};
// byte[] pixels = {255,0,0, //Red
// 0,255,0, //Green
//          0,0,255, //Blue
// 255,255,0 //Yellow
// };

//Texture
int textureId;
float[] texCoords = new float[] { 0.0f,1.0f,
  1.0f,1.0f,
  0.0f,0.0f,
  1.0f,0.0f
};

IntPtr data;


[Export("layerClass")]
static Class LayerClass ()
{
return iPhoneOSGameView.GetLayerClass ();
}

[Export("initWithCoder:")]
public EAGLView (NSCoder coder) : base(coder)
{
LayerRetainsBacking = false;
LayerColorFormat = EAGLColorFormat.RGBA8;
}

protected override void CreateFrameBuffer ()
{
#if OPENGLES2
ContextRenderingApi = EAGLRenderingAPI.OpenGLES2;
base.CreateFrameBuffer();
Initialize();
#else
ContextRenderingApi = EAGLRenderingAPI.OpenGLES1;
base.CreateFrameBuffer();
#endif
}

                                

#if OPENGLES2

private bool Initialize()
{
viewportHeight = Size.Height;
viewportWidth = Size.Width;

// Vertex and fragment shaders
string vertexShaderSrc =  @"attribute vec4 aPosition;
attribute vec2 aTexCoord;
varying vec2 vTexCoord;
    void main()                  
    {                        
   vTexCoord = aTexCoord;
       gl_Position = aPosition;
    }";                          

string fragmentShaderSrc = @"precision mediump float;
varying vec2 vTexCoord;
uniform sampler2D sTexture;
            void main()                                
            {                                        
              gl_FragColor = texture2D(sTexture,vTexCoord);
            }";

int vertexShader = LoadShader (All.VertexShader, vertexShaderSrc );
int fragmentShader = LoadShader (All.FragmentShader, fragmentShaderSrc );
program = GL.CreateProgram();
if (program == 0)
throw new InvalidOperationException ("Unable to create program");

GL.AttachShader (program, vertexShader);
GL.AttachShader (program, fragmentShader);

//Set position
GL.BindAttribLocation (program, 0, "aPosition");
GL.BindAttribLocation (program, 1, "aTexCoord");

GL.LinkProgram (program);

int linked = 0;
GL.GetProgram (program, All.LinkStatus, ref linked);
if (linked == 0) {
// link failed
int length = 0;
GL.GetProgram (program, All.InfoLogLength, ref length);
if (length > 0) {
var log = new StringBuilder (length);
GL.GetProgramInfoLog (program, length, ref length, log);
Console.WriteLine ("GL2", "Couldn't link program: " + log.ToString ());
return false;
}

GL.DeleteProgram (program);
throw new InvalidOperationException ("Unable to link program");
}

LoadTexture();

return true;
}

private int LoadShader ( All type, string source )
{
   int shader = GL.CreateShader(type);

   if ( shader == 0 )
   throw new InvalidOperationException("Unable to create shader");     

   // Load the shader source
   int length = 0;
GL.ShaderSource(shader, 1, new string[] {source}, (int[])null);
  
   // Compile the shader
   GL.CompileShader( shader );

   int compiled = 0;
GL.GetShader (shader, All.CompileStatus, ref compiled);
if (compiled == 0) {
length = 0;
GL.GetShader (shader, All.InfoLogLength, ref length);
if (length > 0) {
var log = new StringBuilder (length);
GL.GetShaderInfoLog (shader, length, ref length, log);
Console.WriteLine("GL2", "Couldn't compile shader: " + log.ToString ());
}

GL.DeleteShader (shader);
throw new InvalidOperationException ("Unable to compile shader of type : " + type.ToString ());
}

return shader;

}

private void LoadTexture()
{

UIImage ui = UIImage.FromFile("mario3.jpg");
CGImage image = ui.CGImage;

CGColorSpace colorspace = CGColorSpace.CreateDeviceRGB();
data = Marshal.AllocHGlobal(image.Height*image.Width*4);
CGContext context = new CGBitmapContext(data,image.Width,image.Height,8,4*image.Width, colorspace,CGImageAlphaInfo.NoneSkipLast);
colorspace.Dispose();
context.ClearRect(new RectangleF(0,0,image.Width,image.Height));
context.DrawImage(new RectangleF(0,0,image.Width,image.Height),image);


//Use tightly packed data
//GL.PixelStore(All.UnpackAlignment, 1);

//Generate a texture object
GL.GenTextures(1,ref textureId);

//Bind the texture object
GL.ActiveTexture(All.Texture0);
GL.BindTexture(All.Texture2D, textureId);
GL.Uniform1(textureId,0);

//Load the texture
GL.TexImage2D(All.Texture2D, 0, (int)All.Rgba, image.Width, image.Height, 0 ,All.Rgba, All.UnsignedByte, data);
//GL.TexImage2D(All.Texture2D,0, (int)All.Rgb,2,2,0, All.Rgb,All.UnsignedByte,pixels);

//Set the filtering mode
GL.TexParameter(All.Texture2D, All.TextureMinFilter, (float)All.Nearest);
GL.TexParameter(All.Texture2D, All.TextureMagFilter, (float)All.Nearest);

//Wrap setting
GL.TexParameter(All.Texture2D, All.TextureWrapS,(int)All.Repeat);
GL.TexParameter(All.Texture2D, All.TextureWrapT,(int)All.Repeat);

context.Dispose();
Marshal.FreeHGlobal(data);
}


#endif

protected override void ConfigureLayer (CAEAGLLayer eaglLayer)
{
eaglLayer.Opaque = true;
}


#if OPENGLES2
protected override void OnRenderFrame (FrameEventArgs e)
{
base.OnRenderFrame (e);

MakeCurrent();

GL.ClearColor (0.7f, 0.7f, 0.7f, 1);
GL.Clear ((int)All.ColorBufferBit);

GL.Viewport (0, 0, viewportWidth, viewportHeight);
GL.UseProgram (program);

//Active params
GL.EnableVertexAttribArray (0);
GL.EnableVertexAttribArray (1);

//Set params
GL.VertexAttribPointer(0,2,All.Float,false,2*sizeof(float),squareVertices);
GL.VertexAttribPointer(1,2,All.Float,false,2*sizeof(float),texCoords);

GL.DrawArrays (All.TriangleStrip, 0, 4);

//Swapped buffer (Front and Back buffer)
SwapBuffers ();
}

protected override void OnDisposed (EventArgs e)
{
base.OnDisposed (e);
Marshal.FreeHGlobal (data);
if (textureId != 0)
GL.DeleteTextures(1, ref textureId);
}

#else
protected override void OnRenderFrame (FrameEventArgs e)
{
base.OnRenderFrame(e);

float[] squareVertices = { -0.5f, -0.5f, 0.5f, -0.5f, -0.5f, 0.5f, 0.5f, 0.5f };
byte[] squareColors = { 255, 255, 0, 255, 0, 255, 255, 255, 0, 0,
0, 0, 255, 0, 255, 255 };

MakeCurrent ();
GL.Viewport (0, 0, Size.Width, Size.Height);

GL.MatrixMode (All.Projection);
GL.LoadIdentity ();
GL.Ortho (-1.0f, 1.0f, -1.5f, 1.5f, -1.0f, 1.0f);
GL.MatrixMode (All.Modelview);
GL.Rotate (3.0f, 0.0f, 0.0f, 1.0f);

GL.ClearColor (0.5f, 0.5f, 0.5f, 1.0f);
GL.Clear ((uint)All.ColorBufferBit);

GL.VertexPointer (2, All.Float, 0, squareVertices);
GL.EnableClientState (All.VertexArray);
GL.ColorPointer (4, All.UnsignedByte, 0, squareColors);
GL.EnableClientState (All.ColorArray);

GL.DrawArrays (All.TriangleStrip, 0, 4);

SwapBuffers ();
}
#endif
}
}


martes, 12 de abril de 2011

OpenGLES2.0 y Monotouch I (Poligon)

Actualmente me encuentro trabajando con OpenGLES2.0 en el proyecto MonoGame y una de las cosas que más trabajo me ha costado encontrar
es un ejemplo de monotouch usando openGL-ES2.0. Por ello he decido escribir uno para muchos como yo que estuvierán perdidos.

Bien pues si teneís instalado Monotouch en vuestro MacOSX (actualmente monotouch sólo funciona sobre MacOSX) y usáis Monodevelop podréis ver una plantilla de Monotouch y OpenGL.

Creamos un proyecto de este tipo y veremos que tenemos dos ficheros (Main.cs y EAGLView.cs) además del componente ventana (fichero xib).

Main.cs: Es la clase que contiene el método main y que llama a UIApplication.Main que es el método principal al trabajar en IOS.

EAGLView.cs: Es la clase de ejemplo que nos crea Monotouch usando OpenGL-ES1.1 con fixed pipeline. Que basicamente significa que no podemos modificar el pipeline de dibujado y por lo tanto no podemos usar shader. Los shader nos permiten tener un control más pontente del pipeline de dibujado y por lo tanto mayor flexibilidad. Otra de las mejoras al usar OpenGL-ES2.0 es que en vez de limitarnos a texturas de 1024x1024 en la versión ES1.1 en la segunda versión ya puedes usar texturas de 2048x2048.

Bueno en resumen por estos motivos y muchos más es muy interesante migrarnos a OpenGL-ES2.0 pero con la salvedad de que en la actualidad aún todos los terminales no soportan ES2.0, así que si el dispositivo no detecta esto deberemos volver a la versión 1.1

Para usar OpenGLES2.0 sobre este ejemplo sólo vamos a tocar la clase EAGLView.cs por lo que es la única que os muestro:



EAGLView.cs


#define OPENGLES2


using System;
using OpenTK.Platform.iPhoneOS;
using MonoTouch.CoreAnimation;
using OpenTK;

#if OPENGLES2
using OpenTK.Graphics.ES20;
#else
using OpenTK.Graphics.ES11;
#endif
using MonoTouch.Foundation;
using MonoTouch.ObjCRuntime;
using MonoTouch.OpenGLES;
using System.Text;
using System.Drawing;
using OpenTK.Platform;

namespace OpenGLES
{
public partial class EAGLView : iPhoneOSGameView
{
int viewportWidth, viewportHeight;
int program;
float [] vertices = new float [] {0.0f, 0.5f, 0.0f,
  -0.5f, -0.5f, 0.0f,
  0.5f, -0.5f, 0.0f
     };

[Export("layerClass")]
static Class LayerClass ()
{
return iPhoneOSGameView.GetLayerClass ();
}

[Export("initWithCoder:")]
public EAGLView (NSCoder coder) : base(coder)
{
LayerRetainsBacking = false;
LayerColorFormat = EAGLColorFormat.RGBA8;
}

protected override void CreateFrameBuffer ()
{
#if OPENGLES2
ContextRenderingApi = EAGLRenderingAPI.OpenGLES2;
base.CreateFrameBuffer();
Initialize();
#else
ContextRenderingApi = EAGLRenderingAPI.OpenGLES1;
base.CreateFrameBuffer();
#endif
}

                                

#if OPENGLES2
// protected override void OnLoad(EventArgs e)
// {
// Initialize();
// }

private bool Initialize()
{
viewportHeight = Size.Height;
viewportWidth = Size.Width;

// Vertex and fragment shaders
string vertexShaderSrc =  @"attribute vec4 aPosition;  
    void main()                  
    {                        
       gl_Position = aPosition;
    }";                          

string fragmentShaderSrc = @"precision mediump float;
varying vec4 vcolor;
            void main()                                
            {                                        
              gl_FragColor = vec4(1.0,0.0,0.0,1.0);
            }";

int vertexShader = LoadShader (All.VertexShader, vertexShaderSrc );
int fragmentShader = LoadShader (All.FragmentShader, fragmentShaderSrc );
program = GL.CreateProgram();
if (program == 0)
throw new InvalidOperationException ("Unable to create program");

GL.AttachShader (program, vertexShader);
GL.AttachShader (program, fragmentShader);

//Set position
GL.BindAttribLocation (program, 0, "aPosition");

GL.LinkProgram (program);

int linked = 0;
GL.GetProgram (program, All.LinkStatus, ref linked);
if (linked == 0) {
// link failed
int length = 0;
GL.GetProgram (program, All.InfoLogLength, ref length);
if (length > 0) {
var log = new StringBuilder (length);
GL.GetProgramInfoLog (program, length, ref length, log);
Console.WriteLine ("GL2", "Couldn't link program: " + log.ToString ());
return false;
}

GL.DeleteProgram (program);
throw new InvalidOperationException ("Unable to link program");
}

return true;
}

private int LoadShader ( All type, string source )
{
   int shader = GL.CreateShader(type);

   if ( shader == 0 )
   throw new InvalidOperationException("Unable to create shader");     

   // Load the shader source
   int length = 0;
GL.ShaderSource(shader, 1, new string[] {source}, (int[])null);
  
   // Compile the shader
   GL.CompileShader( shader );

   int compiled = 0;
GL.GetShader (shader, All.CompileStatus, ref compiled);
if (compiled == 0) {
length = 0;
GL.GetShader (shader, All.InfoLogLength, ref length);
if (length > 0) {
var log = new StringBuilder (length);
GL.GetShaderInfoLog (shader, length, ref length, log);
Console.WriteLine("GL2", "Couldn't compile shader: " + log.ToString ());
}

GL.DeleteShader (shader);
throw new InvalidOperationException ("Unable to compile shader of type : " + type.ToString ());
}

return shader;

}
#endif

protected override void ConfigureLayer (CAEAGLLayer eaglLayer)
{
eaglLayer.Opaque = true;
}


#if OPENGLES2
protected override void OnRenderFrame (FrameEventArgs e)
{
base.OnRenderFrame (e);

MakeCurrent();

GL.ClearColor (0.7f, 0.7f, 0.7f, 1);
GL.Clear ((int)All.ColorBufferBit);

GL.Viewport (0, 0, viewportWidth, viewportHeight);
GL.UseProgram (program);

GL.EnableVertexAttribArray (0);

GL.VertexAttribPointer (0, 3, All.Float, false, 0, vertices);

GL.DrawArrays (All.Triangles, 0, 3);

SwapBuffers ();
}

#else
protected override void OnRenderFrame (FrameEventArgs e)
{
base.OnRenderFrame(e);

float[] squareVertices = { -0.5f, -0.5f, 0.5f, -0.5f, -0.5f, 0.5f, 0.5f, 0.5f };
byte[] squareColors = { 255, 255, 0, 255, 0, 255, 255, 255, 0, 0,
0, 0, 255, 0, 255, 255 };

MakeCurrent ();
GL.Viewport (0, 0, Size.Width, Size.Height);

GL.MatrixMode (All.Projection);
GL.LoadIdentity ();
GL.Ortho (-1.0f, 1.0f, -1.5f, 1.5f, -1.0f, 1.0f);
GL.MatrixMode (All.Modelview);
GL.Rotate (3.0f, 0.0f, 0.0f, 1.0f);

GL.ClearColor (0.5f, 0.5f, 0.5f, 1.0f);
GL.Clear ((uint)All.ColorBufferBit);

GL.VertexPointer (2, All.Float, 0, squareVertices);
GL.EnableClientState (All.VertexArray);
GL.ColorPointer (4, All.UnsignedByte, 0, squareColors);
GL.EnableClientState (All.ColorArray);

GL.DrawArrays (All.TriangleStrip, 0, 4);

SwapBuffers ();
}
#endif
}
}




Nota. Para terminar si comentas la primera linea es decir "#define OPENGLES2" se renderizará usando ES1.1 y si no
usará ES2.0 con shaders.

Abrir dos instancias de la misma aplicación en MacOSX

Actualmente estoy trabajando con Monodevelop en MacOSX y uno de los primeros incovenientes que te encuentras es el no poder abrir varias instancias de Monodevelop con lo necesario que esto es para un programador. En principio MacOSX no te deja hacerlo desde su interfaz gráfico pero esto no quiere decir que no se pueda. Así que hoy os cuento otro tip sobre MacOSX que a mi me facilitó mucho la tarea al trabajar con Monodevelop.


Abrimos un terminal y ponemos

/Applications/MonoDevelop.app/Contents/MacOS/monodevelop &

Dentro del directorio Applications se encuentran todas las aplicaciones que tenemos instaladas por lo que supongo que esto seguro que os sirve para otros programas.

Mostrar ficheros ocultos en MacOSX

Hoy escribo un pequeño truco que me reportó Javier fernandez de Syderis para poder ver en una ventana del finder en MacOSX los ficheros y directorios ocultos. Esto es un poco más rebuscado que en sistemas como Windows y no tenemos una propiedad fácilmente modificable. Necesitamos modificar la variable AppleShowAllFiles que es un bool y ponerla a true ya que por defecto viene a false, para ello:

Abrimos un terminal y ponemos:

Mostrar ficheros ocultos:
defaults write com.apple.finder AppleShowAllFiles TRUE

killall Finder


Ocultar ficheros ocultos:
defaults write com.apple.finder AppleShowAllFiles FALSE

killall Finder

martes, 22 de marzo de 2011

Crear un fichero de cualquier tamaño

Hoy estamos configurando el NAS y necesitamos ficheros de tamaños determinados para probar cuotas de espacio en disco. Para esto es muy util poder crear un fichero de un fichero determinado. Para esto en sistemas deribados de UNIX como MacOSX o la famila Linux tenemos el comando dd que nos ayudará a esta tarea. Dejo este pequeño tip que espero le sea de utilidad a muchos de vosotros.

Nos posicionamos en la carpeta donde queramos dejar el fichero
cd /tmp

Creamos un fichero de 50MGs
dd if=/dev/zero of=archivo50megas.txt bs=1024 count=51200

if - archivo de entrada (cogemos basura del dispositivo zero)
of - archivo de salida (el nombre de nuestro fichero)
bs - tamaño de bloque bytes (1024 indica bloques de 1k)
count - Número de bloques (51200 = 50*1024(Mg))

viernes, 19 de noviembre de 2010

Lanzar aplicaciones con retraso al iniciar windows 7

Como todos sabéis Windows tiene varios mecanismos para lanzar aplicaciones en el arranque del sistema operativo. La fórmula más conocida es colocar un acceso directo en la carpeta "Inicio". Pero hoy me encuentro con el problema de lanzar una aplicación que hace uso de la tarjeta gráfica y el problema consiste es que al poner la aplicación en la carpeta de Inicio esta se lanza antes de que se cargue el servicio de DirectX por lo que la aplicación da un fallo de no estar aún enable dichas funcionalidades. La manera de resolver el problema ha sido construir un pequeño script en bacth (lenguaje de script de MS-DOS) para que espero lo necesario hasta que los servicios gráficos hayan sido cargados.

Os dejo el script:

---------------------
@echo off
timeout 30
start chrome
------------------
"@echo off" -> no imprima la salida de los comandos por la consola
"timeout 30" -> espere 30 segundos (tiempo suficiente para el arranque de todos los servicios de windows 7
"start chrome" -> arrancar la aplicación

Lo guardais como loquequerais.bat y lo colocais en la carpeta de "Inicio"


Sintasis del comando start
Syntax
      START "title" [/Dpath] [options] "command" [parameters]

Key:
   title      : Text for the CMD window title bar (required)
   path       : Starting directory
   command    : The command, batch file or executable program to run
   parameters : The parameters passed to the command

Options:
   /MIN       : Minimized
   /MAX       : Maximized
   /WAIT      : Start application and wait for it to terminate
   /LOW       : Use IDLE priority class
   /NORMAL    : Use NORMAL priority class
   /HIGH      : Use HIGH priority class
   /REALTIME  : Use REALTIME priority class

   /B         : Start application without creating a new window. In this case
                ^C will be ignored - leaving ^Break as the only way to
                interrupt the application
   /I         : Ignore any changes to the current environment.

   Options for 16-bit WINDOWS programs only

   /SEPARATE   Start in separate memory space (more robust)
   /SHARED     Start in shared memory space (default)