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)

miércoles, 27 de octubre de 2010

Mi primera DLL

Hoy he decidido grabarme un video construyendo una dll básica en c++ y consumiendola desde una aplicación de consola en c++ porque es una tarea util cuando necesitas hacer un wrapper de una librería en c o c++ y usarla desde otros lenguajes como c#. Aunque es algo muy fácil me cuesta muchas veces recordar la nomenglatura de ahí la idea de este tutorial espero que os sea útil para arrancar vuestros proyectos.




El codigo fuente de la dll sería:


#include "stdafx.h"

#define DLL_EXPORT extern "C" __declspec(dllexport)

DLL_EXPORT double Sum(double a, double b);

double Sum(double a, double b)
{
return a+b;
}



y el de la clase en c++ que lo consume sería:


#include "stdafx.h"

#include <iostream>

extern "C" __declspec(dllimport)double Sum(double a, double b);

using namespace std;

int main(){
cout << "hola dll" << endl;
cout << "La suma de 2 + 3 es:" << Sum(2,3);

getchar();
return 0;
}


Y ahora en este segundo video creo un proyecto de consola de c# desde
el cual también consumiremos los métodos de nuestra DLL.



El código de la clase Wrapper:


namespace UseDLLCSharp
{
    class WrapperDLL
    {
        [DllImport("DLL.dll")]
        public static extern double Sum(double a, double b);
    }
}



El código de la clase principal de C#:


namespace UseDLLCSharp
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("hola mundo");
            Console.WriteLine("La suma de 3 + 2 es: " + WrapperDLL.Sum(3, 2));

            Thread.Sleep(5000);
        }
    }
}

martes, 19 de octubre de 2010

La evolución de un programador

Hoy encontré un artículo super divertido sobre la evolución que sufre una programador al ir ascendiendo de cargo o rango con los años, no es perdáis el final.


High School/Jr.High

  10 PRINT "HELLO WORLD"
  20 END

First year in College

  program Hello(input, output)
    begin
      writeln('Hello World')
    end.

Senior year in College

  (defun hello
    (print
      (cons 'Hello (list 'World))))

New professional

  #include <stdio.h>
  void main(void)
  {
    char *message[] = {"Hello ", "World"};
    int i;

    for(i = 0; i < 2; ++i)
      printf("%s", message[i]);
    printf("\n");
  }

Seasoned professional

  #include <iostream.h>
  #include <string.h>

  class string
  {
  private:
    int size;
    char *ptr;

  string() : size(0), ptr(new char[1]) { ptr[0] = 0; }

    string(const string &s) : size(s.size)
    {
      ptr = new char[size + 1];
      strcpy(ptr, s.ptr);
    }

    ~string()
    {
      delete [] ptr;
    }

    friend ostream &operator <<(ostream &, const string &);
    string &operator=(const char *);
  };

  ostream &operator<<(ostream &stream, const string &s)
  {
    return(stream << s.ptr);
  }

  string &string::operator=(const char *chrs)
  {
    if (this != &chrs)
    {
      delete [] ptr;
     size = strlen(chrs);
      ptr = new char[size + 1];
      strcpy(ptr, chrs);
    }
    return(*this);
  }

  int main()
  {
    string str;

    str = "Hello World";
    cout << str << endl;

    return(0);
  }

