Chi mi conosce sa bene il mio rapporto di amore-odio con Java. Amore perché Java è un linguaggio performante, di alto livello e soprattutto portabile. L’ho usato spesso, lo uso tutt’ora e ci ho fatto addirittura del game development. Odio perché, proprio perché ci ho combattuto tanto, ne conosco tutti i difetti, i limiti e le idiosincrasie. Java è sintatticamente prolisso e ha qualche problema di “vecchiaia” che andrebbe risolto (ed il confronto con C# è impietoso). Continue reading »

 
skyrim

Qualche tempo fa, durante l’incontro annuale di AltDevConf 2012, Miguel de Icaza ha partecipato con un talk dal titolo “Mono for Game Development”. Una presentazione interessante (che trovate nel link) che dava una panoramica piuttosto completa dell’utilizzo di C# e di Mono nello sviluppo videoludico e dei vantaggi che ne conseguono.

Ok. Una presentazione di de Icaza sui vantaggi di Mono suona molto come chiedere all’oste se il vino è buono. Tuttavia l’argomento è interessante e lancia subito una domanda: “Mono e C# sono veramente linguaggi utili e con un futuro nello sviluppo di videogame?”

Continue reading »

 

Mi hanno fatto una domanda nei commenti molto interessante: come posso sfruttare Lua con del codice Fortran? Bene, ho trovato una soluzione piuttosto semplice ed interessante per cui ho deciso di scriverci sopra un bel post.

Per prima cosa sappiate che non c’è un vero modo per collegare Lua a Fortran direttamente. Lua ha la sua libreria in C, pensata per il C e funziona per il C. Anche cercando in giro non ho trovato nulla che permetta il collegamento diretto. Tuttavia il Fortran e il C/C++ sono collegabili nativamente! Per questo motivo il procedimento si sintetizza in due punti

  • Collegare le funzioni Fortran alle funzioni C++
  • Collegare Lua alle funzioni C++

In questo modo il C++ assume il ruolo di collante fra Fortran e Lua e tutto funziona a meraviglia ma non solo: nonostante l’approccio a tre vie l’implementazione è formidabilmente trasparente e intuitiva!

Poiché sappiamo già come collegare Lua al C++ comincerò a far vedere come collegare Fortran a C++. Cominciamo con il codice C++ di esempio.

#include <iostream>

using namespace std;

extern "C" {
  void ffunction_(float *a, float *b);
}

int main()
{
    float a = 0;
    float b = 0;
   
    ffunction_(&a,&b);
   
    cout << a << " " << b << endl;
}

Il programma è stupido, lo so, ma rende l’idea. In pratica lasciamo che la funzione ffunction_ vada a modificare i valori delle due variabili a e b e poi stampiamo i nuovi valori.

Ma cosa fa ffunction_? Questa è la nostra funzione Fortran e nel codice C++ dobbiamo solo assicurarci che sia definita come extern. Il codice di questa funzione è semplice ed è salvato nel file ffunction.f.

      subroutine ffunction(a,b)
      a=3.0
      b=4.0
      end

Ora come compiliamo? Semplicissimo.

  • Prima compiliamo il codice C++ con g++ esempio.cpp -c ottenendo il file esempio.o
  • Poi compiliamo il codice fortran con gfortran ffunction.f -c ottenendo il file ffunction.o
  • Infine uniamo il tutto con g++ -o esempio esempio.o ffunction.o ottenendo l’eseguibile esempio

Niente di più semplice. In pratica, salvo definire le funzioni fortran come extern e l’uso di un compilatore diverso, l’integrazione fra fortran e C++ è praticamente trasparente!

A questo punto collegare Lua al Fortran è praticamente IDENTICO a collegare Lua al C++. Le nostre funzioni LuaGlue non faranno altro che chiamare funzioni Fortran come se stessero chiamando una funzione C++.

Supponiamo di voler chiamare una funzione Fortran che calcoli il fattoriale di un numero come nel caso di esempio di un articolo precedente:

LuaGlue _FortranFactorial(struct lua_State *pLuaState)
{
     double n;
     n = pLua->GetNumberArgument(1);
     
     /* Calcoliamo il fattoriale */
     int res = fortran_factorial_recursive_(n);
     
     /* Restituiamo il valore di ritorno */
     pLua->PushNumber(res);
     
     return 1;
}

Il codice è identico salvo che fortran_factorial_recursive_ questa volta non è una funzione C ma una funzione Fortran definita nel modo che abbiamo visto in precedenza.

E se siete abilissimi programmatori Fortran ma non sapete nulla di C++? Non credo sia un grosso problema, in questo approccio tutta la programmazione è eseguita in Fortran e Lua. Di C++ è necessario sapere proprio le basi e l’uso di LuaGrip per agganciare le funzioni a Lua, nulla più. Una piccola scocciatura e un piccolo sforzo iniziale in più per avere un integrazione Lua/Fortran praticamente perfetta.

 

A parte il nome esotico, volevo presentarvi Lua’s Totally Awesome Tutorial Pack xD

Un modo esagerato e divertente per dirvi che ho raccolto tutto il codice degli scorsi tutorial su Lua e C++ in un comodo file tar.gz. All’interno trovate anche l’ultimissima versione di LuaGrip.

DOWNLOAD

Per prima cosa dovete installare LuaGrip. Per fare questo basta dare i comandi di rito:

mkdir build
cd build
cmake ..
make
sudo make install

A questo punto potete compilare ogni file nel tutorial con g++ aggiungendo i dovuti flag. Se non conoscete i flag vi basta aggiungere in coda:

`pkg-config --cflags libluagrip` `pkg-config --cflags lua5.1` `pkg-config --libs libluagrip` `pkg-config --libs lua5.1`

Non proprio una meraviglia di lettura ma dovrebbe fare decentemente il suo lavoro. :D Magari date i comandi singolarmente e vi segnate i flag in modo da non dover recuperare questa stringa infinita di byte ogni volta che dovete compilare un programma con LuaGrip.

I tutorial funzionano anche su Windows ma non so come compilarli dato che non uso Windows da un lustro.

Fatemi sapere se ci sono problemi.

 

Prima cosa. Così la programmazione event-driven? Risposta semplice: un paradigma di programmazione in cui parti di codice vengono avviare dal lancio di eventi. Risposta ancora più semplice (per gli esperti: perdonatemi la banalizzazione). Immaginate tre persone in una casa. Immaginate che queste persone, dotate di genitori nerd molto crudeli, si chiamino Stampa, AggiungiUno e, ovviamente, Main. Main, il leader del gruppo, vuole contare tutte le macchine rosse che passano davanti la finestra.

Main ha due possibilità: andare a chiamare personalmente AggiungiUno per chiedergli di aumentare un contatore e Stampa per avere il risultato, oppure urlare “MACCHINA ROSSA” in modo tale che chi di dovere capisca che è passata una macchina rossa e aggiunga il contatore.

In questo scenario i due metodi sono pressocché equivalenti, ma supponiamo che Main non conosca il nome di chi è nella casa oppure che ad un certo punto AggiungiUno si faccia sostituire da IncrementaUno. In questo caso sarebbe impossibile programmare Main secondo il primo approccio mentre sarebbe banale programmare Main in modo da gridare MACCHINA ROSSA assumendo che ci sia qualcuno nella casa in grado di capire il significato di quel grido.

La programmazione event-driven consiste proprio nel gridare MACCHINA ROSSA. Ovviamente in programmazione non c’è il suono, sta a noi programmare il mezzo in cui gli eventi vengono propagati.

Senza entrare nel dettaglio vediamo come implementare i Lua e C++ un semplice meccanismo a eventi. Gli eventi saranno lanciati da C++ e verranno raccolti da una funzione Lua.

-- Esempio di programmazione Event-Driven
-- in Lua.

MACCHINA_ROSSA = 1000
STAMPA = 2000

numero_macchine_rosse = 0

RegisterEventHandler("EventHandler")

function EventHandler(id)
    if id == MACCHINA_ROSSA then
    print("Macchine +1")
        numero_macchine_rosse = numero_macchine_rosse + 1
    elseif id == STAMPA then
        print(string.format("%s%d", "Num. Macchine: ", numero_macchine_rosse))
    end
end

Cominciamo con lo script Lua.

Le prime due righe associano solo l’indice dell’evento che vogliamo ad una variabile mnemonica. Nulla di particolare, serve solo a rendere il codice più leggibile e chiaro.

La funzione RegisterEventHandler è importante. È una funzione LuaGlue, ovvero una funzione implementata in C++. Questa funzione comunica alla parte C++ quale è il nome della funzione che gestisce gli eventi. La funzione non è in teoria strettamente necessaria, si potrebbe, ad esempio, scrivere direttamente nel codice C++ che la funzione che gestisce gli eventi è EventHandler. Tuttavia in questo modo renderemmo il codice C++ dipendente dal codice Lua: se cambiamo il nome della funzione o se vogliamo cambiarla in run-time dobbiamo riscrivere anche il codice C++. Usando RegisterEventHandler invece le due cose sono completamente disaccoppiate.

Vediamo ora la funzione principe. EventHandler è il mezzo tramite cui gli eventi si propagano ed ha un comportamento molto semplice: riceve in ingresso l’id dell’evento e lo smista verso la funzione idonea. Nel nostro caso, poiché le funzioni sono piuttosto semplici sono scritte direttamente in EventHandler.

Ora vediamo il listato C++.

#include<iostream>
#include<luagrip.hpp>
#include<string>

#define MACCHINA_ROSSA 1000
#define STAMPA 2000

std::string strEventHandler = "";
LuaGrip* pLua;

LuaGlue _RegisterEventHandler(lua_State *L)
{
    strEventHandler = pLua->GetStringArgument(1,"");
   
    return 1;
}

void FireEvent(int id)
{
    if (strEventHandler != "")
    {
        char buf[254];
        sprintf(buf, "%s(%d)", strEventHandler.c_str(), id);
        pLua->RunString(buf);
    }
}

int main()
{
    pLua = new LuaGrip();
    pLua->AddFunction("RegisterEventHandler",_RegisterEventHandler);
    pLua->RunScript("event.lua"); // Carica il modulo Lua.
   
    FireEvent(MACCHINA_ROSSA);
    FireEvent(MACCHINA_ROSSA);
    FireEvent(STAMPA);
    FireEvent(MACCHINA_ROSSA);
    FireEvent(STAMPA);
   
    delete pLua;
}

Il codice è composto da tre funzioni.

La prima è _RegisterEventHandler. Abbiamo già parlato di questa funzione che si limita a ricevere il nome della funzione incaricata di gestire gli eventi e di memorizzarlo in una variabile globale.

La seconda è FireEvent. Come possiamo intuire dal nome questa funzione lancia gli eventi (nel nostro esempio corrisponde all’azione di gridare). In che modo? Ci sono molti modi diversi, il più semplice dei quali consiste nel creare una stringa che corrisponde ad una chiamata di funzione Lua e poi eseguirla nel solito modo.

Infine la funzione main inizializza Lua e lancia gli eventi. La sequenza descritta in main da luogo al seguente output:

Macchine +1
Macchine +1
Num. Macchine: 2
Macchine +1
Num. Macchine: 3

Questa struttura è la base del meccanismo event-driven. Ovviamente la struttura può essere ulteriormente complicata, ad esempio permettendo l’uso di eventi con argomenti (ad esempio un evento IncrementaN).

La prossima volta vorrei farvi vedere invece come sfruttare Lua per il salvataggio e il caricamento dei dati.

 

Aldrin Apollo 11

Abbiamo visto negli articoli precedenti come utilizzare funzioni C++ all’interno dei script Lua (e viceversa). Ci eravamo però dimenticati di dire come fare a passare dati sottoforma di parametri fra Lua e C++. Ora è giunto il momento di colmare questa lacuna.

Il passaggio di parametri fra funzioni Lua e C++ è, come potete immaginare, un aspetto fondamentale della programmazione mista Lua/C++. Tuttavia, nonostante la procedura non sia delle più intuitive, è estremamente semplice. Ma partiamo da un esempio, consideriamo il seguente script Lua.

-- Questo è un esempio di script Lua che
-- utilizza al suo interno una funzione C++.

print("Fattoriale di 5!")
print("Implementato in C++ con amore!")
print(Factorial(5))

Un caso d’uso dei più banali consiste nell’usare all’interno di uno script Lua funzioni C++ per le operazioni CPU-intensive. Possiamo trovare un esempio spicciolo nel listato Lua precedente. La funzione Factorial per il calcolo del fattoriale è notoriamente una funzione che necessita di una buona velocità. Così, invece di implementarla in Lua useremo una funzione C++. Vediamo quindi il codice C++.

LuaGrip* pLua;

int factorial_recursive(int n)
{
    if (n==1) return 1;
    return n * factorial_recursive(n-1);
}

LuaGlue _Factorial(struct lua_State *pLuaState)
{
    /* Ricaviamo i parametri della funzione.
     *
     * La funzione Lua agganciata a questa funzione C++
     * ha la seguente struttura:
     *
     *     int Factorial(int n)
     *
     * Dobbiamo quindi recuperare il primo int.
     */

     double n;
     n = pLua->GetNumberArgument(1);
     
     /* Calcoliamo il fattoriale */
     int res = factorial_recursive(n);
     
     /* Restituiamo il valore di ritorno */
     pLua->PushNumber(res);
     
     return 1;
}

La funzione _Factorial è la classica funzione LuaGlue. La domanda viene spontanea: come fare a passare il valore 5 alla funzione Factorial? E come fare a restituire il valore finale? Andiamo per passi:

La prima cosa che facciamo nella funzione _Factorial è proprio recuperare il parametro 5. Facciamo questo tramite la funzione LuaGrip double GetNumberArgument(int argnum). La funzione prende in ingresso il numero del parametro da recuperare, nel nostro caso abbiamo bisogno del primo parametro e quindi usiamo semplicemente il numero 1. Come valore di ritorno la funzione restituisce un double.

A questo punto passiamo il valore recuperato ad una funzione “tradizionale” factorial_recursive che calcola il valore del fattoriale nel modo “classico”.

Infine, il valore di ritorno viene restituito a Lua grazie alla funzione LuaGrip void PushNumber(res).

Mi raccomando non dimenticate di ritornare un 1 alla fine altrimenti Lua interpreterà il mancato valore di ritorno come un errore nella funzione.

A questo punto scriviamo il main che, in questo caso, non farà altro che agganciare la funzione Factorial a Lua e lanciare lo script.

int main()
{
    pLua = new LuaGrip();
    pLua->AddFunction("Factorial",_Factorial);
    pLua->RunScript("fac.lua");
    delete pLua;
}

A questo punto l’integrazione è completa! Non c’è molto altro da sapere :)

Tuttavia continuerò a presentare esempi. Nel prossimo articolo su Lua/C++ ho intenzione di parlare su come utilizzare Lua per la programmazione event-driven.

 

Full Moon Space Art

Poiché l’argomento Lua e C++ è di notevole interesse per me ed ha suscitato un discreto numero di contatti mi sento in dovere di approfondirlo. La cosa necessiterebbe di un mare di tempo e spazio in quanto si potrebbero scrivere libri e libri sull’argomento (e infatti ce ne sono migliaia) ma cercherò di concentrarmi sugli aspetti pratici e implementativi.

Per ogni esempio che farò ora e per i secoli a venire farò sempre riferimento alla mia libreria LuaGrip (che potete scaricare qui). Questa libreria ha lo scopo di nascondere e avvolgere il collegamento di basso livello con la libreria nativa di Lua. Ho fatto questo per due motivi:

  • Semplificare e abbreviare le operazioni ripetitive del collegamento c++/lua come ad esempio la creazione dell’ambiente lua e la sua distruzione.
  • La libreria di Lua è scritta in C e la sua integrazione in C++ richiede un paio di accortezze che magari risulterebbero di difficile comprensione a chi non è espertissimo. Usando LuaGrip potete fregarvene del tutto e potete utilizzarlo tranquillamente anche se siete apprendisti.

La libreria è direttamente ispirata (dico ispirata per dire che le API sono copiate pari pari) ad una libreria descritta nel libro “Game Developement with Lua” di Paul Schuytema e Mark Manyen. Ho dovuto però reimplementare tutto per rendere l’interfaccia il più generica possibile e per aggiornare il codice alla nuova versione di lua (5.1).

Detto questo, la prima cosa da fare è studiarci per bene il programma di esempio che è incluso nel pacchetto:

#include <stdio.h>
#include <string.h>
#include "luagrip.hpp"

Per prima cosa che vediamo sono i consueti include. Fin qui non c’è nulla di particolare.

LuaGlue _Version(lua_State *L)
{
    puts("This is Version 2.0 of the Console Program");
    return 0;
}

La prima funzione che troviamo è la funzione _Version. Questa funzione è una funzione LuaGlue ovvero una funzione implementata in C++ che sarà richiamabile da uno script Lua. La funzione ha i seguenti particolari:

  • Il valore di ritorno è LuaGlue. Consideratelo semplicemente un valore int.
  • Il nome comincia con un underscore (_). Questa è solo una convenzione stilistica.
  • Come unico parametro in ingresso abbiamo un puntatore a lua_State.

Tutto questo sembra estremamente limitante ma così non è. Vedremo poi come sia possibile sfruttare il puntatore allo stato (o semplicemente la classe LuaGrip) per avere in ingresso qualsiasi parametro e restituire qualunque valore.

