Autore Topic: [Hollywood] Gli effetti di transizione  (Letto 1828 volte)

Offline Allanon

  • Administrator
  • Synthetic Voodoo
  • *****
  • Post: 3498
  • Karma: +17/-4
    • Mostra profilo
    • http://www.a-mc.biz
[Hollywood] Gli effetti di transizione
« il: 04 Dicembre 2011, 00:09:41 »
PROLOGO
Apro questo thread per spiegare come funzionano gli effetti di transizione di Hollywood, la loro gestione e successivamente illustrerò una mia libreria che ho implementato per semplificare la gestione degli effetti in maniera asincrona.

GLI EFFETTI DI TRANSIZIONE
Per effetto di transizione si intende un effetto speciale con il quale una data immagine viene mostrata sullo schermo.
Hollywood è nato principalmente come strumento per realizzare delle presentazioni interattive e solo successivamente è stato sviluppato come  linguaggio vero e proprio orientato al multimedia, è per questo che risulta essere molto potente in questo settore, perchè è nato proprio per fare ciò.

Come ho anticipato è possibile mostrare a video una determinata immagine con un effetto di transizione, come ad esempio una dissolvenza. Con questo metodo è possibile mostrare dei Brush, dei Layer, degli oggetti testuali o delle immagini di sfondo (Backdrop).
Adesso non starò qui ad illustrare tutti i comandi disponibili ma solo un paio, i più comuni, ossia i Brush e i Layer e le meccaniche di funzionamento.

Per mostrare un brush utilizzando un effetto di transizione si utilizza il comando:
Codice: [Seleziona]
DisplayBrushFX(brush_id, x, y, parameters)
Dove:
 - brush_id -> id del brush creato o caricato
 - x, y -> coordinate dove mostrare il brush
 - parameters -> tabella contenente ulteriori parametri legati all'effetto da utilizzare