Master Programmer

  [
  uuid(2573F8F4-CFEE-101A-9A9F-00AA00342820)
  ]
  library LHello
  {
      // bring in the master library
      importlib("actimp.tlb");
      importlib("actexp.tlb");

      // bring in my interfaces
      #include "pshlo.idl"

      [
      uuid(2573F8F5-CFEE-101A-9A9F-00AA00342820)
      ]
      cotype THello
   {
   interface IHello;
   interface IPersistFile;
   };
  };

  [
  exe,
  uuid(2573F890-CFEE-101A-9A9F-00AA00342820)
  ]
  module CHelloLib
  {

      // some code related header files
      importheader(<windows.h>);
      importheader(<ole2.h>);
      importheader(<except.hxx>);
      importheader("pshlo.h");
      importheader("shlo.hxx");
      importheader("mycls.hxx");

      // needed typelibs
      importlib("actimp.tlb");
      importlib("actexp.tlb");
      importlib("thlo.tlb");

      [
      uuid(2573F891-CFEE-101A-9A9F-00AA00342820),
      aggregatable
      ]
      coclass CHello
   {
   cotype THello;
   };
  };


  #include "ipfix.hxx"

  extern HANDLE hEvent;

  class CHello : public CHelloBase
  {
  public:
      IPFIX(CLSID_CHello);

      CHello(IUnknown *pUnk);
      ~CHello();

      HRESULT  __stdcall PrintSz(LPWSTR pwszString);

  private:
      static int cObjRef;
  };


  #include <windows.h>
  #include <ole2.h>
  #include <stdio.h>
  #include <stdlib.h>
  #include "thlo.h"
  #include "pshlo.h"
  #include "shlo.hxx"
  #include "mycls.hxx"

  int CHello::cObjRef = 0;

  CHello::CHello(IUnknown *pUnk) : CHelloBase(pUnk)
  {
      cObjRef++;
      return;
  }

  HRESULT  __stdcall  CHello::PrintSz(LPWSTR pwszString)
  {
      printf("%ws
", pwszString);
      return(ResultFromScode(S_OK));
  }


  CHello::~CHello(void)
  {

  // when the object count goes to zero, stop the server
  cObjRef--;
  if( cObjRef == 0 )
      PulseEvent(hEvent);

  return;
  }

  #include <windows.h>
  #include <ole2.h>
  #include "pshlo.h"
  #include "shlo.hxx"
  #include "mycls.hxx"

  HANDLE hEvent;

   int _cdecl main(
  int argc,
  char * argv[]
  ) {
  ULONG ulRef;
  DWORD dwRegistration;
  CHelloCF *pCF = new CHelloCF();

  hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);

  // Initialize the OLE libraries
  CoInitializeEx(NULL, COINIT_MULTITHREADED);

  CoRegisterClassObject(CLSID_CHello, pCF, CLSCTX_LOCAL_SERVER,
      REGCLS_MULTIPLEUSE, &dwRegistration);

  // wait on an event to stop
  WaitForSingleObject(hEvent, INFINITE);

  // revoke and release the class object
  CoRevokeClassObject(dwRegistration);
  ulRef = pCF->Release();

  // Tell OLE we are going away.
  CoUninitialize();

  return(0); }

  extern CLSID CLSID_CHello;
  extern UUID LIBID_CHelloLib;

  CLSID CLSID_CHello = { /* 2573F891-CFEE-101A-9A9F-00AA00342820 */
      0x2573F891,
      0xCFEE,
      0x101A,
      { 0x9A, 0x9F, 0x00, 0xAA, 0x00, 0x34, 0x28, 0x20 }
  };

  UUID LIBID_CHelloLib = { /* 2573F890-CFEE-101A-9A9F-00AA00342820 */
      0x2573F890,
      0xCFEE,
      0x101A,
      { 0x9A, 0x9F, 0x00, 0xAA, 0x00, 0x34, 0x28, 0x20 }
  };

  #include <windows.h>
  #include <ole2.h>
  #include <stdlib.h>
  #include <string.h>
  #include <stdio.h>
  #include "pshlo.h"
  #include "shlo.hxx"
  #include "clsid.h"

  int _cdecl main(
  int argc,
  char * argv[]
  ) {
  HRESULT  hRslt;
  IHello        *pHello;
  ULONG  ulCnt;
  IMoniker * pmk;
  WCHAR  wcsT[_MAX_PATH];
  WCHAR  wcsPath[2 * _MAX_PATH];

  // get object path
  wcsPath[0] = '\0';
  wcsT[0] = '\0';
  if( argc > 1) {
      mbstowcs(wcsPath, argv[1], strlen(argv[1]) + 1);
      wcsupr(wcsPath);
      }
  else {
      fprintf(stderr, "Object path must be specified\n");
      return(1);
      }

  // get print string
  if(argc > 2)
      mbstowcs(wcsT, argv[2], strlen(argv[2]) + 1);
  else
      wcscpy(wcsT, L"Hello World");

  printf("Linking to object %ws\n", wcsPath);
  printf("Text String %ws\n", wcsT);

  // Initialize the OLE libraries
  hRslt = CoInitializeEx(NULL, COINIT_MULTITHREADED);

  if(SUCCEEDED(hRslt)) {


      hRslt = CreateFileMoniker(wcsPath, &pmk);
      if(SUCCEEDED(hRslt))
   hRslt = BindMoniker(pmk, 0, IID_IHello, (void **)&pHello);

      if(SUCCEEDED(hRslt)) {

   // print a string out
   pHello->PrintSz(wcsT);

   Sleep(2000);
   ulCnt = pHello->Release();
   }
      else
   printf("Failure to connect, status: %lx", hRslt);

      // Tell OLE we are going away.
      CoUninitialize();
      }

  return(0);
  }

Apprentice Hacker

  #!/usr/local/bin/perl
  $msg="Hello, world.\n";
  if ($#ARGV >= 0) {
    while(defined($arg=shift(@ARGV))) {
      $outfilename = $arg;
      open(FILE, ">" . $outfilename) || die "Can't write $arg: $!\n";
      print (FILE $msg);
      close(FILE) || die "Can't close $arg: $!\n";
    }
  } else {
    print ($msg);
  }
  1;

Experienced Hacker

  #include <stdio.h>
  #define S "Hello, World\n"
  main(){exit(printf(S) == strlen(S) ? 0 : 1);}

Seasoned Hacker

  % cc -o a.out ~/src/misc/hw/hw.c
  % a.out

Guru Hacker

  % echo "Hello, world."

New Manager

  10 PRINT "HELLO WORLD"
  20 END

Middle Manager

  mail -s "Hello, world." bob@b12
  Bob, could you please write me a program that prints "Hello, world."?
  I need it by tomorrow.
  ^D

Senior Manager

  % zmail jim
  I need a "Hello, world." program by this afternoon.

Chief Executive

  % letter
  letter: Command not found.
  % mail
  To: ^X ^F ^C
  % help mail
  help: Command not found.
  % damn!
  !: Event unrecognized
  % logout



(Lo encontre en fuente)