char gpCommandBuffer[254];

const char *GetCommand(void)
{
    printf("Ready> ");
    return fgets(gpCommandBuffer,254,stdin);
}

Questa è una semplice funzione ausiliaria, non ha nessun collegamento con lua. Questa funzione non fa altro che leggere una stringa dalla shell e memorizzarla nel buffer gpCommandBuffer.

int main()
{
    LuaGrip *pLua = new LuaGrip;
    pLua->AddFunction("Version",_Version);
   
    pLua->RunScript("hello.lua");
   
    const char *pCommand = GetCommand();
    while(strcmp(pCommand, "QUIT\n") != 0)
    {
        if(!pLua->RunString(pCommand))
        {
            printf("ERROR:%s\n",pLua->GetErrorString());
        }
        pCommand = GetCommand();
    }
   
    delete pLua;
}

Ora veniamo al sodo: la funzione main. La prima cosa che facciamo è creare un istanza della classe LuaGrip che inizializza la macchina virtuale di Lua.

Subito dopo agganciamo la funzione _Version all’interprete Lua. In pratica diciamo alla macchina virtuale di Lua di agganciare la funzione Lua Version alla funzione C _Version. Da questo momento in poi possiamo usare la funzione Version() all’interno di uno script Lua come se fosse un qualsiasi altro comando Lua.