I campi supportati nella tabella <parameters> sono:
 - type -> effetto da utilizzare per la transizione (ad esempio: #CROSSFADE, #DIAGONAL, #ROLLTOP, ecc...)
 - speed -> velocità dell'effetto (può essere un numero oppure una costante predefinita tipo: #NORMALSPEED, #FASTSPEED, ...)ù
 - parameter -> parametro addizionale richiesto da alcuni effetti particolari
 - async -> flag che permette di eseguire transizioni asincrone (default False)

Questo semplice pezzettino di codice mostrerà come eseguire una transizione con un brush mostrandolo al centro dello schermo:
Codice: [Seleziona]
...
Local mybrush = LoadBrush(Nil, "testimage.jpg")
DisplayBrushFX(mybrush, #CENTER, #CENTER, { type = #CROSSFADE })
Print("Done!")
...

In pratica viene caricato un brush e mostrato a video con l'effetto crossfade, al termine della transizione verrà stampato il testo "Done!".
Come si vede è molto semplice gestire le transizioni ma anche molto limitante perchè in questo modo è possibile eseguire una sola transizione alla volta.

Se ad esempio dovessi mostrare più brush o layer contemporaneamente ed eventualmente con effetti differenti per ognuno di essi sarà indispensabile gestire manualmente le transizioni in maniera asincrona, questo è possibile impostando il flag async = True nella tabella parameters vista poco più su.

EFFETTI DI TRANSIZIONE ASINCRONI
Modificando il minuscolo esempio che abbiamo fatto per una gestione asincrona avremo il seguente codice:
Codice: [Seleziona]
...
Local mybrush = LoadBrush(Nil, "testimage.jpg")
Local fx_id = DisplayBrushFX(mybrush, #CENTER, #CENTER, { type = #CROSSFADE, async = True })
Print("Done!")

While Not(ASyncDrawFrame(fx_id))
   Wait(50,  #MILLISECONDS)
Wend
Print("Transition done!")
...

Quando si utilizza la transizione asincrona la funzione che determina l'effetto (in questo caso DisplayBrushFX) restituisce sempre un id di riferimento all'effetto in modo da permetterci di referenziare la transizione per poterla aggiornare (ASyncDrawFrame), terminare (FinishASyncDraw) oppure interrompere (CancelASynDraw).
E' chiaro che nel loop While...Wend stiamo gestendo manualmente la transizione, frame dopo frame con un'attesa di 50 millisecondi fra ogni aggiornamento.
Il comando ASyncDrawFrame() resituisce True se non ci sono altri frame da disegnare altrimenti restituisce False.
L'esempio è molto spartano ma permette di capire il meccanismo, con questa tecnica è possibile utilizzare delle routine di aggiornamento temporizzate con estrema semplicità che possono gestire tutte le transizioni asincrone che vogliamo in maniera efficiente.

Per concludere questa prima panoramica aggiungo che attraverso il comando ASyncDrawFrame() è possibile richiedere uno specifico frame da visualizzare, è quindi possibile avere il controllo totale della transizione mostrando i frame con la sequenza desiderata.
« Ultima modifica: 01 Gennaio 1970, 02:00:00 da Guest »

Offline Allanon

  • Administrator
  • Synthetic Voodoo
  • *****
  • Post: 3498
  • Karma: +17/-4
    • Mostra profilo
    • http://www.a-mc.biz
Re: [Hollywood] Gli effetti di transizione
« Risposta #1 il: 04 Dicembre 2011, 00:10:49 »
ASYNCFX LIBRARY: IMPLEMENTAZIONE (Parte 1)
Come abbiamo visto il meccanismo per gestire gli effetti asincroni è semplice ma gestire un determinato numero di effetti (non predeterminato) potrebbe risultare complicato con un semplice loop.

A me piace molto l'approccio "Run & Forget" ossia lancia (una routine) e dimenticati (di essa), in questo modo tutte le risorse allocate dal lancio della routine dovranno essere automaticamente deallocate al temine di essa liberando il programmatore da ulteriori complicazioni: ma questo è solo un mio modo di vedere le cose :)

Per comodità chiamerò le animazioni (o effetti asincroni) come "task".

La lista della spesa è la seguente:
 - Una tabella dove raggruppare i dati globali della libreria
 - Un oggetto Task con relativi metodi e proprietà che rappresenta ogni effetto asincrono che vogliamo gestire con questa libreria

La tabella globale si chiama "AFX" e conterrà:
 - Tutti i task attualemente in esecuzione (e quindi una sequenza di oggetti Task)
 - Una serie di parametri globali

Inoltre a me piace automatizzare le cose al massimo quindi ho inserito le seguenti feature aggiuntive:
 - Possibilità di "aggiustare" il timing di aggiornamento del singolo oggetto con un offset sul timing globale
 - Deallocazione automatica dell'oggetto task una volta concluso l'effetto
 - La possibilità di agganciare una funzione all'evento "OnEnd" all'oggetto task che si verifica quando il task termina
 - La possibilità di agganciare una funzione quando viene rilevato l'evento "OnNoTasks", ossia quando tutti i task sono stati conclusi

Questo mi permette una flessibilità infinita nel concatenare gli effetti, se per esempio ho una funzione che mi carica un immagine e la mostra utilizzando una transizione, basterà agganciarla all'evento "OnEnd" del task che stiamo creando per creare un loop infinito, e il tutto senza bloccare minimamente l'esecuzione del codice, in maniera asincrona appunto.
Stesso discorso per l'evento "OnNoTasks": io lancio una serie di effetti e non ho la più pallida idea di quando saranno tutti terminati, ma con questo evento è semplice perchè la funzione agganciata a questo evento sarà automaticamente chiamata nel preciso istante in cui l'ultimo effetto in corso sarà stato completato.

Detto ciò, l'implementazione è abbastanza semplice, tutto ruota attorno ad una routine che sarà chiamata ad intervalli regolari ed in maniera automatica installando la funzione con il comando "SetInterval()".
Questo comando è potentissimo perchè permette di definire una funzione da chiamare ogni tot tempo (millisecondi, ticks (=50ms) o secondi), non ci sono limiti al numero di funzioni che possiamo definire con questo metodo.
Ovviamente la libreria prevede anche la possibilità di aggiornare manualmente tutti gli effetti chiamando direttamente la funzione di aggiornamento di tutti i task.

Quindi, riepilogando, questa sarà lo scheletro della libreria:

Codice: [Seleziona]
; Alcune costanti riferite allo stato della routine globale di aggiornamento
Const #AFX_STATE_RUNNING = 1
Const #AFX_STATE_PAUSED  = 2

; Altre costanti riferite allo stato del singolo task
Const #AFX_TASKSTATE_RUNNING = 1
Const #AFX_TASKSTATE_PAUSED  = 2
Const #AFX_TASKSTATE_ENDED   = 3

Struttura globale:
Codice: [Seleziona]
Global AFX = {}                     ; Main data structure
       AFX.Tasks = {}               ; Defined tasks list
       AFX.Data  = {                ; Engine data
          Upd_Freq   = -1,                 ; Updater frequency in ms
          Def_State  = -1,                 ; Default new tasks state
          State      = #AFX_STATE_RUNNING, ; Engine state
          TasksCount = -1,                 ; Tasks counter
          OnNoTasks  = Nil,                ; Function to call when all tasks are ended
          TimerID    = Nil,                ; Timer id used to update the tasks
          UpdaterID  = Nil }               ; Interval ID for the updater

       AFX.Build = {
          Date       = "2011.12.04",  ; Build date
          Version    = 1,             ; Build version
          Subversion = 0 }            ; Build subversion

Funzioni globali (che agiscono su tutti i task):
Codice: [Seleziona]
AFX.Init(params) -> Inizializza la libreria, se ci sono task avviati li elimina
AFX.Update() -> Aggiorna tutti i task definiti
AFX.Free() -> Rimuove tutti i task attualmente in uso e ne libera le risorse  
AFX.Finish() -> Termina l'effetto mostrandone l'ultimo frame e rimuove il task  
AFX.Cancel() -> Termina l'effetto lasciando il frame corrente e rimuove il task
AFX.Pause() -> Mette in pausa l'aggiornamento di tutti i task
AFX.Resume() -> Riprende l'aggiornamento di tutti i task


Oggetto TaskObject
Codice: [Seleziona]
  AFX.TaskObject = {
      Name = "",                 ; Unique task name
      FXID    = -1,              ; Async Fx id
      UpdFreq = 0,               ; Update frequency
      OnEnd   = Nil,             ; OnEnd event
      Userdata = Nil,            ; Userdata field
      Private = {
         NxUpdate = -1,          ; Timer for the next update
         State    = -1           ; FX current state
      }
   }

Metodi del TaskObject:
Codice: [Seleziona]
AFX.TaskObject:Add(FXId, OnEnd, Userdata, UpdFreq, Name) -> Aggiunge un nuovo task da aggiornare
AFX.TaskObject:Update() -> Aggiorna il task
AFX.TaskObject:Remove() -> Rimuove il task  
AFX.TaskObject:Cancel() -> Interrompe l'effetto lasciando il frame corrente e rimuove il task
AFX.TaskObject:Finish() -> Interrompe l'effetto mostrando l'ultimo frame e rimuove il task
AFX.TaskObject:Pause() -> Mette in pausa l'aggiornamento del task
AFX.TaskObject:Resume() -> Riprende l'aggiornamento del task


Nella prossima puntata entrerò nel dettaglio del codice :)

ASYNCFX LIBRARY: IMPLEMENTAZIONE (Parte 2)
...
« Ultima modifica: 01 Gennaio 1970, 02:00:00 da Guest »

Offline Allanon

  • Administrator
  • Synthetic Voodoo
  • *****
  • Post: 3498
  • Karma: +17/-4
    • Mostra profilo
    • http://www.a-mc.biz
Re: [Hollywood] Gli effetti di transizione
« Risposta #2 il: 04 Dicembre 2011, 00:11:55 »
[POST RISERVATO] ASYNCFX LIBRARY: I task e gli eventi
« Ultima modifica: 01 Gennaio 1970, 02:00:00 da Guest »

Offline Allanon

  • Administrator
  • Synthetic Voodoo
  • *****
  • Post: 3498
  • Karma: +17/-4
    • Mostra profilo
    • http://www.a-mc.biz
Re: [Hollywood] Gli effetti di transizione
« Risposta #3 il: 04 Dicembre 2011, 00:13:15 »
[POST RISERVATO] ASYNCFX LIBRARY: Esempio pratico + eseguibili
« Ultima modifica: 01 Gennaio 1970, 02:00:00 da Guest »

Offline cdimauro

  • Human Debugger
  • *****
  • Post: 4291
  • Karma: +7/-95
    • Mostra profilo
Re: [Hollywood] Gli effetti di transizione
« Risposta #4 il: 04 Dicembre 2011, 06:38:01 »
Non mi è chiaro cosa succede al background applicando gli effetti a un brush. Mi spiego meglio con un semplice esempio.

Supponiamo che ci sia uno sfondo che visualizzi un'immagine (statica o dinamica, è indifferente). Decido di farvi apparire sopra un'immagine in dissolvenza, sfruttando soltanto l'alpha channel (da 0.0 a 1.0, o da 0 a 255, a seconda se venga gestito come double o come intero). Quindi all'inizio l'immagine è totalmente trasparente e poi diviene via via sempre più opaca, fino a essere totalmente opaca (a meno che l'immagine non faccia uso a sua volta dell'alpha channel per i suoi pixel, ma per semplificare assumiamo che sia totalmente opaca).

L'immagine visualizzata tiene conto del background e del livello di alpha dell'immagine che si sta visualizzando in dissolvenza? Cioè, le due immagini vengono "fuse" sfruttando l'alpha?

Offline Allanon

  • Administrator
  • Synthetic Voodoo
  • *****
  • Post: 3498
  • Karma: +17/-4
    • Mostra profilo
    • http://www.a-mc.biz
Re: [Hollywood] Gli effetti di transizione
« Risposta #5 il: 04 Dicembre 2011, 09:28:02 »
Si, il background e tutto ciò che vi è stato "stampato" sopra fino a quel momento viene considerato correttamente e le trasparenze del brush sono tenute in considerazione durante l'esecuzione dell'effetto, non solo, se sotto l'effetto c'è un'animazione o un altro effetto questo sarà tenuto in considerazione correttamente.
Il background abbinato al display (finestra) corrente può anche avere parti trasparenti o semitrasparenti per generare finestre "bucate".
Quando mostrerò l'esempio (dove ho utilizzato i layer, ma è lo stesso per i brush o per ogni altro oggetto che supporta gli effetti), vedrai che ci saranno <n> immagini sovrapposte che appaiono e scompaiono con degli effetti di transizione in corso senza darsi fastidio tra loro.
« Ultima modifica: 01 Gennaio 1970, 02:00:00 da Guest »

Offline cdimauro

  • Human Debugger
  • *****
  • Post: 4291
  • Karma: +7/-95
    • Mostra profilo
Re: [Hollywood] Gli effetti di transizione
« Risposta #6 il: 04 Dicembre 2011, 14:13:34 »
Ottimo. Grazie per le informazioni. Aspetto il resto.

Offline Allanon

  • Administrator
  • Synthetic Voodoo
  • *****
  • Post: 3498
  • Karma: +17/-4
    • Mostra profilo
    • http://www.a-mc.biz
Re: [Hollywood] Gli effetti di transizione
« Risposta #7 il: 04 Dicembre 2011, 19:40:11 »
Aggiornato post #2, inserita prima parte dell'implementazione
« Ultima modifica: 01 Gennaio 1970, 02:00:00 da Guest »

Tags: