SCARICA NUMERO 3 ORIGINALE
NAVIGA NUMERO 3 ORIGINALE
Amiga Blast Magazine #3
Benvenuti nel terzo numero di Amiga Blast.
Ci scusiamo sinceramente per il ritardo con il quale abbiamo presentato questo numero della rivista.
In questo numero troverete molte novità… ed altre speriamo di potervele offrire tra breve.
Buona lettura!
Contribuite anche voi ad Amiga Blast (Vedere Come Contribuire ad Amiga Blast )
Ora navigate nella rivista.
Amiga la Fenice
L’Orgoglio Di Essere Tra I Più Grandi (Parte 3)
L’Amiga meglio di un PC o un Mac? Probabilmente. (Parte 3)
Continuiamo con le tecniche di Z-Buffering ed altro
Un po’ di fisica e di orbitali.
Basi di OOP e sue implementazioni in AmigaE (Parte 2)
Uniamo la grafica 3D a quella 2D.
Cosa Abbiamo Chiesto a VIScorp
Le richeste per le nuove macchine Amiga che vorremmo in futuro (testo in inglese)
Creare Fonts non è mai stato così divertente (e professionale)!
Amiga la Fenice
Amiga è stata acquistata di nuovo. Un nuovo passo, un nuovo capitolo che potrebbe demoralizzare ed anche ulteriormente demotivare tutti quelli che, con costanza e determinazione, hanno continuato a credere in questo computer ed hanno continuato a sviluppare software su questa piattaforma sempre più screditata.
Almeno fino ad oggi.
In un primo momento, anch’io mi sono sentito abbattuto e demoralizzato da questa notizia, giunta inaspettatamente, ma le informazioni acquisite successivamente, mi hanno convinto di una semplice cosa : Amiga risorgerà di nuovo. Come una fenice dalla cenere, Amiga tornerà al suo antico splendore. Personalmente, non sono mai rimasto impressionato dalla “potenza” e dalla “flessibilità” delle “macchine multimediali” di oggi : giochi come DOOM e cloni vari, saranno anche veloci, i nuovi processori Pentium avranno prestazioni eccezionali, ma quando si cerca di utilizzare professionalmente queste macchine, ci si scontra con un sistema operativo poco flessibile, obsoleto e pieno di errori anche molto gravi. Lavorare su macchine di questo tipo è frustrante e limitante, mentre con il mio Amiga 4000, che ha ormai più di tre anni sulle spalle, riesco ancora a fare meraviglie impensabili su PC.
Quando parlo di “risorgere”, intendo che Amiga tornerà ad essere un computer considerato, valutato ed acquistato dalle grandi masse, che troveranno nuovamente in questa macchina un ottimo rapporto qualità/prezzo e prestazioni da favola.
Come dice il presidente VISCorp, nei prossimi giorni sentirete malelingue e voci completamente sbagliate su Amiga e sulla sua situazione, ma non preoccupatevi : se Amiga è riuscita ad arrivare incolume fino a qui, rimanendo ancora oggi un computer più che valido per applicazioni professionali in tutti i campi, sicuramente riuscirà a superare anche questo momento. Alla VISCorp lavorano ex ingegneri Commodore, tra i quali il co-autore di Exec (il cuore del sistema operativo multitasking pre-emptive di Amiga) e di AmigaDOS. Già solo questo dovrebbe essere garanzia di sviluppo rapido e sicuro. Amiga risorgerà come la fenice. E quel momento non è più molto lontano. Cominciate a tenere da parte i soldi per acquistare i nuovi modelli : RISC e nuovi chip audio e grafici non sono più molto lontani.
L’Orgoglio Di Essere Tra I Più Grandi (Parte 3)
Le Classi Microsoft
Nell’articolo riservato alla comparazione dei vari sistemi operativi, oggi parleremo delle classi di oggetti di Microsoft per la creazione di programmi in Windows, chiamati MFC Microsoft Fundation Classes.
Cosa Sono Le Classi
Chi sta seguendo il nostro corso di Object Oriented Programming (OOP) nella sezione di articoli di Amiga E, sa già a grandi linee cosa sia una classe. Per chiarezza e precisione diremo che una classe è un Oggetto, un elemento chiuso e ben definito contenente i dati e le funzioni necessarie per eseguire determinate applicazioni. In questa sede non ci dilungheremo troppo a spiegare cosa sia una classe ed un oggetto, nè spiegeremo fondamenti di programmazione a oggetti, cosa per la quale vi rimandiamo alla sezione dedicata ad Amiga E a partire dal secondo numero della rivista.
Microsoft è stata costretta a creare delle classi di oggetti per Windows a causa della troppo elevata difficoltà di programmazione del sistema operativo. Per spiegarmi meglio, non c’è nessun programmatore su Windows che sia riuscito a fare qualcosa su questo sistema operativo senza dover passare per forza attraverso le classi di Microsoft.
Le classi, se ben progettate, possono essere un validissimo strumento per la creazione rapida e sicura di applicazioni. Il problema principale, per quanto riguarda le classi di Microsoft, è che queste non sono sicure… e la stessa Microsoft ce lo dimostra.
Che ci crediate o no, Word 6 alla sua chiusura, non libera l’ 8% delle risorse del sistema: le lascia semplicemente allocate e non saranno disponibili se non dopo essere usciti da Windows ed essere rientrati. Questo significa che, su di una macchina con poca RAM, sarà sufficiente aprire e chiudere Word per tre o quattro volte, per far apparire messaggi di sistema per la poca memoria disponibile. E Word è scritto da Microsoft. E Word è il programma di word processing più usato sotto Windows.
Ma il problema vero e proprio non risiede in Word, bensì nelle classi che esso usa, e che sono le classi che tutti i programmatori su Windows sono costretti ad usare. La classe per la gestione delle finestre, per esempio, non libera dai 512 ai 1024 bytes ogni volta che la finestra viene chiusa (praticamente anche quando spostate una finestra, rischiate di perdere 1K).
Questo problema delle classi, si verifica a causa della mancanza di validi strumenti di sviluppo per il programmatore. Su Amiga esistono tools come Enforcer e Mungwall che permettono di controllare, in ogni stadio dello sviluppo di un programma, il suo corretto funzionamento. Quando un programma passa “incolume” questi tools, vorrà dire che non nuocerà in alcun modo alla stabilità del sistema e che restituirà TUTTE le risorse che sono state allocate.
L’incompletezza e la trascuratezza con le quali sono state scritte le classi di Microsoft, lasciando esse stesse allocate delle risorse di sistema anche dopo la loro reale necessità, minano inevitablimente la qualità finale dei prodotti creati dagli sviluppatori sotto Windows, che si vedono danneggiati da delle colpe che, tutto sommato, non dovrebbero essere loro… e non possono farci nulla.
Benvenuti in Windows. E comprate un po’ più di RAM…
FILLED VECTORS (PARTE 2)
Nella scorsa puntata abbiamo visto come fuziona il doppio buffer, come ruotare punti tridimensionali su 3 assi e come effettuare lo zoom. In questo articolo vedremo l’uso dello z-sorting e come disegnare con il blitter.
Z-SORTING
Questa routine serve per dare una priorita’ di disegno alle facce; in qualunque modo il nostro oggetto sia ruotato verra’ disegnato sempre correttamente.
La rimozione delle superfici nascoste e’ basata su algoritmi ben precisi, non facili da implementare e raramente sono eseguibili alle velocita’ richieste da un demo o da un gioco. La rimozione delle superfici nascoste si divide in due fasi. La prima prevede la rimozione delle facce completamente nascoste (HIDDEN FACES). Le faccie nascoste sono chiamate cosi’ perche’ non possono essere viste dall’osservatore; per scovarle e’ sufficiente calcolare l’angolo formato dalla normale alla superficie e dal vettore della vista. Se questo angolo e’ compreso tra 90 gradi e -90 gradi, la faccia e’ visibile; se l’angolo e’ superiore a 90 gradi o inferiore a -90 gradi, la faccia e’ nascosta.
Per calcolare la normale alla superficie e’ sufficiente calcolare il prodotto incrociato di due suoi lati. Il vettore della vista si calcola congiungendo il punto di osservazione con il punto di cui si e’ calcolata la normale alla superficie.
Una volta eliminate le faccie completamente invisibili si dovra’ disegnare le faccie visibili in modo corretto. Per questo compito esistono due algoritmi: l’algoritmo del buffer Z e quello del pittore. Entrambi gli algorimti non possono essere inseriti in un demo in maniera standard, vediamo quindi una piccola descrizione ed una possibile implementazione.
L’algoritmo del buffer Z e’ cosi struttutturato:
- date le coordinate di una faccia, bisogna calcolare un valore Z per ogni
coordinata X e Y, memorizzare in un buffer in valore Z calcolato e il
colore della faccia - cercare il valore Z piu’ vicino all’osservatore, si confronta questo valore
con quello contenuto nel buffer Z (a parita’ di X e Y) e se piu’ vicino
all’osservatore si sovrascive al precedente; in caso contrario si salta
l’operazione. Ripetere l’operazione per tutti i pixel nello screen. - a questo punto per ogni coordinata X e Y abbiamo una coordianta Z (quella
piu’ vicina all’osservatore) ed un colore (quello del pixel), sara’
sufficiente disegnarlo
L’algoritmo del pittore e’ basato su una serie di controlli:
1- le estensioni lungo l’asse X di due facce si sovrappongono ?
se no -> fine controlli, la priorita’ di disegno non conta
se si -> controllo 2
2- le estensioni lungo l’asse X di due facce si sovrappongono ?
se no -> fine controlli
se si -> controllo 3
3e4 – estendete un poligono all’infinito e avrete un piano: l’altro poligono
si trova interamente da una sola parte (non importa quale) ?
se si -> fine controlli
se no -> controllo 5
5- ora sappiamo che le faccie sono in posizione scorretta; sara’ necessario
invertire l’ordine di disegno di queste due faccie.
Data la quantita’ di calcoli e visto che i nostri amati Amiga non hanno ancora un PowerPC 604 a 200MHz, sconsiglio a chiunque di usare tali algoritmi mentre consiglio di dare un’occhiata a quello che presento io.
Quello che segue non e’ un mio algoritmo ma solo l’algoritmo del buffer Z modificato in modo che sia il piu’ veloce possibile.
Possiamo dividere la routine in due parti. La prima prende tutti i punti che compongono una determinata faccia, somma tutte le Z e divide il risultato per il numero di punti (Z media dei punti che conpongono la faccia).
La seconda riordina le faccia in modo che quelle piu’ lontane dall’osservatore siano visualizzate per prime. In questo modo se un oggetto in primo piano ne oscura un altro, non avremo problemi di nessun genere; vedremo il nostro oggetto in primo piano e in lontananza tutto il resto (magari un paesaggio).
Immaginate un caso in cui non fosse presente questa routine: le faccie sarebbero disegnate sempre nello stesso ordine (imposto da noi!). Immaginiamo ora un bosco pieno di alberi; l’albero in primo piano deve coprire gli alberi piu’ lontani (quindi deve essere disegnato per ultimo!). Se impostassimo questo ordine di disegno gia’ dalla partenza tutto funzionerebbe solo fino a quando non ruotiamo il nostro bosco. Dato che l’ordine di disegno non cambia, avremo la sequenza di disegno delle faccie uguale a prima; nel caso ipotetico in cui ci troviamo dalla parte opposta del bosco e guardiamo il punto da cui siamo partiti (Y=180 gradi), sempre con il medesimo ordine di disegno: cosa accadra’? Innanzitutto verrebbero disegnati gli alberi piu’ lontani (essendo tutto ruotato di 180 gradi, quelli piu’ vicini a noi!!!) e per ultimi i piu’ vicini (quelli piu’ lontano da noi!!!). La schermata risultante potrebbe essere la seguente: alberi in primo piano coperti parzialmente (per le dimensioni, piu’ sono lontano e piu’ sono piccoli) da alberi in lontananza. Come vedete non quadra nulla. Questo e’ sono un piccolo esempio delle potenzialita’ del riordinamento in base al buffer Z.
Attenzione : non sempre e’ necessario.
Esistono molti casi in cui si puo’ eliminare il riordinamento in base al buffer Z, risparmiando parecchio tempo macchima: in questi casi l’ordine di disegno delle faccie e’ irrilevante. Abbiamo detto che si puo’ evitare il riordinamento su alcuni oggetti: innanzitutto devono essere CHIUSI e in secondo luogo devono essere semplici. Facciamo un esempio con una sfera: prima di tutto le faccie nascoste non verranno mai disegnate (importante!!!) e successivamente non avra’ nessuna importanza l’ordine di disegno (in tutti i casi possibili le faccie non si sovrapporranno mai). Gli oggetti devono essere chiusi: se un lato fosse aperto, si renderebbe necessario disegnare anche le faccie nascoste, di conseguenza essendoci le faccie in primo piano che coprono quelle dietro, si renderebbe necessario lo Z-buffer. Infine devono essere semplici in quanto se disegnassimo 2 sfere anziche’ 1, non possiamo permetterci che le faccie siano disegnate a caso.
parte 1 *
CalcPoints:
; media delle Z di tutte le facce
move.l Dlines,a0 ; come unire le faccie
move.l dplane,a1 ; numero punti per faccia, colore
lea Intz(pc),a2 ; valore di Z di tutti i punti
lea BufferFace(pc),a3 ; buffer vuoto
move.w dface,d6 ; numero faccie
moveq #0,d0
moveq #0,d1
LpLps: move.w (a1),d0 ; numero punti che formano faccia
add.w #4,a1
move.w d0,d1 ; d1 = d0
subq.w #1,d0 ; d0 = -1 per dbf
moveq #0,d3
SomaLp: move.w (a0),d2 ; numero punto
add.w #4,a0
add.w d2,d2 ; * 2 perche’ word
add.w (a2,d2.w),d3 ; coordinata Z
dbf d0,SomaLp
ext.l d3
divs.w d1,d3 ; numero punti / somma delle Z
move.w d3,(a3)+ ; salva media
dbf d6,LpLpsparte 2 *
; calcola la Z ma delle facce (non punti)
lea BufferFace(pc),a0 ; media Z di tutte le faccie
lea FacceSeq(pc),a1 ; buffer vuoto
movea.l a0,a2
move.w dface,d4 ; numero faccie
move.w d4,d5 ; numero faccie
move.w d5,d6 ; numero faccie
subq.w #1,d6 ; numero faccia -1 per dbf
move.w d6,d7 ; numero faccie -1 per dbf
add.w d5,d5 ; numero faccie *2
addq.w #2,d5 ; +2 perche’ -(a1) prima decremento
; poi inserimento valore in a1
add.w d5,a1 ; ultimo valore
move.w #$9999,d5 ; $9999 = -26215 valore Z piccolissimo
Calcs: move.w d7,d6 ; numero faccie -1 per dbf
moveq #2,d2 ; prima faccia da inserire (1)(2=WORD)
moveq #0,d3 , faccia di partenza (0)
move.w (a0)+,d0 ; valore Z
Calc: move.w (a0)+,d1 ; valore Z 2
cmp.w d0,d1 ; se Z2 piu’ piccolo di Z1
blt.s NoEx ; salta NoEx
move.w d1,d0 ; valore Z piu’ grande di prima
move.w d2,d3 ; numero faccia con Z grande
NoEx: addq.w #2,d2 ; numero faccia +2 (word)
dbf d6,Calc
move.w d3,-(a1) ; numero faccia da disegnare
movea.l a2,a0
move.w d5,(a0,d3.w) ; valore Z piccolissimo
dbf d4,Calcs
rts
DISEGNO DELL’OGGETTO
Gli indirizzi assoluti intermedi tra $100 e $200 non devono mai essere usati !! Sono stati usati da me in questa vecchia routine perche’ quando l’ho scritta (1990) avevo un Amiga 500 e, su A500 – A2000 e A3000 questi indirizzi erano sempre vuoti e quindi usabili come accesso a word anziche a long (piu’ veloce). Ora con gli Amiga AGA, questi indirizzi sono usati, pena un possibile malfunzionamento del sistema all’uscita del demo.
Data la quantita’ di tempo passata (circa 6 anni), non ricordo esattamente come funzionano tutte le routine, cerchero’ di spiegarle come meglio posso.
Display:
clr.w $120.w
clr.w $122.w
clr.w $124.w
move.l #0,a1
move.w ScrClrNow,a1
move.w #0,(a1)+ ; cancella $150
move.w #$7fff,(a1)+ ; max. valore in $152
move.w #0,(a1)+ ; cancella $154
move.w #$7fff,(a1)+ ; max. valore in $156
move.l Dlines,a6** questa e’ la ruotine principale, viene eseguita 1 volta per ogni faccia
lea $dff000,a6 move.l Bm2_PL1,d1 move.w dpunti,d6 ; numero punti lea UltimateFace(pc),a1 ; buffer vuoto per mettere il numero ; corrispondente alle faccie che ; saranno disegnate per ultime lea IntY1(pc),a2 ; Y lea IntX1(pc),a3 ; X lea FacceSeq(pc),a0 ; sequenza delle faccie moveq #0,d5 move.w dface,d5Face:
move.l dplane,a5
move.l Dlines,a4
move.w (a0)+,d0
lsr.w #1,d0
subq.w #1,d0
moveq #0,d3
moveq #0,d4
cmp.w #-1,d0
beq EAddr
Addr: add.w (a5),d3
add.w #4,a5
addq #1,d4
dbf d0,Addr
EAddr: add.w d3,d3
add.w d3,d3
add.w d4,d4
move.w d4,$130.w
bsr Againdopo
dbf d5,Face
tst.w $120.w
bne HoHo
rts** questa routine viene eseguita solo se sono presenti alcune faccie che devono
** essere disegnate per ultime. La ruotine viene eseguita per ultima.HoHo: move.w #1,$122.w
move.w $124.w,d5
subq #1,d5
lea UltimateFace(pc),a1
Face2: move.l dplane,a5
move.l Dlines,a4
move.w (a1)+,d0
lsr.w #1,d0
subq.w #1,d0
moveq #0,d3
moveq #0,d4
cmp.w #-1,d0
beq EAddr2
Addr2: add.w (a5),d3
add.w #4,a5
addq #1,d4
dbf d0,Addr2
EAddr2: add.w d3,d3
add.w d3,d3
add.w d4,d4
move.w d4,$130.w
bsr Againdopo
dbf d5,Face2
rtsagaindopo: ; calcola il punto di partenza per i dati in Lines2
movem.l a0-a3/d5,-(sp)
clr.w Out
lea BufferLine(pc),a1
add.w d3,a4
move.w d3,$104.w
move.w 2(a5),$106.w
move.w (a5),d6
move.w d6,$10e.w
subq.w #1,d6; Mette in BufferLine le coordinate X,Y di tutti i punti che compongono
; una faccia im modo da averli tutti in sequenzaDlpLop: movem.w (a4)+,d2/d3
add.w d2,d2
add.w d3,d3
move.w (a3,d2.w),(a1)+ ; x1
move.w (a2,d2.w),(a1)+ ; y1
move.w (a3,d3.w),(a1)+ ; x2
move.w (a2,d3.w),(a1)+ ; y2
dbf d6,DlpLop; controlla se in Priority c’e’ 0 o 1
; se 1 la faccia e’ disegnata per ultimamove.l DPriority,a1 move.w $130.w,d2 move.w (a1,d2.w),d2 cmp.w #1,d2 ; disegna tutto beq Dloop2 tst.w $122.w ; se deve disegnare bne Saltoo ; le faccia davanti cmp.w #2,d2 ; ultime le facce davanti beq Ultima; calcola se e’ una linea
Saltoo: cmp.w #1,$10e.w ; disegna solo 1 linea
beq OnlyLine; calcola se la faccia e nascosta (YEAAA!!!)
lea BufferLine(pc),a1
movem.w (a1),d0-d3 ; d0=x0 d1=y0 d2=x1 d3=y1 d4=x2 d5=y2
movem.w 12(a1),d4-d5
sub.w d0,d2 ;
sub.w d0,d4 ;
sub.w d1,d3 ; prodotto incrociato di 2 lati adiacenti
sub.w d1,d5 ;
muls.w d2,d5 ;
muls.w d3,d4 ;** in base a cui e’ disegnato esegue: BLT (less than) oppure BGT (great than)
tst.w $132.w bne.s blts sub.l d4,d5 bgt.s dloop2 lea $dff000,a6 bra NoFace ; faccia nascosta !blts: sub.l d4,d5
blt.s dloop2
lea $dff000,a6
bra NoFace ; faccia nascosta !** la faccia e’ visibile !!! Disegnala ora !
Dloop2: ; ora si hanno tutti i punti della faccia in BufferLine
bsr CalcScr ; calcola X e Y nello schermo per clipping
bsr.l CalcPoits ; calcola Xmax,Ymax,Xmin,Ymin
bsr.l TCalcAll ; Calcola Xmax,Ymax,Xmin,Ymin di tutto
bsr.L CalcArea ; calcola size,mod.,….
bsr.l Lineeee ; disegna linee
bsr.l Fillare ; filla tra le linee
bsr.l Copyarea ; calcola disegno
lea -$58(a6),a6 ; a6 = $dff000
bsr.l Clerorno ; cancello buffer dove ho disegnato
NoFace: move.w #$400,$96(a6)
movem.l (sp)+,a0-a3/d5
rts
Ultima:
movem.l (sp)+,a0-a3/d5
move.w -2(a0),(a1)+
move.w #1,$120.w
add.w #1,$124.w
rts*** calcola il clipping per lo screen ( max size = 320*256 )
CalcScr:
move.w $10e,d6
add.w d6,d6
subq.w #1,d6
lea BufferLine(pc),a0
lea BufferLine2(pc),a1
Clip: movem.w (a0)+,d0-d1
cmp.w #0,d0
bge.s Ok0
move.w #0,(a1)+
move.w #1,Out
bra.s Di1
Ok0: cmp.w #320,d0
ble.s Ok2
move.w #320,(a1)+
bra.s Di1
Ok2: move.w d0,(a1)+
Di1: cmp.w #0,d1
bge.s Ok3
move.w #0,(a1)+
bra.s Di2
Ok3: cmp.w #256,d1
ble.s Ok4
move.w #256,(a1)+
bra.s Di2
Ok4: move.w d1,(a1)+
Di2: dbf d6,Clip
rts*** calcola Xmax, Xmin, Ymax, Ymin di tutto l’oggetto, serve per sapere la
*** dimensione da cancellare (inutile cancellare tutto)
TCalcAll:
lea $140.w,a2
move.w ScrClrNow,a3
moveq #0,d3
move.w (a2)+,d3
cmp.w (a3)+,d3
blt TCalcPoits2
move.w d3,-2(a3)
TCalcPoits2:
move.w (a2)+,d3
cmp.w (a3)+,d3
bgt TCalcPoits3
move.w d3,-2(a3)
TCalcPoits3:
move.w (a2)+,d3
cmp.w (a3)+,d3
blt TCalcPoits4
move.w d3,-2(a3)
TCalcPoits4:
move.w (a2)+,d3
cmp.w (a3)+,d3
bgt TCalcPoits5
move.w d3,-2(a3)
TCalcPoits5:
rts*** calcola la SIZE del blitter e i suoi moduli
CalcArea:
; calcola size
lea Dax(pc),a3
movem.w $140.w,d0-d3
sub.w d3,d2 ; x
sub.w d1,d0 ; y
lsr.w #4,d2
addq #2,d2 ; world size
move.w d2,$100.w
lsr.w #2,d0
addq #1,d0 ; hight screen
lsl.l #8,d0 ; muls #$100,d0
add.w d2,d0 ; size $dff058
move.w d0,18(a3)
; Calcola screen
move.l Fill,a1
move.l Bm2_pl1,a2
; calcola zona di memoria da copiare (metodo: Discendente)
move.w $140.w,d1
move.w d1,d3
muls #$2c,d3
muls #$78,d1
move.w $144.w,d2
lsr.w #3,d2
add.w d2,d1
add.w d2,d3
add.w d3,a1
add.l d1,a2
move.l a1,(a3)
move.l a2,4(a3)
move.l a2,8(a3)
; calcola moduli (metodo discendente)
moveq #0,d1
move.w $100.w,d1 ; num. world da copiare
add.w d1,d1 ; in byte
moveq #44,d2 ; 40 byte in 320 pixel
sub.w d1,d2 ; modulo a
move.w #$78,d3 ; $78 byte
sub.w d1,d3 ; modulo d
move.w d2,12(a3)
move.w d3,14(a3)
move.w d3,16(a3)
rts*** Copia l’area creata e la mette nei plane corrispondenti
Copyarea: ; funzione d=a+c
lea $dff000,a6
move.w #$8400,$96(a6)
lea Jump(pc),a1
lea Dax(pc),a3
move.w $106.w,d1
add.w d1,d1
move.w d1,d2
add.w d2,d2
add.w d2,d1
add.w d1,a1
moveq #0,d0
move.w 18(a3),d0 ; size $dff058
moveq #$28,d1
moveq #0,d2
move.l 4(a3),d2 ; $dff048 – $dff054
moveq #0,d3
move.l (a3),d3 ; $dff050
move.l #AddGriglia+[$2c*256]-2,d4
lea $40(a6),a2
lea $54(a6),a4
lea $48(a6),a5
move.l #$0b0a0002,d5
move.l #$0bfa0002,d6
move.l #$0fca0002,d7
Altola: btst #6,2(a6)
bne Altola
move.w 12(a3),$64(a6)
move.w 12(a3),$62(a6)
move.w 14(a3),$66(a6)
move.w 16(a3),$60(a6)
lea $50(a6),a3
lea $58(a6),a6
jmp (a1)
In base al bitplane in cui deve andare, la routine salta in ordine qui’ sotto. Questo perche’ se la faccia deve essere disegnata con il colore 1 si avra’ il bitplane 1 con il disegno della faccia e tutti gli altri vuoti.Nel caso di un altro colore:
______ plane 4 | _____ plane 3 || ____ plane 2 ||| ___ plane 1 ||||0 -> %0000 non usato
1 -> %0001 plane 1 pieno, 2-3-4 vuoti
2 -> %0010 plane 2 pieno, 1-3-4 vuoti
3 -> %0011 plane 1-2 pieni, 3-4 vuoti
4 -> %0100 plane 3 pieno, 1-2-4 vuoti
. -> %….
In base al colore usato sara’ necessario copiare o cancellare l’aria interessata. Per la copia e’ sufficiente sommare lo screen con la faccia in questione. Per cio’ che riguarda la cancellazione bisogna effettuare una moltiplicatione della faccia NEGATA per lo screen destinazione.In base al colore da noi assegnato sara’ eseguita UNA SOLA delle routine che seguono.
Jump: jmp zeros
jmp unos
jmp dues
jmp tres
jmp quattros
jmp cinques
jmp seis
jmp settes
jmp ottos
jmp noves
jmp diecis
jmp undicis
jmp dodicis
jmp tredicis
zeros:
bsr disegnare ; disegna plane 0
add.w d1,d2
bsr cancellare ; cancella plane 1
add.w d1,d2
bsr cancellare ; cancella plane 2
rts
unos:
bsr cancellare ; disegna plane 0
add.w d1,d2
bsr disegnare ; disegna plane 1
add.w d1,d2
bsr cancellare ; cancella plane 2
rts
dues:
bsr cancellare ; cancella plane 0
add.w d1,d2
bsr cancellare ; cancella plane 1
add.w d1,d2
bsr disegnare ; disegna plane 2
rts
tres:
bsr disegnare
add.w d1,d2
bsr disegnare
add.w d1,d2
bsr cancellare
rts
quattros:
bsr disegnare
add.w d1,d2
bsr cancellare
add.w d1,d2
bsr disegnare
rts
cinques:
bsr cancellare
add.w d1,d2
bsr disegnare
add.w d1,d2
bsr disegnare
rts
seis:
bsr disegnare
add.w d1,d2
bsr disegnare
add.w d1,d2
bsr disegnare
rts
settes:
bsr griglia
add.w d1,d2
bsr cancellare
add.w d1,d2
bsr cancellare
rts
ottos:
bsr cancellare
add.w d1,d2
bsr griglia
add.w d1,d2
bsr cancellare
rts
noves:
bsr cancellare
add.w d1,d2
bsr cancellare
add.w d1,d2
bsr griglia
rts
diecis:
bsr griglia
add.w d1,d2
bsr griglia
add.w d1,d2
bsr cancellare
rts
undicis:
bsr griglia
add.w d1,d2
bsr cancellare
add.w d1,d2
bsr griglia
rts
dodicis:
bsr cancellare
add.w d1,d2
bsr griglia
add.w d1,d2
bsr griglia
rts
tredicis:
bsr griglia
add.w d1,d2
bsr griglia
add.w d1,d2
bsr griglia
rtscancellare: ; funzione D=A(neg)*C per cancellare
btst #6,-$56(a6)
bne cancellare
move.l d5,(a2)
move.l d3,(a3)
move.l d2,(a4)
move.l d2,(a5)
move.w d0,(a6)
rtsdisegnare:
btst #6,-$56(a6)
bne disegnare
move.l d6,(a2)
move.l d3,(a3)
move.l d2,(a4)
move.l d2,(a5)
move.w d0,(a6)
rtsGriglia:
btst #6,-$56(a6)
bne griglia
move.l d7,(a2) ; funzione D=A(neg)C+AB
move.l d4,-$c(a6)
move.l d3,(a3)
move.l d2,(a4)
move.l d2,(a5)
move.w d0,(a6)
rts** Questa routine cancella la zona usata precedentemente come buffer in cui
** e’ stata creata la faccia.Clerorno: ; zona da cancellare per disegnare linee
btst #6,$2(a6)
bne Clerorno
lea Dax(pc),a3
move.l #$01000002,$40(a6)
move.w 12(a3),$66(a6)
move.l (a3),$54(a6)
move.w 18(a3),$58(a6)
rts** Dopo aver tracciato tutte le linee che compongono la faccia e’ necessario
** fillarle con il blitter (usando il metodo DISCENDENTE.
** Il metodo discendente funziona in modo contrario a tutti gli altri.
** Il blitter riempira’ la zona assegnata partendo dal basso a sinistra e
** finendo in alto a destra.Fillare:
lea Dax(pc),a3
tst.w out
beq doppld
move.w 12(a3),d0
addq.w #2,d0
move.w 18(a3),d1
subq.w #1,d1
bra.s FillWait
doppld:
move.w 12(a3),d0
move.w 18(a3),d1
FillWait: ; zona da fillare per riempire linee
btst #6,$2(a6)
bne FillWait
move.l #$09f00012,$40(a6)
move.w d0,$64(a6)
move.w d0,$66(a6)
move.l (a3),$50(a6)
move.l (a3),$54(a6)
move.w d1,$58(a6)
rts** Questa routine disegna SOLO UNA LINEA con il blitter, verra’ disegnata
** direttamente sullo screen senza passare da nessun buffer.Onlyline:
bsr CalcScr ; calcola le X e Y nello schermo
lea BufferLine(pc),a1
lea jump2(pc),a2
move.l BM2_PL1,a0
move.l BM2_PL1,a3
lea $dff000,a6
move.w $106.w,d1
add.w d1,d1
move.w d1,d2
add.w d2,d2
add.w d2,d1
add.w d1,a2
jmp (a2)** Il JMP funziona nelle stesso modo descritto sopra, serve per assegnare il
** colore alla linea.Jump2: jmp linep0
jmp linep1
jmp linep2
jmp linep3
jmp linep4
jmp linep5
jmp linep6Linep0: move.l #$ffff8000,d7 ; metodo TEXTURE = tutto pieno
bsr Line00
move.l #$00008000,d7 ; metodo TEXTURE = vuoto = cancella linea
add.w #$28,a3
bsr Line00
add.w #$28,a3
bsr Line00
bra CalcMax
Linep1: move.l #$00008000,d7
bsr Line00
move.l #$ffff8000,d7
add.w #$28,a3
bsr Line00
move.l #$00008000,d7
add.w #$28,a3
bsr Line00
bra CalcMax
Linep2: move.l #$00008000,d7
bsr Line00
add.w #$28,a3
bsr Line00
move.l #$ffff8000,d7
add.w #$28,a3
bsr Line00
bra CalcMax
Linep3: move.l #$ffff8000,d7
bsr Line00
add.w #$28,a3
bsr Line00
add.w #$28,a3
move.l #$00008000,d7
bsr Line00
bra CalcMax
Linep4: move.l #$ffff8000,d7
bsr Line00
move.l #$00008000,d7
add.w #$28,a3
bsr Line00
move.l #$ffff8000,d7
add.w #$28,a3
bsr Line00
bra CalcMax
Linep5: move.l #$00008000,d7
bsr Line00
move.l #$ffff8000,d7
add.w #$28,a3
bsr Line00
add.w #$28,a3
bsr Line00
bra CalcMax
Linep6: move.l #$ffff8000,d7
bsr Line00
add.w #$28,a3
bsr Line00
add.w #$28,a3
bsr Line00
bra CalcMax** Questa routine traccia le linee usando il blitter
Line00:
movem.w (a1),d0-d3 ; coordinate x0,y0,x1,y1QUI DEVE ESSERE INSERITA LA ROUTINE DI CLIPPING
Line:
cmp.w d1,d3
bne encode
rts
encode:
move.l a3,a0
move.w #$78,d4
sub.w d0,d2
bpl.s Oct1278
neg.w d2
sub.w d1,d3
bpl.s Oct34
neg.w d3
cmp.w d2,d3
bpl.s Oct6
moveq.l #28+1,d5
bra.s Lline
Oct6: exg d2,d3
moveq.l #12+1,d5
bra.s Lline
Oct34: cmp.w d2,d3
bpl.s Oct3
moveq.l #20+1,d5
bra.s Lline
Oct3: exg d2,d3
moveq.l #8+1,d5
bra.s Lline
Oct1278:sub.w d1,d3
bpl.s Oct12
neg.w d3
cmp.w d2,d3
bpl.s Oct7
moveq.l #24+1,d5
bra.s Lline
Oct7: exg d2,d3
moveq.l #4+1,d5
bra.s Lline
Oct12: cmp.w d2,d3
bpl.s Oct2
moveq.l #16+1,d5
bra.s Lline
Oct2: exg d2,d3
moveq.l #0+1,d5
Lline: mulu.w d4,d1
ror.l #4,d0
add.w d0,d0
add.l d1,a0
add.w d0,a0
swap d0
or.w #$bca,d0
add.w d3,d3
add.w d3,d3
add.w d2,d2
move.w d2,d1
lsl.w #5,d1
add.w #$42,d1
swap d5
move.w d0,d5
swap d5
move.w d3,d0
sub.w d2,d0
bpl waitb1
bset #6,d5
waitb1: move.w d0,d6
sub.w d2,d6
Drawl2: btst #6,2(a6)
bne.s Drawl2
move.w d3,$62(a6)
move.l d0,$50(a6)
move.l d5,$40(a6)
move.w d4,$60(a6)
move.w d4,$66(a6)
move.w d6,$64(a6)
move.l #-1,$44(a6)
move.l d7,$72(a6)
move.l a0,$48(a6)
move.l a0,$54(a6)
move.w d1,$58(a6)
rts** Qui vengono calcolati i valori Xmax,Xmin,Ymax,Ymin per ogli linea
CalcMax: ; calcola
lea BufferLine2(pc),a1
lea $140.w,a2
moveq #0,d0
moveq #0,d1
moveq #0,d2
moveq #0,d3
movem.w (a1),d0-d3
cmp.w d0,d2
ble.s Less
move.w d0,6(a2)
move.w d2,4(a2)
bra.s Great
Less: move.w d0,4(a2)
move.w d2,6(a2)
Great: cmp.w d1,d3
ble.s Less2
move.w d1,2(a2)
move.w d3,(a2)
bra.s Great2
Less2: move.w d1,(a2)
move.w d3,2(a2)
Great2: bsr TCalcAll
bra NoFaceCalcPoits: ; Calcola Xmax,Xmin,Ymax,Ymin
lea BufferLine2+2(pc),a2
move.w $10e.w,d6
add.w d6,d6
subq.w #1,d6
move.w d6,d7
moveq #0,d1
move.w (a2),d2
moveq #0,d3
CalcPoits4:
move.w (a2),d1
cmp.w d1,d3
bgt.s CalcPoits2
move.w d1,d3
addq #4,a2
dbf d6,CalcPoits4
bra.s CalcPoitsend
CalcPoits2:
cmp.w d1,d2
blt.s CalcPoits3
move.w d1,d2
CalcPoits3:
addq #4,a2
dbf d6,CalcPoits4
CalcPoitsend:
move.w d3,$140.w
move.w d2,$142.w
lea BufferLine2(pc),a2
moveq #0,d0
moveq #0,d1
move.w (a2),d2
moveq #0,d3
move.w d7,d6
CalcPoit5:
move.w (a2),d1
cmp.w d1,d3
bgt.s CalcPoit6
move.w d1,d3
addq #4,a2
dbf d6,CalcPoit5
move.w d3,$144.w
move.w d2,$146.w
rts
CalcPoit6:
cmp.w d1,d2
blt.s CalcPoit7
move.w d1,d2
CalcPoit7:
addq #4,a2
dbf d6,CalcPoit5
move.w d3,$144.w
move.w d2,$146.w
rts*** Questa ruotine disegna tutte le linee nel buffer
Lineeee:
lea BufferLine(pc),a5 ; sequanza delle linee da disegnare
move.w $10e.w,d6
subq.w #1,d6
Linene: movem.w (a5)+,d0-d3
bsr.s SWline
dbf d6,Linene
rts** Qui deve essere inserita la routine di CLIPPING
SWLine:
move.l Fill,a0
lea $dff000,a6
cmp.w d1,d3
bne.s Sencode ; linea orizzontale
rts
Sencode:bmi.s SLine0A
exg.l d0,d2
exg.l d1,d3
SLine0A:addq.w #1,d3
clr.w d4
sub.w d1,d3
bge.s SLine16
neg.w d3
bra.s SLine1A
SLine16:or.w #1,d4
SLine1A:sub.w d0,d2
bge.s SLine22
neg.w d2
bra.s SLine26
SLine22:or.w #2,d4
SLine26:cmp.w d3,d2
bge.s SLine2E
exg.l d2,d3
bra.s SLine32
SLine2E:or.w #4,d4
SLine32:clr.w d5
ror.w #4,d0
or.w #$B00,d0
move.b d0,d5
move.b #$5A,d0
add.w d5,d5
mulu.w #$2c,d1
and.w #$FFFF,d1
add.w d5,d1
add.l a0,d1
move.b oct(pc,d4.w),d4
add.l d3,d3
SLine5C:btst #6,2(a6)
bne.s SLine5C
move.w d3,$62(a6)
sub.w d2,d3
bge.s SLine70
or.b #$40,d4
SLine70:
move.l d3,$50(a6)
sub.w d2,d3
move.l #$ffff8000,$72(a6)
moveq #-1,d5
move.l d5,$44(a6)
moveq #44,d5
move.w d5,$60(a6)
move.w d5,$66(a6)
move.w d3,$64(a6)
move.w d4,$42(a6)
move.w d0,$40(a6)
move.l d1,$48(a6)
move.l d1,$54(a6)
lsl.w #6,d2
add.w #$42,d2
move.w d2,$58(a6)
rts; octant codes
oct: dc.b $0f,$0b,$07,$03,$1f,$17,$1b,$13
Chi ha controllato il sorgente avra’ sicuramente notato che la routine di CLIPPING non e’ presente. Questo solo perche’ ho cercato di facilitare i meno esperti, tralasciando le routine piu’ conplesse. Non vi preoccupate!!! Troverete tale routine nel prossimo articolo con una spiegazione dettagliata sul funzionamento. Dato che il clipping serve per eliminare la parte del disegno al di fuori dello screen, avrete (solo per questo mese) una sola limitazione; infatti non dovete per nessun motivo far uscire gli oggetti dalle coordinate dello screen. In effetti, sarebbe possibile farli uscire verso l’alto o verso il basso, solo se la memoria sopra o sotto il buffer di disegno, e’ MEMORIA PULITA, infatti gli oggetti verranno disegnati in questa zona di memoria.Esaminiamo ora le parti di sorgente restanti.
jmp START org $130000 load $130000START:
…………….
Questi comandi servono per rendere il codice NON RILOCABILE, ovvero sara’ necessario che la ruotine sia caricata sempre a partire dall’indirizzo $130000.
lea $150000,a0Clear: clr.l (a0)+
cmp.l #$180000,a0
bne clear
lea $100.w,a0
dsf: clr.b (a0)+
cmp.l #$200,a0
bne dsfIl loop sopra serve per cancellare la memoria tra gli indirizzi :
$150000 e $180000 e tra $100 e $200.
lea SphLines(pc),a0 lea Plane9(pc),a1addiaz: add.w #96,(a0)+
cmp.l a0,a1
bne addiaz
Non serve a nulla!!! Serve solo per sommare il valore 96 alla sfera presente nel satellite; i due oggetti erano stati creati separatemente ed ora unendoli e’ necessario sommare questo valore alla sfera, atrementi si avrebbero piu’ poligoni con gli stessi valori (numero di poligono uguale).
lea AddGriglia,a0 move.w #$80,d1 ; 1/2 heightgri1: moveq #10,d0 ; num. screen in long
gri2: move.l #$55555555,(a0)+
move.l #$aaaaaaaa,$28(a0) ; $28=modulo-$4[1 long]
dbra d0,gri2
add.l #$2c,a0 ; modulo
dbra d1,gri1** Crea una griglia per usare l’effetto dithering, la mette in AddGriglia
move.w #npoints2-1,dpunti move.w #nface2-1,dface move.l #wx2,dx move.l #wy2,dy move.l #wz2,dz move.l #lines2,dlines move.l #plane2,dplane move.l #Priotity2,Dpriority move.w #1,$132.w ; 1 se blt.s ; 0 se bgt.s** Le coordinate delle faccie sono messe nelle variabili : dpunti,dface,dx,dy,
** dz,dlines,dplane,Dpriority. Questo per facilitare il cambiamento di
** oggetto durante l’eseguzione del demo.
Inter:
btst #5,$dff01f
beq.w Int
move.w #$20,$dff09c
add.w #4,ZANGLE
add.w #2,YANGLE
add.w #4,XANGLE
move.w #1,IntOk
Int: rte
IntOk: dc.w 0** Routine in INTERRUPT $6c. Questo perche’ il nostro oggetto girera’ sempre
** alla medesima velocita’, anche se cio’ comporta piu’ o meno fluidita’ di
** muovimanto.
COME DISEGNARE GLI OGGETTI
Dpunti: dc.w 0 ; numero punti
Dface: dc.w 0 ; numero faccie
DX: dc.l 0 ; coords X
DY: dc.l 0 ; coords Y
DZ: dc.l 0 ; coords Z
Dlines: dc.l 0 ; come unire le linee
Dplane: dc.l 0 ; come colorare l’oggetto
Dpriority: dc.l 0 ; come disegnare l’oggetto (vedi dopo!)
- ATTENZIONE: le 3 variabili sotto sono per l’oggetto + grande. Dato che la
- routine deve gestire diversi oggetti, e’ bene definire qui’ le dimensioni
- del piu’ grande.
Blkpoints=200 ; num.punti
BlkLine=26 ; la faccia che ha piu’ linee ne ha ?
Blkface=200 ; num.facce; cubo con scritte
NPOINTS=76 ; numero punti
Nface=12 ; numero faccie
Wx:
dc.w -120,120,120,-120,-120,120,120,-120
dc.w -100,100,100,35,35,-35,-35,-100
dc.w 120,120,120,120,120,120,120,120,120,120,120,120
dc.w 100,-20,-100,-100,-20,100,45,5,-45,-45,5,45
dc.w -120,-120,-120,-120,-120,-120,-120,-120,-120,-120,-120,-120,-120,-120
dc.w -120,-120,-120,-120,-120,-120,-120,-120,-120,-120,-120,-120
dc.w 0,-80,100,-100,80
dc.w 0,-80,100,-100,80
Wy:
dc.w 120,120,-120,-120,120,120,-120,-120
dc.w 100,100,40,40,-100,-100,40,40
dc.w 100,100,60,60,20,20,-20,-20,-60,-60,-100,-100
dc.w 100,100,40,-40,-100,-100,45,45,10,-10,-45,-45
dc.w 60,60,40,40,-40,-40,-20,-20,0,0,-20,-20,-60,-60
dc.w 60,60,40,40,10,10,-60,-60,-40,-40,-10,-10
dc.w 120,120,120,120,120
dc.w -120,-120,-120,-120,-120
Wz:
dc.w 120,120,120,120,-120,-120,-120,-120
dc.w 120,120,120,120,120,120,120,120
dc.w 100,-100,-100,40,40,-40,-40,40,40,-100,-100,100
dc.w -120,-120,-120,-120,-120,-120,-120,-120,-120,-120,-120,-120
dc.w -100,-20,-20,-80,-80,-40,-40,-50,-50,-10,-10,-20,-20,-100
dc.w 10,100,100,30,30,100,100,10,10,80,80,10
dc.w 100,-100,20,20,-100
dc.w 100,-100,20,20,-100
Lines:
dc.w 0,1,1,2,2,3,3,0
dc.w 5,4,4,7,7,6,6,5
dc.w 1,5,5,6,6,2,2,1
dc.w 4,0,0,3,3,7,7,4
dc.w 4,5,5,1,1,0,0,4
dc.w 3,2,2,6,6,7,7,3
dc.w 8,9,9,10,10,11,11,12,12,13,13,14,14,15,15,8
dc.w 16,17,17,18,18,19,19,20,20,21,21,22,22,23,23,24,24,25,25,26,26,27,27,16
dc.w 28,29,29,30,30,31,31,32,32,33,33,28,34,35,35,36,36,37,37,38,38,39,39,34
dc.w 40,41,41,42,42,43,43,44,44,45,45,46,46,47,47,48,48,49,49,50,50,51,51,52,52,53,53,40
dc.w 54,55,55,56,56,57,57,58,58,59,59,60,60,61,61,62,62,63,63,64,64,65,65,54
dc.w 66,67,67,68,68,69,69,70,70,66
dc.w 75,74,74,73,73,72,72,71,71,75
Plane:
dc.w 4,0,4,0,4,1,4,1,4,2,4,2,8,3,12,4,12,6,26,5,5,5,5,1
Priotity: ; 0 se le calcola ; 1 se le disegna sempre ; 2 se ultima
dc.w 0,0,0,0,0,0,2,2,2,2,2,2
Per disegnare un oggetto e’ necessario :
- mettere le coordinate X dei punti nella variabile Wx
- mettere le coordinate Y dei punti nella variabile Wy
- mettere le coordinate Z dei punti nella variabile Wz
- stabilire come unire i punti e mettere i valori in Lines
- stabilire come colorare le faccie e fornire il numero di linee della faccia
- definire la priorita’ della faccia
Per essere piu’ veloci nella spiegazione e’ meglio fare un esempio.
NON E’ POSSIBILE DISEGNARE LE FACCIE A CASO SE E’ PRESENTE LA ROUTINE PER ELIMINARE LE FACCIE NASCOSTE!!!!!!!
Se vogliamo disegnare un cubo, la prima faccia sara’ cosi’ strutturata:
0----1 | | | | | | 3----2Ora e’ necessario dare un verso di percorrenza alla faccia:
0--------1 | -> | | |/\ | |||
|| | |||
|| | |\/
| |
| |
3——–2
<-
Come si nota la faccia va’ dal punto 0 al 1, dal 1 al 2, dal 2 al 3 e dal 3 allo 0. IMPORTANTE iniziare sempre dallo 0.
LA FACCIA ADIACENTE DEVE AVERE VERSO DI PERCORRENZA OPPOSTO !!!
4 /| / | / | 0--------1/ | | -> | | | | |/\ | | 5
|| | ||| /
|| | ||| /
| \/| /
| |/
3——–2
<-
La faccia formato dai punti : 1,4,5,2 deve avere verso di percorrenza opposto alla precedente (solo se 1 lato la tocca). Quindi:4 /| -> / ||| / ||| 0--------1/ |\/ | | | | | | | /\| 5 | ||| / | ||| / | | /<- | |/ 3--------2La faccia sara’ unita in questo modo: dal 2 al 1, dal 1 al 4, dal 4 al 5, dal 5 al 2. Ora date le coordinate nello spazio 3D, e data la simmetria centrale:
Y (-100,-100,100) (100,-100,100) /\ 0---------1 | | | | | | | | | | | / Z | - - | | / | | | | / | | |/ | | ----------> X 3---------2 (-100,100,100) (100,100,100)La faccia in primo piano ha Z=100 e quella dietro Z=-100.
Abbiamo per le prime 2 faccie:
Wx: dc.w -100,100,100,-100,100,100
Wy: dc.w -100,-100,100,100,-100,-100
Wz: dc.w 100,100,100,100,-100,-100
Lines:
dc.w 0,1,1,2,2,3,3,0
dc.w 5,2,2,1,1,4,4,5
Plane:
dc.w 4,0,4,1
Priotity: ; 0 se le calcola ; 1 se le disegna sempre ; 2 se ultima
dc.w 0,0
Plane definisce:4,0 = faccia composta da 4 linee con colore 0
4,1 = faccia composta da 4 linee con colore 1
esempio :13,89 = faccia composta da 13 linee con colore 89
Priotity definisce se:
0 = la faccia deve essere calcolata (se visibile o no) tramite routine che calcola la faccie nascoste
1 = la faccia deve essere disegnata sempre, dimentica passaggio sopra
2 = la faccia deve essere disegnata per ultima, dopo tutte le altre.
Colori :
; 0= primo plane
; 1= secondo plane
; 2= terzo plane
; 3= primo + secondo plane
; 4= primo + terzo plane
; 5= secondo + terzo plane
; 6= primo + secondo + terzo plane
; uso della griglia (stencil vector !!!!)
; 7= primo plane
; 8= secondo plane
; 9= terzo plane
; 10= primo + secondo plane
; 11= primo + terzo plane
; 12= secondo + terzo plane
; 13= primo + secondo + terzo plane
P.S.: I dati necessari al programa si possono prelevare dall’archivio dello scorso mese. P.S.2: Se ho dimenticato di spiegare qualcosa , mandatemi una E-Mail
Corso Di Blitz Basic
Orbitali atomici per l’equazione di Scroedinger.
Probabilmente un titolo migliore potrebbe essere: “Un modo numerico per scoprire che la fisica funziona”. Il programma è semplicemente un function plotter che sfrutta le coordinate polari invece delle solite coordinate cartesiane.
Lo scopo è quello di disegnare la distribuzione di probabilità di trovare un elettrone vicino ad un determinato punto dello spazio attorno al nucleo di un atomo idrogenoide (cioè un atomo con un solo elettrone ma con un nucleo composto da Z protoni). Dovete immaginare l’elettrone come una nuvola attorno al nucleo dell’atomo: i colori rappresentano la probabilità di trovare l’elettrone in un intorno di un determinato punto nello spazio per un determinato orbitale (quello scelto fissando tre parametri (n,l,m)). I parametri hanno il loro solito significato: n è detto “numero quantico principale” ed è legato all’energia dell’orbitale; l è detto “numero quantico azimutale” (o orbitale) in quanto è legato al momento angolare orbitale; m è detto “numero quantico magnetico”. Ciascuna scelta della tripletta individua un diverso orbitale e quindi un diverso comportamento dell’elettrone. Per ottenere la tridimensionalità degli orbitali dovete farli ruotare attorno all’asse verticale dello schermo. Notate anche come il medesimo orbitale si rimpicciolisce quando aumentate il numero Z di cariche positive nel nucleo.
Poiché sono un fisico, prima di tutto vi dirò qualcosa sull’equazione di Scroedinger (se già conoscete questi argomenti potete benissimo saltarli: Goto Shortcut): avete bisogno solo di poche nozioni di algebra elementare in quanto ometterò tutti i dettagli e citerò solo i concetti essenziali. Inoltre tutto quello che segue fino all’etichetta Shortcut esclusa non è indispensabile per la comprensione del programma.
Le soluzioni dell’equazione di Scroedinger forniscono la distribuzione della densità di probabilità nello spazio, ovvero qual’è la possibilità di trovare la particella nell’intorno di un determinato punto. L’equazione agli autovalori si scrive:
Hu(x) = Eu(x)
dove H è l’operatore Hamiltoniano, E è l’autovalore (l’energia) e u(x) è l’autofunzione. Il passo successivo è quello di scrivere il vettore x = (x, y, z) in coordinate sferiche (r, theta, phi) e di cercare una soluzione dell’equazione della forma R(r)T(theta)P(phi), dove R dipende solo dal raggio r, T dipende solo dall’angolo theta e P dipende solo dall’angolo phi. Scriviamo quindi:
H[R(r)T(theta)P(phi)] = E [R(r)T(theta)P(phi)]
Se prendiamo come operatore H il Laplaciano (in notazione TeX: \nabla^2) più un potenziale U(r) dipendente solo dalla coordinata radiale, la soluzione generale è:
u (r, theta, phi) = R (r) Y (theta, phi)
nlm n lm
dove le Y sono le cosiddette armoniche sferiche (alcune utili funzioni che sono già state studiate dai matematici).
L’atomo idrogenoide appartiene a questo schema generale: immaginiamo una particella con una carica negativa che si muove in un potenziale di tipo Coulombiano
2
Ze
U(r) = – —
r
generato da un nucleo fisso con Z cariche positive. Sostituendo tale potenziale nelle relazioni precedenti, con molti(ssimi) conti noiosi e subdoli ricaviamo che la parte R è costituita dai polinomi di Laguerre (altre terribili funzioni). In questo modo abbiamo ricavato le funzioni u_{nlm}, parte delle quali compaiono nel programma.
Shortcut
Supponiamo che abbiate saltato tutta la parte precedente (se non l’avete fatto ora probabilmente avete un terribile mal di testa): partite con una funzione u dipendente da tre parametri interi non negativi (n,l,m) e da tre variabili (r, theta, phi) che sono le coordinate sferiche di un punto nello spazio. Fissate i tre parametri (ad es.: (n,l,m)=(1,0,0)): affermo che la risultante funzione u ha una simmetria di rotazione rispetto all’angolo phi, quindi possiamo rappresentarla su uno schermo 2-dimensionale utilizzando solo le rimanenti coordinate (r, theta); poi possiamo ruotarla con l’immaginazione attorno all’asse verticale dello schermo per ottenere il risultato finale. A seconda dei valori dei tre parametri la funzione u ha espressioni differenti e, quindi, diverse sono le forme che appaiono sul vostro monitor.
Il programma è un function plotter: valuta la funzione u(r, theta) per un intervallo di valori delle due variabili; il valore di u viene poi convertito in colore e disegnato sullo schermo. Poiché la funzione u fornisce una probabilità i suoi valori sono compresi tra 0 e 1, però tale valore è spesso così piccolo che, quando viene convertito in colore, fornisce sempre 0 come risultato. Dunque ho dovuto aggiungere il “colour factor”, ovvero un fattore moltiplicativo che “sposta” il valore della probabilità in un intervallo utile per la selezione dei colori. C’è un modo migliore per far questo: calcolare l’intero grafico senza disegnarlo e memorizzare il massimo valore che si ottiene per la funzione u; poi potete scalare la densità di probabilità in modo che il valore massimo corrisponda al colore numero 31, e così via… Non ho scritto questa parte dell’algoritmo (potete farlo voi per esercizio se volete) poiché il programma sarebbe diventato più lento e, invece, volevo che ammiraste gli orbitali dell’atomo di idrogeno senza dover attendere troppo.
Clickate qui per il sorgente.
E per Esperti
Basi di OOP e sue implementazioni in AmigaE (Parte 2)
Uno dei principi piu’ importanti della programmazione a oggetti e’ di cercare di creare oggetti piccoli, compatti e specializzati. Ereditare un oggetto con queste caratteristiche sara’ sempre facile e fruttuoso. Gli oggetti creati dovranno essere il piu’ specializzati possibile: se create un oggetto “disco” che si occupa dell’ input/output su di un disco, cercate di prevedere tutte le funzionalita’ che un programmatore potrebbe richiedere e fate anche in modo che l’oggetto creato sia testato in tutte le condizioni, in modo da assicurare stabilita’ anche se il programmatore che si accinge ad utilizzare il vostro oggetto commette degli errori.
La OOP ha delle caratteristiche esaltanti e riesce a mettere nelle mani del programmatore una serie di strumenti per lo sviluppo rapidissimo di applicazioni complesse. Tutto questo ha pero’ un prezzo: bisogna pianificare accuratamente le caratteristiche e i comportamenti dell’oggetto PRIMA di iniziare a scrivere del codice. Questo accorgimento, che di per se’ potrebbe sembrare banale, riesce invece ad assicurare un notevole risparmio di tempo nella stesura definitiva e permettera’ poi di ereditare l’oggetto proficuamente.
Un Primo Esempio
Iniziamo adesso a scrivere il nostro primo oggetto in Amiga E, per quello che riguarda la parte teorica della programmazione a oggetti, ci occuperemo dei vari aspetti man mano che li incontreremo. Il nostro primo oggetto sara’ molto semplice e sicuramente non molto utile, ma servira’ ad introdurci alla programmazione a oggetti. Ci occuperemo di scrivere un oggetto chiamato “person” che conterra’ il nome, il cognome e il numero di telefono di una persona.
Per prima cosa, inizializziamo descriviamo la struttura dell’oggetto persona, in Amiga E scriveremo:
OBJECT person
name:PTR TO CHAR
surname:PTR TO CHAR
phone:PTR TO CHAR
ENDOBJECT
come vedete abbiamo definito un OBJECT standard di E, che normalmente si utilizza per la creazione delle strutture. Come abbiamo detto in precedenza, un oggetto non e’ altro che un inseme di dati organizzati in una struttura e delle funzioni particolari apposite per la loro manipolazione, non c’e’ da stupirsi, quindi, che un oggetto in Amiga E inizi proprio con la definizione della struttura OBJECT, cosi’ come siamo sempre stati abituati a fare.
Tra le funzioni piu’ importanti legate ad un oggetto, troviamo il “costruttore”, che serve ad inizializzare un oggetto durante la sua creazione, e il “distruttore”, che invece si occupa di liberare tutte le risorse eventualmente allocate dall’oggetto. Solitamente, al “costruttore” si assegna lo stesso nome dato all’oggetto che deve costruire, quindi nel nostro caso si chiamera’ “person()”. Il “distruttore”, invece, deve avere il nome fisso “end()” e non dovrebbe MAI essere chiamato, in quanto e’ Amiga E stesso che si occupa di invocarlo quando decideremo di “uccidere” un oggetto. Ricordatevi di chiudere tutti gli oggetti creati durante il programma, prima di uscire definitivamente, altrimenti potreste lasciare della memoria allocata.
Creiamo adesso il costruttore e il distruttore del nostro oggetto person. Il costruttore si occupera’ di allocare una stringa di 25 caratteri per ogni campo. Normalmente, non bisognerebbe dare dei limiti “rigidi” ai nostri oggetti, ma per ora ci limiteremo a descrivere il costruttore e lo faremo anche in modo non del tutto “corretto”, in seguito miglioreremo anche questo fattore. Per creare una funzione legata ad un oggetto, in E, basta scrivere PROC nomeproc() OF nomeogg e cosi’ noi faremo adesso per il costruttore (notate che si chiamera’ esattamente come l’oggetto).
PROC person() OF person
self.name:=String(25)
self.surname:=String(25)
self.phone:=String(25)
ENDPROC
come potete notare, le variabili “interne” ad un oggetto vengono referenziate con il suffisso “self.”.
Adesso possiamo creare il distruttore, che si dovra’ chiamare per forza end() e che si occupera’ di liberare tutte le risorse prima che l’oggetto venga ucciso:
PROC end() OF person
DisposeLink(self.name)
DisposeLink(self.surname)
DisposeLink(self.phone)
ENDPROC
Ora che il nostro oggetto e’ in grado di inizializzarsi e di distruggersi, possiamo iniziare a scrivere le routines necessarie a gestire i dati interni. Cominciamo con la creazione di due metodi: set() e get() che, rispettivamente, si occupano di settare e leggere una determinata inforazione all’interno. All’inizio del nostro codice scriviamo la seguente linea per creare delle costanti numeriche:
ENUM MODE_NAME=1, MODE_SURNAME, MODE_PHONE
e poi scriviamo, il seguente metodo set():
PROC set(s:PTR TO CHAR, mode=MODE_NAME) OF person
SELECT mode
CASE MODE_NAME
StrCopy(self.name, s)
CASE MODE_SURNAME
StrCopy(self.surname, s)
CASE MODE_PHONE
StrCopy(self.phone, s)
ENDSELECT
ENDPROC
e di seguito il metodo get():
PROC get(mode=MODE_NAME) OF person
DEF s:PTR TO CHARSELECT mode
CASE MODE_NAME
s:=self.name
CASE MODE_SURNAME
s:=self.surname
CASE MODE_PHONE
s:=self.phone
ENDSELECT
ENDPROC s
Con questa ultima procedura, possiamo gia’ testare il nostro oggetto e vederne il funzionamento, per farlo, sara’ necessario una procedura main() e una istanza dell’oggetto person. Il codice che segue, crea un oggetto person, tramite set() inserisce dei dati e li rilegge con get(). Per quanto riguarda la descrizione approfondita del sorgente e dei comandi NEW e END, la eseguiremo nel prossimo articolo.
PROC main()
DEF p:PTR TO personNEW p.person() -> Notate l’utilizzo del costruttore assieme a NEW
p.set(“Fabio”) -> Settiamo il nome della persona
p.set(“Rotondo”, MODE_SURNAME) -> Settiamo il cognome della persona
p.set(“(ITA)-(0)321 – 459676”, MODE_PHONE) -> Settiamo il numero di telefono.WriteF(“Name:\s\nSurname:\s\nPhone:\s\n”, p.get(), p.get(MODE_SURNAME), p.get(MODE_PHONE))
END p -> Uccidendo l’oggetto, automaticamente liberiamo anche la memoria allocata da questo.
CleanUp(0) -> Questo comando e’ necessario per ripulire tutto, lo dice Wouter 😉
ENDPROC -> Fine del programma.
continua nel prossimo numero…
Tutorial Di Lightwave (Parte 3)
Eccoci arrivati al terzo numero della rivista dedicata ad AMIGA. In questo numero e in altri successivi impareremo a creare un gioco dalla grafica Tridimensionale e quindi molto spettacolare da vedere, ma molto facile da fare.
Materiale occorrente:
- LIGHTWAVE e MODELER
- Programmi di FotoRitocco: ADpro, ImageFx, ecc.
- Programmi 2D: Brillance, Dpaint, Cloanto Paint ecc.
- TEXTURE varie
Per prima cosa bisogna caricare il Modeler di LightWave, selezionare BOX e NUMERIC, inserire il valore 10 nei SEGMENTS. Modificare con l’ Opzione DRAG tutti i punti che vogliamo in modo Caotico e disordinato su tutti gli assi PO,PV,PL. Assegnamo la SURFACE Rock a tutto l’ oggetto, facendo POLYGON, SURFACE. Copiamo l’ oggetto in modo da formare un quadrato e salviamo il tutto.
Andiamo in LIGHTWAVE carichiamo l’ oggetto e posizioniamo la CAMERA e la LIGHT esattamente davanti all’ oggetto. Creaiamo la KEY e renderizziamo il TUTTO. Abbiamo creato così il blocco principale.
Ora carichiamo come Background, in LIGHTWAVE, un qualsiasi oggetto che rassomigli a delle montagne (i classici DEM che si possono trovare vanno benissimo). Carichiamo i Gruppi di Blocchi e posizioniamoli, come vogliamo, molto distanti dalle nostre montagne. Questi blocchi, che dovranno essere copiati più volte, serviranno per creare il percorso del nostro giocatore. Ora posizioniamo la CAMERA e la LIGHT frontalmente, ma un po’ più in alto della linea d’ orizzonte. Fatto questo renderizziamo il nostro percorso. L’ effetto ottenuto e’ molto bello da vedere e facile da fare, come si puo’ vedere nel disegno dimostrativo. Aggiungendo altri blocchi, che verranno spiegati nel prossimo numero, si potrà avere una grande varietà nei fondali. Nel prossimo numero verranno spiegati i seguenti argomenti:
- Creazione di altri Blocchi
- Diversi modi per creare i Background
- Creazione del secondo livello di gioco.
What We Have Asked To VIScorp
New OS features :
- Improve camd.library so it can be a valid and solid tool for
developing midi apps.- Create and implement a library to create font sensitive,
resizable GUIs (such as MUI, BGUI, Triton and so on).
This could avoid the proliferation of thousands of different libs
for this scope. I want not see the day when I was forced to load up
four different libs for four different programs.- Implement a Virtual Memory Manager into OS. So every user can use
bigger programs than its system is capable of.
(This should avoid proliferation of different programs such as VMM,
GigaMem and so on…)- We want NET support : local, ethernet and Internet support all
by our own OS. It should be not a very big problem, and should
increase dramatically productivity (we should not thing to Amiga
as a “stand alone” computer anymore : it should be seen as a
powerful tool for multimedia developing. As it has always been.)- Create some “easy-to-use” libs : for example, I have never used
camd.library for creating a little proggy to play midi,
because it misses some commands such as : struct midi * midih= camd_OpenMIDIFile (APTR filename) to simply load up a midi file and : BOOL result = camd_PlayMidi(struct midi * midih)
BOOL result = camd_StopMidi(struct midi * midih) to play and stop a midi file.
We need EASY and FAST libs to develop easy programs or
just programs that has a simple implementation of some features.- Create a ILBM.library to load and save IFF pictures, with async I/O.
This should avoid bad-written proggies which do not load up
some particular IFF pics. Also an anim.library should be appreciated.- Better OOP and BOOPSI support. Create an easy and comfy way to talk
to objects in Amiga OS, and try to implement as object as many part
of the OS as possible. We are talking of a ’96/’97 computer :
and we MUST be the future.- Implement AVI, QuickTime and something like that as datatypes.
- Power up Datatypes so they can handle up to 24Bit graphics.
- Power up BOOPSI gadgets. New gadgets = more power and better interfaces.
- System support for streamers, scanners and so on.
Hardware :
- Get rid of 68EC0x0 processors : use just FULL featured processors.
Get rid of 68020, we need a 68030 base machine with FPU and MMU.
This should be the base and nothing less powerful.- At least 4Mb of RAM is needed. 2MB of chip and 2MB of fast.
A stock A1200, now, is just useful for games.
But Amiga is not a game machine anymore
(it’s never been, in my opinion).- Please, just HD floppies.
- Consider a built-in SCSI2 interface also.
- Keep on custom gfx-chips development : no stuck up with gfx-cards,
because they are all PC gfx-chip based, which means :
VGA resolution (ie. Not genlockable, no TV-set compatible and so on)- On the other way, go on developing RTG technology.
- Extend Chip Ram to 16MB (at least).
Consider also a faster chip ram access.- Extend Audio chip to 16bit.
- The new gfx chip should be : chunky, planar and also hybrid.
Should be 24 or 32bit (a 32Bit chip should give us also
a very powerful alpha channel) and MUST be faster and faster
in blitting (almost 10/20 times faster)- Increase hardware sprite from 8 to 32 minimum,
increase width from 64 (AGA) to 128/256 pixels,
increase colors from 4 to 8 or 16.- Better dual-playfield with 32 + 32 colors and up
(ideal should be 128 + 128 or 256+256, but also 32 + 32
would be nice)Developer Support:
Share as many infos as possible : why don’t you create a CD-ROM
containing all infos about Amiga OS and hardware.
For example devcon, OS3.1/OS3.2 includes and autodocs.
All CATS docs… everything that can help hardware and software
developers developing.
Review
Font Machine – A Program By ClassX
Una delle caratteristiche più esaltanti di Amiga è la sua incredibile potenza e flessibilità nella gestione della grafica. Su Amiga non esiste la “modalità testo“: tutto quello che appare su video, anche i caratteri della Shell, sono in realtà elementi grafici. Naturale evoluzione dei caratteri “piatti” e monocromatici, è quindi la nascita di Color Fonts, caratteri a colori che Amiga gestisce perfettamente e che rendono più gradevoli le nostre pagine Web, le nostre video titolazioni, la creazione delle nostre demo o semplici immagini ecc…
Fino ad oggi, la creazione di Fonts a colori era relegata a programmi o difficili da usare (vedi Cloanto Personal Fonts, un programma con una interfaccia ed una impostazione globale ormai vecchia di almeno sette anni) o troppo amatoriali: ci sono infatti programmi per la creazione di Fonts a colori, ma sono di pubblico dominio e, a volte, anche più instabili del prodotto della Cloanto.
Ora ClassX, una casa di software in quel di Pisa, sforna questo piccolo pacchetto, un prodotto professionale e dalle prestazioni elevatissime, che permette la realizzazione di Fonts a colori con pochi (e semplici) click del mouse.
La teoria che sta alla base di Font Machine è molto semplice: un Font a colori può essere ricavato rielaborando un font monocromatico. Questa operazione di rielaborazione, viene eseguita da Font Machine con vari metodi, sempre efficaci e differenti. E’ possibile infatti “mappare” su di un font una immagine grafica, oppure creare dei pattern matematici direttamente all’interno di Font Machine. Oltre alla mappatura, è possibile creare un’ombra al Font ed anche dargli un effetto 3D, molto simile a quello che si può ottenere utilizzando pacchetti come Scala Multimedia.
La maggior parte delle funzioni del programma sono eseguite in asincrono: è possibile quindi modificare al volo i parametri dei caratteri e vedere subito i risultati sul Font… e mentre il programma genera i nuovi Font è possibile già rimodificare i valori.
L’interfaccia del programma è semplice ed intuitiva (io l’ho utilizzato appieno senza nemmeno aprire il manuale) e non vi ci vorranno più di cinque minuti per iniziare a produrre Fonts originali, attraenti e sempre diversi.
Il manuale è molto completo e, sotto certi aspetti, forse anche un po’ troppo per principianti: pensate che descrive e spiega cos’è un gadget, uno slider… insomma: tutti elementi che un qualsiasi utilizzatore Amiga dovrebbe conoscere. Questo, d’altro canto, dimostra l’incredibile cura messa anche nella creazione del manuale.
Ad un esame più approfondito, Font Machine si è comportato perfettamente: non genera Enforcer’s Hits, è stabile anche con MungWall e genera Fonts che, ricaricati con vari programmi di grafica e DTP, si sono rivelati essere perfetti.
Insomma, Font Machine è un programma facile da usare, completo, affidabile e altamente professionale… ed è pure divertentissimo da usare!
Personalmente, lo consiglio a tutti coloro che si dilettano di grafica o che utilizzano Amiga in campo professionale (per esempio per la creazione di video titolazioni).
Se volete vedere due screen shots di Font Machine al lavoro, premete
Font Machine Pic 1 Font Machine Pic 2
ATTENZIONE! ClassX offre uno sconto del 20% a chi acquista il programma dicendo che ha letto la recensione su Amiga Blast!!
Per informazioni, scrivete una mail a:classx@pisoft.it