Subito dopo eseguiamo lo script hello.lua, script che non fa altro che stampare a schermo una breve introduzione per la nostra console.

A questo punto inizia il ciclo della shell. Leggiamo i comandi inviati dall’utente fino a quando non viene digitato il comando QUIT. I comandi di nostro interesse sono:

  • pLua->RunString(pCommand) – Analogamente al comando RunScript, il quale esegue uno script contenuto in un file, questo comando esegue comandi Lua contenuti in una stringa.
  • pLua->GetErrorString() – Questo comando restituisce la stringa di errore generata dall’interprete.

Alla fine non ci resta che eliminare l’istanza di LuaGrip per terminare la macchina virtuale.

Ora siamo pronti a vedere come passare valori e parametri fra C++ e Lua. Ma questo ve lo racconto un’altra volta.

Jun 022011
 

Cos’è Lua?

Lua (parola portoghese per luna) è un linguaggio di scripting dinamico, riflessivo e procedurale di origine brasiliana usato massivamente nell’industria dei videogiochi.

Cosa ci fa l’industria dei videogame con Lua? Non usano il c++?

Si. Programmi con altissime richieste prestazionali come i videogiochi non possono fare a meno di utilizzare linguaggi compilati di medio-basso livello come il c++. Tuttavia programmare in c++ è sicuramente più scomodo che programmare in un linguaggio di alto livello e, inoltre, non tutte le parti di un software necessitano della stessa ferrea richiesta di performance. Sarebbe come voler costruire una casa resistente intagliandola in un mastodontico blocco di marmo. :) La prassi consiste quindi nello scrivere grossi mattoni in C++ puro e di legarli insieme con una calce fatta con un linguaggio di scripting.

Nell’industria dei videogiochi da molto tempo si utilizza una calce fatta con Lua.

Lua? Perché usare un linguaggio che non ho mai sentito quando si può usare un linguaggio noto come Python, Ruby o altro?

Nulla vi vieta di usarli. Tuttavia ci sono tre grandi motivi che rendono ancora Lua un leader nel suo campo. Primo, Lua nasce per essere integrato in codice compilato, integrazione che quindi risulta semplice ed efficace. Secondo, a differenza degli altri linguaggi di scripting Lua è decisamente spartano, non possiede nemmeno il paradigma a oggetti (che però può essere replicato in modo personalizzato usando le strutture dati native di Lua); questa essenzialità rende Lua performante. Terzo, e più importante, Lua è estremamente versatile per quanto riguarda il multithreading (permette, ad esempio, di avviare un interprete separato per ogni thread).

Detto questo potete comunque utilizzare nel vostro progetto qualunque linguaggio di scripting, ma almeno saprete cosa ha Lua in più o in meno (e potrete così fare una scelta consapevole).

Figo! Come posso integrare Lua in un mio progetto?

Ho scritto un wrapper in C++ per semplificare ulteriormente l’integrazione di Lua nel vostro progetto.

#ifndef H_LUAGRIP
#define H_LUAGRIP

extern "C" {
#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>
}

struct lua_State;

#define LuaGlue extern "C" int

extern "C" {
    typedef int (*LuaFunctionType)(struct lua_State *pLuaState);
};

class LuaGrip
{
    public:
        /**
         * Constructor.
         */

        LuaGrip();
        virtual ~LuaGrip();
       
        /**
         * Execute Lua script indicated by pFilename.
         *
         * @param pFilename [in] Script's path.
         * @return false on error. true otherwise.
         */

        bool RunScript(const char *pFilename);
       
        /**
         * Execute one string.
         *
         * @param pCommand [in] String representing a Lua command.
         * @return false on error. true otherwise.
         */

        bool RunString(const char *pCommand);
       
        /**
         * Get a string representing the last occurred error.
         *
         * @return ...
         */

        const char *GetErrorString();
       
        /**
         * Link a C/C++ function to Lua interpeter.
         *
         * @param pFunctionName [in] String of function name.
         * @param pfunction [in] Pointer to a function you are going to link.
         * @return  false on error. true otherwise.
         */

        bool AddFunction(const char *pFunctionName, LuaFunctionType pFunction);
       
        /**
         *
         */

        const char *GetStringArgument(int num, const char *pDefault=NULL);
       
        /**
         *
         */

        double GetNumberArgument(int num, double dDefault=0.0);
       
        void PopLast();
       
        void PushString(const char *pString);
        void PushNumber(double value);
   
    private:
        lua_State *m_State;
};

#endif /* H_LUAGRIP */
#include "luagrip.hpp"
#include <string.h>

LuaGrip::LuaGrip()
{
    this->m_State = luaL_newstate();
    luaL_openlibs(this->m_State);
}

LuaGrip::~LuaGrip()
{
    lua_close(this->m_State);
}

bool LuaGrip::AddFunction(const char *pFunctionName, LuaFunctionType pFunction)
{
    lua_register(this->m_State,pFunctionName,pFunction);
    return true;
}

bool LuaGrip::RunScript(const char *pFilename)
{
    if (!luaL_loadfile(this->m_State, pFilename))
    {
        if (!lua_pcall(this->m_State, 0, LUA_MULTRET, 0))
        {
            return false;
        }
    } else return false;
}

bool LuaGrip::RunString(const char *pCommand)
{
    if (luaL_loadbuffer(this->m_State, pCommand, strlen(pCommand), "line") == 0)
    {
        if (lua_pcall(this->m_State, 0, 0, 0) != 0)
        {
            return false;
        }
    } else return false;

    return true;
}

const char *LuaGrip::GetErrorString(void)
{
    return lua_tostring(this->m_State, -1);
}

const char *LuaGrip::GetStringArgument(int num, const char *pDefault)
{
    return luaL_optstring(this->m_State, num, pDefault);

}

double LuaGrip::GetNumberArgument(int num, double dDefault)
{
    return luaL_optnumber(this->m_State, num, dDefault);
}

void LuaGrip::PushString(const char *pString)
{
    lua_pushstring(this->m_State, pString);
}

void LuaGrip::PushNumber(double value)
{
    lua_pushnumber(this->m_State, value);
}

void LuaGrip::PopLast()
{
    lua_pop(this->m_State,1);
}

Sono due file (uno .hpp e l’altro .cpp) che vi basta aggiungere al vostro progetto ed utilizzarli come una classe qualsiasi.

Ottimo! Un esempio?

Ovviamente. Questa è una piccola “shell” per Lua.

#include <stdio.h>
#include <string.h>
#include "luagrip.hpp"

extern "C" int _Version(lua_State *L)
{
    puts("This is Version 2.0 of the Console Program");
    return 0;
}

char gpCommandBuffer[254];

const char *GetCommand(void)
{
    printf("Ready> ");
    return fgets(gpCommandBuffer,254,stdin);
    //return gets(gpCommandBuffer);
}

int main()
{
    LuaGrip *pLua = new LuaGrip;
    pLua->AddFunction("Version",_Version);
   
    pLua->RunScript("hello.lua");
   
    const char *pCommand = GetCommand();
    while(strcmp(pCommand, "QUIT\n") != 0)
    {
        if(!pLua->RunString(pCommand))
        {
            printf("ERROR:%s\n",pLua->GetErrorString());
            pLua->PopLast();
        }
        pCommand = GetCommand();
    }
   
    delete pLua;
}

Hello.lua non è altro che un “Hello World” scritto in Lua: print("Hello World!")

Se volete vi darò qualche ulteriore dettaglio sull’uso di Lua in un prossimo articolo. Fatemi sapere.

 

Vi avevo avvertito che stavo lavorando ad un piccolo progetto didattico. Sono quindi lieto di annunciarvi che finalmente è disponibile una versione funzionante di questa piccola libreria.

OpenGLoader è un semplicissimo mesh-loader (sistema che si occupa di caricare in memoria la struttura 3D di un oggetto scritta in un file) scritto in C++ che potete utilizzare per caricare dei modelli pre-costruiti all’interno delle vostre applicazioni. Questa libreria non ha affatto intenzione di sostituirsi a librerie professionali ma vuole essere una via estremamente breve per inserire mesh complessi in programmi di complessità medio-bassa.

Il primo intento di OpenGLoader è di essere istruttivo. Il sorgente è volutamente semplice, super modulare e “all-inclusive” ovvero non fa uso di alcuna libreria esterna (escluse le OpenGL, ovviamente).

Il secondo intento è di essere estremamente veloce da usare. Infatti una mesh può essere caricata con 2 comandi:

gloDLInitFile("/home/davide/scimmia_tr.obj", gloReader::GLO_OBJ);
GLuint dl;
gloDLRead(&amp;dl);

La sintassi è estremamente semplice: si inizializza il tutto con gloDLInitFile passando come parametro la posizione e il formato del file. Poi si genera un display-list tramite gloDLRead.

Per chi non conoscesse le display list vi dico che per essere disegnate basta dare questi comandi:

glColor3f(1.0, 1.0, 1.0);

glCallList(dl);
glFlush();

Il programma è ancora molto immaturo, funziona ma non è stato ancora testato a dovere e, inoltre, credo che dia ancora qualche problema di memory-leak dato che quell’aspetto lo devo ancora valutare accuratamente. Quindi usatelo per giocarci ma vi sconsiglio ancora di usarlo per applicazioni “serie”.

La versione inoltre è estremamente limitata rispetto alle caratteristiche che ho programmato per la versione completa. Ecco alcune limitazioni:

  • Non supporta la decodifica delle texture.
  • Non supporta la decodifica dei materiali.
  • Supporta esclusivamente i file nel formato .OBJ.
  • Output solamente sotto forma di display-list.

Tuttavia questo basta e avanza per poter usare, ad esempio, Blender per costruire modelli, esportarli in OBJ e importarli nella vostra applicazione.

Detto questo vi lascio alla pagina di git-hub dove trovate il codice sorgente e il download della documentazione delle API. In attesa che completi una documentazione più dettagliata. :)

REPO GIT

 

In e C/C++ si ha la convenzione di suddividere il codice all’interno di due file: i file .h per le dichiarazioni e .cpp o .c. Le motivazioni di questa scelta, in realtà, vanno oltre il semplice vezzo stilistico. Tale suddivisione permette infatti una profonda modularità del software e una rudimentale forma di information-hiding. I vari moduli (cpp) quando richiamano un altro modulo (tramite include) vengono a conoscenza solamente delle dichiarazioni delle funzioni e mai della loro implementazione. Implementazione che, inoltre, non gli servirebbe a nulla.

Capita così che il novello programmatore C++ (nostro ormai noto compagno di avventure), conscio di questa convenzione, inizia a scrivere le sue classi con disinvoltura. Suddivide tutte le sue classi con cura ma pecca di solerzia: divide anche le classi template.

Le classi template sono delle classi che hanno uno (o più) tipi parametrizzati. Supponiamo infatti di voler scrivere una struttura dati (ad esempio un array)per organizzare Pere. Poi decidiamo di scrivere una struttura dati analoga solo per gestire Autoradio. Ci rendiamo conto che la struttura fondamentale delle due classi è la stessa. Senza template dovremmo scrivere due classi differenti mentre con le classi template ci basta farne una parametrizzata. Vediamo un esempio:

template
class MyArray
{
         std::vector data;
      public:
         void Add(T  *d);
         void Remove();
         void Print();
};

Come potete notare all’interno di questo scheletro di classe il tipo gestito non è esplicito ma indicato da un segnaposto T. Quando inizializziamo una nuova coda non ci resta che inizializzarla specificando il tipo parametrizzato, ad esempio in questo modo:

MyArray<Pere> lista_pere = new MyArray<Pere>

Ma come funziona questo artificio stregonesco? Molto semplice: in pratica è il compilatore che si incarica di scrivere le classi differenti basandosi sullo scheletro che voi avete dato.

Ed è proprio qui che cade la magagna! A causa di ciò, infatti, le classi template non possono essere divise in file .h e .cpp. se lo fate noterete che il vostro linker inizierà a lamentarsi vistosamente dicendovi che non esiste nessun MyArray<Pere>.

Il motivo di questo comportamento è logico se ci pensate. Supponiamo di avere diviso il nostro template in due file: MyArray.h e MyArray.cpp. Supponiamo poi di utilizzare il nostro template nel file Fruttivendolo.cpp. A questo punto compiliamo:

  1. Compiliamo tranquillamente il nostro template generando il file compilato MyArray.o.
  2. A questo punto andiamo a compilare Fruttivendolo.cpp.
  3. Come abbiamo detto prima il compilatore nota la riga
    MyArray<Pere>

    e quindi “costruisce” la classe corrispodente.

  4. Ma il file Fruttivendolo.cpp può vedere solo MyArray.h perché è il solo file incluso!

A questo punto il compilatore si porge giustamente la domanda: come faccio a compilare la classe MyArray<Pere> se non conosco come sono implementati i metodi del template MyArray.h?

Infatti non lo fa. Ignora il tutto lasciando il compito al linker e sperando che esso trovi da qualche parte un aggancio ad una classe MyArray<pere> che, come è giusto che sia, non trova.

Come risolvere il problema? La soluzione più semplice è di scrivere tutto (dichiarazione più implementazione) tutto nel file header. Tuttavia noi vogliamo mantenere una certa omogeneità nel codice e vogliamo quindi mantenere la divisione!

Per questo ci sono tre soluzioni accettabili. Ovviamente ognuna hai suoi vantaggi e svantaggi e sta a voi scegliere quale sia la migliore per la vostra esigenza:

  1. Nel file .h aggiungere alla fine la riga #include MyArray.cpp. In questo modo viene simulata la scrittura “tutto in uno” pur mantenendo la suddivisione del file. Ovviamente in questo caso nel file .cpp NON VA INCLUSO IL FILE .h per evitare un inclusione ciclica. Questa soluzione ha lo svantaggio di “gonfiare” il codice compilato nel caso lo stesso template venga utilizzato in parecchi file.
  2. Una soluzione alternativa è di definire tutte le funzioni come inline. Anche qui abbiamo gli stessi svantaggi del caso precedente (forse sono anche peggio).
  3. La terza soluzione è l’ideale se sapete da subito quali sono i tipi di dato con cui utilizzerete il template. In questo caso vi basta aggiungere in fonfo al file .cpp la riga
    template class MyArray<Pere>;

    per forzare la compilazione del template per quei tipi particolari. A questo punto il linker troverà sicuramente una versione già compilate della classe che è stata appena chiamata.

Spero che questa piccola note, spesso trascurata quando si parla di template, vi faccia risparmiare tutto il tempo che ha fatto perdere a me a suo tempo.

Buon coding! :D

© 2008-2012 SlashCode Suffusion theme by Sayontan Sinha