mercoledì 31 dicembre 2014

ImageData con il canvas

Ho un canvas che misura 600 x 600 pixel.
Ora creo un imageData.
<!DOCTYPE html>
<html>
<head>
<script>
var canvas;
var ctx;
var x;
var y;
var alfa;
var sfondo = new Image();

function inizia(){
 canvas=document.getElementById("myCanvas");
 ctx=canvas.getContext("2d");
 ctx.fillStyle="#FFFFCC";
 ctx.rect(0,0,600,600);
 ctx.fill();
 elabora();
}
function elabora(){
 
 var imgData = ctx.createImageData(100, 1);

 for (var i = 0; i < 100; i+=4) {
     imgData.data[i]=255;
     imgData.data[i+1]=0;
     imgData.data[i+2]=0;
     imgData.data[i+3]=255;
 }

 ctx.putImageData(imgData, 10, 10);
}

window.addEventListener("load", inizia);
</script>
</head>
<body>

 <canvas id="myCanvas" width="600" height="600">
 </canvas>
</body>
</html> 
Ho creato un'immagine di dimensioni 100 x 1;
Definisco i valori dei pixel ogni 4: rosso, verde, blu, trasparenza;
Metto l'immagine creata alle coordinate 10,10.

Ed ecco che viene fuori una striscia rossa orizzontale.

Come primo passo andiamo bene.

lunedì 29 dicembre 2014

Scrivere un file XML con il C#

Ho trovato il modo di scrivere un file XML direttamente da un programma fatto con iln C#.
private void button1_Click(object sender, EventArgs e)
        {
            XmlTextWriter writer = new XmlTextWriter("C:/Users/Antonello/product.xml", System.Text.Encoding.UTF8);
            writer.WriteStartDocument(true);
            writer.Formatting = Formatting.Indented;
            writer.Indentation = 2;
            writer.WriteStartElement("Table");
            createNode("1", "Product 1", "1000", writer);
            createNode("2", "Product 2", "2000", writer);
            createNode("3", "Product 3", "3000", writer);
            createNode("4", "Product 4", "4000", writer);
            writer.WriteEndElement();
            writer.WriteEndDocument();
            writer.Close();
            MessageBox.Show("XML File created ! ");
        }

        private void createNode(string pID, string pName, string pPrice, XmlTextWriter writer)
        {
            writer.WriteStartElement("Product");
            writer.WriteStartElement("Product_id");
            writer.WriteString(pID);
            writer.WriteEndElement();
            writer.WriteStartElement("Product_name");
            writer.WriteString(pName);
            writer.WriteEndElement();
            writer.WriteStartElement("Product_price");
            writer.WriteString(pPrice);
            writer.WriteEndElement();
            writer.WriteEndElement();
        }
Il file può essere creato dovunque.
Resta da studiare la cosa e da elaborare anche un programma per la lettura.

domenica 28 dicembre 2014

Una linea in movimento mediante il canvas

Ecco, ho cominciato a penetrare i segreti dell'animazione mediante il canvas.
Il meccanismo è banale.
Quel tutorial che avevo trovato è un tantinello cervellotico, ma mi è servito a capire il meccanismo, che poi ho verificato su un tutorial più facile da capire.
Ecco il codice:
<!DOCTYPE html>
<html>
<head>
<script>
var canvas;
var ctx;
var x;
var y;
var sfondo = new Image();

function inizia(){
 canvas=document.getElementById("myCanvas");
 ctx=canvas.getContext("2d");
 ctx.fillStyle="#000080";
 ctx.beginPath();
 ctx.rect(0,0,600,600);
 ctx.closePath();
 ctx.fill();
 sfondo=ctx.getImageData(0,0,600,600);
 x=0;
 y=600;

 z=setInterval(disegna,100);
}

function disegna(){
 ctx.putImageData(sfondo,0,0);
 ctx.strokeStyle="white";
 ctx.beginPath();
 ctx.moveTo(0,0);
 ctx.lineTo(x,y);
 ctx.closePath();
 ctx.stroke();
 x=x+10;
}

window.addEventListener("load", inizia);
</script>
</head>
<body>

 <canvas id="myCanvas" width="600" height="600">
 </canvas>
</body>
</html> 
che traccia una linea che si muove.

Game su canvas...

Ora il tutorial fa delle aggiunte.
Provo a marcarle in rosso...

<!DOCTYPE html>
<html>
<head>
<script>
var canvas;
var ctx;

//memorizziamo le immagini
var back = new Image();
var oldBack=new Image();
var ship=new Image();

//memorizziamo le coordinate
var shipX=0;
var shipY=0;
var oldShipX=0;
var oldShipY=0;

function canvasSpaceGame(){
 canvas=document.getElementById("myCanvas");
 
 ctx=canvas.getContext("2d");
 
 
 ctx.fillStyle="black";
 ctx.rect(0,0,300,300);
 ctx.fill();
 
 back=ctx.getImageData(0,0,30,30);
 
 stars();  
 
 makeShip();   
 
 
        gameLoop = setInterval(doGameLoop, 16);

        
        window.addEventListener('keydown', whatKey, true);
 
}

function stars(){
 for(var i=0;i<50;i++){
  x=Math.floor(Math.random()*299);
  y=Math.floor(Math.random()*299);
  
  ctx.fillStyle="yellow"
  if (x<30 || y<30) ctx.fillStyle="black";
  ctx.beginPath();
  ctx.arc(x,y,3,Math.PI*2,false);
  ctx.closePath();
  ctx.fill(); 
  
  oldBack=ctx.getImageData(0,0,30,30); 
 }
}
function makeShip() {

       
        ctx.beginPath();
        ctx.moveTo(28.4, 16.9);
        ctx.bezierCurveTo(28.4, 19.7, 22.9, 22.0, 16.0, 22.0);
        ctx.bezierCurveTo(9.1, 22.0, 3.6, 19.7, 3.6, 16.9);
        ctx.bezierCurveTo(3.6, 14.1, 9.1, 11.8, 16.0, 11.8);
        ctx.bezierCurveTo(22.9, 11.8, 28.4, 14.1, 28.4, 16.9);
        ctx.closePath();
        ctx.fillStyle = "rgb(222, 103, 0)";
        ctx.fill();

        
        ctx.beginPath();
        ctx.moveTo(22.3, 12.0);
        ctx.bezierCurveTo(22.3, 13.3, 19.4, 14.3, 15.9, 14.3);
        ctx.bezierCurveTo(12.4, 14.3, 9.6, 13.3, 9.6, 12.0);
        ctx.bezierCurveTo(9.6, 10.8, 12.4, 9.7, 15.9, 9.7);
        ctx.bezierCurveTo(19.4, 9.7, 22.3, 10.8, 22.3, 12.0);
        ctx.closePath();
        ctx.fillStyle = "rgb(51, 190, 0)";
        ctx.fill();
        
        ship=ctx.getImageData(0,0,30,30);
        ctx.putImageData(oldBack, 0, 0);
}
  

window.addEventListener("load",function(){canvasSpaceGame()});
</script>
</head>
<body>
 <canvas id="myCanvas" width="300" height="300">
 </canvas>
</body>
</html> 
Ho marcato in verde le variabili globali, in rosso le istruzioni che memorizzano in una variabile delle immagini o le rimettono sul canvas (a quanto ho capito adesso) e in blu due righe che poco ancora capisco, di cui una aggiunge un evento da tastiera.
Ho notato che putImageData, da quanto riesco a capire, rimette sullo schermo il contenuto di immagine immagazzinato in una variabile precedentemente, e infatti rimettendo alle coordinate 0 e 0 oldBack nasconde l'astronave...

Cielo stellato e variazioni.

Seguiamo pedissequamente...

C'era il fatto di disegnare 50 stelle casuali.
Bene, adesso ho fatto un po' di variazioni e ho disegnato un cielo stellato più ampio, con stelle gialle.
<!DOCTYPE html>
<html>
<head>
<script>
function canvasSpaceGame(){
	canvas=document.getElementById("myCanvas");
	
	ctx=canvas.getContext("2d");
	
	
	ctx.fillStyle="black";
	ctx.rect(0,0,1000,600);
	ctx.fill();
	
	stars();     
}

function stars(){
	for(var i=0;i<6000;i++){
		x=Math.floor(Math.random()*999);
		y=Math.floor(Math.random()*999);
		
		ctx.fillStyle="yellow"
		
		ctx.beginPath();
		ctx.arc(x,y,1,Math.PI*2,false);
		ctx.closePath();
		ctx.fill();
	}
}
		

window.addEventListener("load",function(){canvasSpaceGame()});
</script>
</head>
<body>
	<canvas id="myCanvas" width="1000" height="600">
	</canvas>
</body>
</html> 
Come posso fare per fare alcune stelle gialle e altre bianche?
<!DOCTYPE html>
<html>
<head>
<script>
function canvasSpaceGame(){
	canvas=document.getElementById("myCanvas");
	
	ctx=canvas.getContext("2d");
	
	
	ctx.fillStyle="black";
	ctx.rect(0,0,1000,600);
	ctx.fill();
	
	stars();     
}

function stars(){
	for(var i=0;i<3000;i++){
		x=Math.floor(Math.random()*999);
		y=Math.floor(Math.random()*999);
		
		ctx.fillStyle="yellow"
		
		ctx.beginPath();
		ctx.arc(x,y,1,Math.PI*2,false);
		ctx.closePath();
		ctx.fill();
		
		x=Math.floor(Math.random()*999);
		y=Math.floor(Math.random()*999);
		
		ctx.fillStyle="white"
		
		ctx.beginPath();
		ctx.arc(x,y,1,Math.PI*2,false);
		ctx.closePath();
		ctx.fill();
	}
	
}
		

window.addEventListener("load",function(){canvasSpaceGame()});
</script>
</head>
<body>
	<canvas id="myCanvas" width="1000" height="600">
	</canvas>
</body>
</html> 

fillStyle, rect e fill nel canvas

Preso possesso del canvas, adesso vediamo che ci posso fare...

<!DOCTYPE html>
<html>
<head>
<script>
function canvasSpaceGame(){
	canvas=document.getElementById("myCanvas");
	
	ctx=canvas.getContext("2d");
	
	
	ctx.fillStyle="#AAFFBB";
	ctx.rect(0,0,300,300);
	ctx.fill();
}


window.addEventListener("load",function(){canvasSpaceGame()});
</script>
</head>
<body>
	<canvas id="myCanvas" width="300" height="300">
	</canvas>
</body>
</html> 
Ecco, ho definito il colore di riempimento, delineato un rettangolo e dato il comando fill che riempie il rettangolo in questione...

Iniziamo col canvas: prendiamone possesso dal Javascript...

Scriviamo Tutorial di riferimento il codice di un canvas, con tutti gli elementi del Path per tracciare "roba" su di esso...

<!DOCTYPE html>
<html>
<head>
<script>
</script>
</head>
<body>
 <canvas id="myCanvas" width="300" height="300">
 </canvas>
</body>
</html> 
Ora con il Javascript "prendiamo possesso" del canvas...

Inizio con la prima funzione Javascript "associata" all'evento load della finestra.
<!DOCTYPE html>
<html>
<head>
<script>
function inizia(){
 
}


window.addEventListener("load",function(){inizia()});
</script>
</head>
<body>
 <canvas id="myCanvas" width="300" height="300">
 </canvas>
</body>
</html> 
E ora "prendiamo possesso" del canvas.

<!DOCTYPE html>
<html>
<head>
<script>
function canvasSpaceGame(){
 canvas=document.getElementById("myCanvas");
 
 ctx=canvas.getContext("2d");
 
}


window.addEventListener("load",function(){canvasSpaceGame()});
</script>
</head>
<body>
 <canvas id="myCanvas" width="300" height="300">
 </canvas>
</body>
</html> 

sabato 27 dicembre 2014

Ereditarietà in Javascript

Creo un costruttore qualunque:
<script>
function classe(nome){
 this.chiama=function(){
  alert(nome);
 }
}
function inizia(){
 var oggetto=new classe("Cicciobello");
 oggetto.chiama();
}
window.addEventListener("load",function(){inizia()});
</script>
Bene.
Ho creato un'istanza oggetto di una classe classe.

Ora voglio creare una classe che eredita da classe...

Ecco:
<script>
function classe(nome){
 this.chiama=function(){
  alert(nome);
 }
}

function figlia(nome){
 classe.call(this,nome);
}
function inizia(){
 var oggetto=new classe("Cicciobello");
 oggetto.chiama();
 
 var derivata=new figlia("Mario");
 derivata.chiama();
}
window.addEventListener("load",function(){inizia()});
</script>
E ottengo una seconda MessageBox con il nome "Mario". Quindi funziona.

Come controprova tolgo la riga con scritto classe.call(this,nome);
<script>
function classe(nome){
 this.chiama=function(){
  alert(nome);
 }
}

function figlia(nome){
 
}
function inizia(){
 var oggetto=new classe("Cicciobello");
 oggetto.chiama();
 
 var derivata=new figlia("Mario");
 derivata.chiama();
}
window.addEventListener("load",function(){inizia()});
</script>
E vediamo:
Sì, non ottengo più la seconda MessageBox.
Questo che significa?
Praticamente invece di scrivere public classe o :classe o extends classe come nei vari linguaggi, qui si inserisce il nome della classe genitrice con il call(this.... e i parametri).

GameLoop nella creazione di giochi con l'uso del Canvas in HTML5

Adesso viene soltanto immessa la funzione GameLoop.
Proviamo...

<!DOCTYPE html>
<html>
<head>
<script>
function Game(){
 
 this.div=document.getElementById("GameDiv");
 this.div.style.width="768";
 this.div.style.height="512";
 
 this.canvas=document.getElementById("GameCanvas");
 this.canvas.setAttribute("width","768");
 this.canvas.setAttribute("height","512");
 this.canvas.defaultWidth=this.canvas.width;
 this.canvas.defaultHeight=this.canvas.height;
 
 this.canvas.style.cursor="none";
 
 this.ctx=this.canvas.getContext("2d");
 
 this.GameLoop=function(){
  
  if(!this.paused){
   this.Update();
  }
  this.Draw();
  window.requestAnimFrame(function(){
   game.GameLoop();
  });
 }
  
}

function StartGame(){
 game=new Game();
}
window.addEventListener("load",function(){
 StartGame();
},true);
</script>
</head>
<body>
 <div id="GameDiv">
  <canvas id="GameCanvas">
  </canvas>
 </div>
</body>
</html>
Però ora il tutorial mi fa una divagazione sull'ereditarietà prototipale del Javascript...
Conviene seguirla...

Creazione di games con HTML5: parte iniziale (scrittura del costruttore di Game)

Mettiamo un DIV.
<!DOCTYPE html>
<html>
<head>
<script>
<!DOCTYPE html>
<html>
<head>
<script>

 
</script>
</head>
<body>
 <div id="GameDiv">
  <canvas id="GameCanvas">
  </canvas>
 </div>
</body>
</html>>


Ora scriviamo la funzione Game() in Javascript.
<!DOCTYPE html>
<html>
<head>
<script>
function Game(){
 
 this.div=document.getElementById("GameDiv");
 this.div.style.width="768";
 this.div.style.height="512";
 
 this.canvas=document.getElementById("GameCanvas");
 this.canvas.setAttribute("width","768");
 this.canvas.setAttribute("height","512");
 this.canvas.defaultWidth=this.canvas.width;
 this.canvas.defaultHeight=this.canvas.height;
 
 this.canvas.style.cursor="none";
 
 this.ctx=this.canvas.getContext("2d");
}

function StartGame(){
 game=new Game();
}
window.addEventListener("load",function(){
 StartGame();
},true);
</script>
</head>
<body>
 <div id="GameDiv">
  <canvas id="GameCanvas">
  </canvas>
 </div>
</body>
</html>


Ecco.

venerdì 26 dicembre 2014

Disegnare triangoli in Direct3D senza VertexBuffer

Disegno triangoli soltanto definendo un array di vertici.
Questo è il codice che definisce i vertici.
public void CreaVertici()
        {
            vertices = new CustomVertex.PositionColored[9];
            vertices[0].Position = new Vector3(0f, 0f, 0f);
            vertices[0].Color = Color.Blue.ToArgb();
            vertices[1].Position = new Vector3(0f, 10f, 0f);
            vertices[1].Color = Color.Blue.ToArgb();
            vertices[2].Position = new Vector3(10f, 0f, 0f);
            vertices[2].Color = Color.Blue.ToArgb();
            vertices[3].Position = new Vector3(5f, 0f, 0f);
            vertices[3].Color = Color.Green.ToArgb();
            vertices[4].Position = new Vector3(5f, 15f, 0f);
            vertices[4].Color = Color.Green.ToArgb();
            vertices[5].Position = new Vector3(15f, 0f, 0f);
            vertices[5].Color = Color.Green.ToArgb();
            vertices[6].Position = new Vector3(0f, -10f, 0f);
            vertices[6].Color = Color.Red.ToArgb();
            vertices[7].Position = new Vector3(18f, -15f, 0f);
            vertices[7].Color = Color.Red.ToArgb();
            vertices[8].Position = new Vector3(15f, 8f, 0f);
            vertices[8].Color = Color.Red.ToArgb();
        }
Il numero evidenziato in rosso su giallo è il numero di vertici compresi nell'array,

Se non si usa vertexBuffer bisogna specificare i vertici uno dopo l'altro anche se sono uguali.
Una volta specificati i vertici, di tipo CustomVertex.PositionColored, si usa il comando che li stampa:
        private void render()
        {
            device.Clear(ClearFlags.Target, System.Drawing.Color.Black, 1.0f, 0);
            device.BeginScene();
            device.VertexFormat = CustomVertex.PositionColored.Format;
            device.DrawUserPrimitives(PrimitiveType.TriangleList, 3, vertices);
            device.EndScene();
            device.Present();
        }
Ecco, quello marcato in rosso è il comando fondamentale, che stampa i triangoli specificando:
  • Il tipo di primitiva
  • Il numero di primitive
  • l'array di vertici da usare.
Il numero di primitive è importante! Se non si specifica il numero giusto non vengono disegnate tutte le primitive.
Ecco l'immagine:



Ma se io uso device.DrawUserPrimitives specificando un numero inferiore di primitive:
        private void render()
        {
            device.Clear(ClearFlags.Target, System.Drawing.Color.Black, 1.0f, 0);
            device.BeginScene();
            device.VertexFormat = CustomVertex.PositionColored.Format;
            device.DrawUserPrimitives(PrimitiveType.TriangleList, 2, vertices);
            device.EndScene();
            device.Present();
        }
Ottengo questa immagine:

mercoledì 24 dicembre 2014

Costruttori in Javascript

Cerchiamo di riprendere il Javascript...

Se quello che scriviamo abitualmente è solo il costruttore di una classe...
function funzione()
{
 alert("Ciao");
}

funzione();
ho verificato mediante il C# se sia ammissibile dichiarare una variabile nel corso di un metodo
        private void metodo()
        {
            int numero = 0;
            numero = 1234;
            Console.WriteLine(numero);
            Console.ReadLine();
        }
e lo è: è una variabile locale, allo stesso modo di come viene dichiarata nel costruttore in Javascript:
function funzione()
{
 var numero=0;
 numero=1234;
 alert(numero);
}

domenica 21 dicembre 2014

DirectX

Codice che ho ricavato finora:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Microsoft.DirectX.Direct3D;
using Microsoft.DirectX;

namespace DirectXProject
{
    public partial class mioForm : Form

    {
        
        public Device device;
        private float angle = 0f;
        CustomVertex.PositionColored[] vertices;
       
        public mioForm()
        {
            InitializeComponent();
            
        }

        public void InitializeDevice()
        {
            
            PresentParameters presentParams = new PresentParameters();
            presentParams.BackBufferCount = 1;
            presentParams.BackBufferFormat = Manager.Adapters[0].CurrentDisplayMode.Format;
            presentParams.BackBufferWidth =1366;
            presentParams.BackBufferHeight =768;
            
            presentParams.Windowed = false;
            presentParams.FullScreenRefreshRateInHz = Manager.Adapters[0].CurrentDisplayMode.RefreshRate;
            presentParams.SwapEffect = SwapEffect.Discard;

            device = new Device(0, DeviceType.Hardware, this, CreateFlags.SoftwareVertexProcessing, presentParams);
        }

        public void CreaVertici()
        {
            vertices= new CustomVertex.PositionColored[3];
            vertices[0].Position = new Vector3(0f, 0f, 0f);
            vertices[0].Color = Color.Red.ToArgb();
            vertices[1].Position = new Vector3(0f, 10f, 0f);
            vertices[1].Color = Color.Red.ToArgb();
            vertices[2].Position = new Vector3(10f, 0f, 0f);
            vertices[2].Color = Color.Red.ToArgb();
           
        }
        public void Camera()
        {
            device.Transform.Projection = Matrix.PerspectiveFovLH((float)Math.PI / 4, this.Width / this.Height, 1f, 100f);
             
            device.Transform.View = Matrix.LookAtLH(new Vector3(0, 0, -50), new Vector3(0, 0, 0), new Vector3(0, 1, 0));
            device.RenderState.Lighting = false;
            device.RenderState.CullMode = Cull.None;
        }

        private void render()
        {
            device.Clear(ClearFlags.Target, System.Drawing.Color.Black, 1.0f, 0);
            device.BeginScene();
            device.VertexFormat = CustomVertex.PositionColored.Format;
            device.Transform.World = Matrix.RotationX(angle) * Matrix.RotationZ(angle);
            device.DrawUserPrimitives(PrimitiveType.TriangleList,1,vertices);
            device.EndScene();
            device.Present();
            angle += 0.1f;

        }
       
        public static void Main()
        {


                mioForm frm = new mioForm();
                frm.WindowState = FormWindowState.Maximized;
                frm.InitializeDevice();
                frm.CreaVertici();
                frm.Camera();
                frm.Show();
                while (frm.Created)
                {
                    frm.render();
                    Application.DoEvents();
                }
            

        }
        

        private void mioForm_Load(object sender, EventArgs e)
        {

        }

        private void mioForm_Click(object sender, EventArgs e)
        {
            Application.Exit();
        }
        
    }
}
A parte l'effetto ameno di un triangolo rosso che ruota in modo un po' pazzoide, cerchiamo di analizzare il codice...

Nel costruttore viene chiamata solo InitializeComponent, che si trova nell'altro mezzo modulo con la mezza classe form...

Poi ho marcato in colori diversi i metodi fondamentali dell'oggetto che mi servono.
Sono quattro:
  • Uno che crea il Device
  • Uno che crea i Vertici
  • Uno che setta la Telecamera
  • Uno che dà l'avvio al disegno.
Così dovrebbe essere più chiaro.
I quattro vengono richiamati nel metodo Main()

domenica 14 dicembre 2014

Esercizio elementare di moltiplicazione di matrici relative alle coordinate di un punto.

Dunque proviamo a moltiplicare le due semplici matrici:
x         2  0
y         0  2
Le dimensiohni sono (2 x 1) e (2 x 2).
Dobbiamo invertirle:
2  0      x  
0  2      y
Adesso abbiamo (2 x 2) e (2 x 1), quindi sono moltiplicabili e ne verrà fuori una matrice di dimensioni (2 x 1).
2x + 0y = 2x
0x + 2y = 2y
La matrice risultante sarà quindi
2x
2y
Ed ecco che il valore raddoppia.

Moltiplicazione fra matrici

Le dimensioni delle matrici si descriverebbero con il numero di righe seguito dal numero di colonne.
 2  1 -1            1  1  2  2
-2  3  4            2 -3  1  3
                   -1 -1  5  2


Le dimensioni della prima matrice sono (2 x 3) e (3 x 4).
I numeri interni sono uguali, e quindi le due matrici sono moltiplicabili.
La matrice prodotto sarà uguale a (2 x 4).
Ogni riga si moltiplica per ogni colonna.
2*1 + 1*2 + (-1)*(-1) = 2 + 2 + 1 = 5;

2*1 + 1*(-3)+ (-1)*(-1) = 2 -3 +1 = 0;

2*2 + 1*1 + (-1)*5 = 4 + 1 -5 = 0;

2*2 + 1*3 + (-1)*2 = 4 +3 -2 = 5:


(-2)*1 + 3*2 + 4*(-1) = -2 + 6 -4 = 0;

(-2)*1 + 3*(-3) + 4*(-1) = -2 -9 -4 = -15;

(-2)*2 + 3*1 + 4*5 = -4 +3 +20 = 19;

(-2)*2 + 3*3 + 4*2 = -4 +9 +8 = 13;


Risultato:
5   0   0   5
0 -15  19  13
Corrisponde all'esempio trovato.
Prendiamo in esame questa proprietà del codice che serve per la telecamera:
device.Transform.View = Matrix.LookAtLH(new Vector3(0, 0, -40), new Vector3(0, 0, 0), new Vector3(0, 1, 0));
Adesso modifico il primo parametro, che dovrebbe essere il punto in cui io mi pongo con la telecamera per osservare il triangolo.
Come lo modifico, riporto anche l'ìmmagine, con pazienza, per ricostruire come mi sposto.


Partiamo dalla base.
device.Transform.View = Matrix.LookAtLH(new Vector3(0, 0, -40), new Vector3(0, 0, 0), new Vector3(0, 1, 0));

sabato 13 dicembre 2014

Studio di uno scheletro generale per un'applicazione DirectX

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Microsoft.DirectX.Direct3D;
using Microsoft.DirectX;

namespace DirectXProject
{
    public partial class mioForm : Form

    {
        public Device device;
        CustomVertex.PositionColored[] vertices;

        public mioForm()
        {
            InitializeComponent();
            
        }

        public void InitializeDevice()
        {
            angle = 0f;
            PresentParameters presentParams = new PresentParameters();
            presentParams.Windowed = true;
            presentParams.SwapEffect = SwapEffect.Discard;

            device = new Device(0, DeviceType.Hardware, this, CreateFlags.SoftwareVertexProcessing, presentParams);
        }

        public void CreaVertici()
        {
            vertices= new CustomVertex.PositionColored[3];
            vertices[0].Position = new Vector3(0f, 0f, 0f);
            vertices[0].Color = Color.Red.ToArgb();
            vertices[1].Position = new Vector3(10f, 0f, 0f);
            vertices[1].Color = Color.Green.ToArgb();
            vertices[2].Position = new Vector3(5f, 10f, 0f);
            vertices[2].Color = Color.Yellow.ToArgb();    
        }

        public void Camera()
        {
            device.Transform.Projection = Matrix.PerspectiveFovLH((float)Math.PI / 4, this.Width / this.Height, 1f, 50f);

            device.Transform.View = Matrix.LookAtLH(new Vector3(0, 0, -30), new Vector3(0, 0, 0), new Vector3(0, 1, 0));
            device.RenderState.Lighting = false;
            device.RenderState.CullMode = Cull.None;
        }


        protected override void OnPaint(PaintEventArgs e)
        { 
            device.Clear(ClearFlags.Target, Color.DarkSlateBlue, 1.0f, 0);
            device.BeginScene();
            device.VertexFormat = CustomVertex.PositionColored.Format;
            device.DrawUserPrimitives(PrimitiveType.TriangleList, 1, vertices);
            device.EndScene();
            device.Present();
        } 
        
       
        public static void Main()
        {
            mioForm frm = new mioForm();
            frm.InitializeDevice();
            frm.CreaVertici();
            frm.Camera();
            Application.Run(frm);

        } 
    }
}
Dunque il metodo CreaVertici(), che ho creato io, non fa altro che inizializzare un array di vertici del tipo PositionColored.
Il metodo Camera(), sempre creato da me, non fa che posizionare la telecamera, il punto di osservazione.

Il metodo Main chiama questi metodi che preparano i vertici e la telecamera, e quindi inizia il metodon OnPaint, nel quale:
  1. Si dice al device qual è il formato dei vertici.
  2. Si dice quale primitiva usare e la matrice di vertici da prendere in considerazione.

lunedì 8 dicembre 2014

Gestori di eventi e delegati.

Nell'ambito di una classe è dichiarato l'evento, con il nome preceduto dall'handler.
    class altraClasse
    {
        public event mioHandler Evento;

    }
che ancora mi dà errore perché quel mioHandler non significa ancora nulla.

Nell'ambito della stessa classe viene dichiarato il delegato, ossia l'handler.
Cerchiamo di interpretare con parole "umane": l'evento viene dichiarato con il nome dell'handler.
L'handler, essendo dichiarato come delegato, esprime la sua firma, ossia il numero e il tipo di parametri. Questo significa che quel dato evento può essere gestito solo da funzioni che abbiano quella firma.
Quindi con la dichiarazione del delegato noi non facciamo altro che esprimere il fatto che quel gestore di eventi, che gestisce quel dato evento, può essere espressione soltanto di funzioni con una determinata firma.
Proviamo:
    class altraClasse
    {
        public event mioHandler Evento;

        public delegate void mioHandler();

    }
Ecco, il mio handler, o delegato, non ha parametri.
Più semplice di così...

Ora, però, mettiamo nella nostra classe una funzione che evochi l'evento...
    class altraClasse
    {
        public event mioHandler Evento;

        public delegate void mioHandler();

        public void Evoca()
        {
            Evento();
        }

    }
Bene.

Ora dalla classe principale proviamo a istanziare questa classe.
        public static void Main()
        {
            altraClasse cs = new altraClasse();
            
        }
Ora, dopo che nel contesto dell'altra classe è stato stabilito che l'evento va gestito da una funzione avente la firma definita dall'handler (delegato), in questa classe si sostituisce al delegato una funzione esistente che abbia la stessa firma, ossia Scrivi().
        public static void Main()
        {
            altraClasse cs = new altraClasse();
            cs.Evento += new altraClasse.mioHandler(Scrivi);
            cs.Evoca();
        }
Quindi si evoca l'evento, e funziona.

Bene. Dunque nella classe che esprime l'evento si esprime, tramite il delegato/handler, il tipo di funzione che dovrà gestire l'evento. Punto.
Poi, in un'altra classe, si può verificare l'evento associando all'evento una funzione che abbia la giusta firma.

Spero di aver capito...

domenica 7 dicembre 2014

Array di controlli in C#

Ho realizzato un array di controlli.
Ecco il codice:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Drawing;
namespace Project10
{
    class mioForm:Form
    {
        Button[] bottone;
        public mioForm()
        {
            InitializeComponent();
        }

        public static void Main()
        {
            mioForm frm = new mioForm();
            Application.Run(frm);
            
           
        }
        
        private void InitializeComponent()
        {
           
            bottone = new Button[23];
            this.SuspendLayout();
            for (int n = 0; n < 23; n++)
            {
                bottone[n] = new Button();
                bottone[n].Width = 50;
                bottone[n].Height = 50;
                bottone[n].Left = bottone[n].Width * (n % 5);
                bottone[n].Top = bottone[n].Height * (n / 5);
                bottone[n].Text = (n+1).ToString();
                this.Controls.Add(bottone[n]);
               
            }

            
            this.ClientSize = new System.Drawing.Size(584, 561);
            
            this.Name = "mioForm";
            this.Load += new System.EventHandler(this.mioForm_Load);
            this.ResumeLayout(false);
            this.PerformLayout();

        }

        private void mioForm_Load(object sender, EventArgs e)
        {
           
        }

       

        
    }

}
Resta ancora da vedere come gestire l'evento Click di ciascuno dei controlli, altrimenti che ci faccio?
Per il momento, passo ad altro.

Creazione dal nulla di un'applicazione con un form in C#

Apro un progetto vuoto.
Ci aggiungo i riferimenti (System.Windows.Forms) e li collego al programma;
aggiungo una classe mioForm.cs;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace Project10
{
    class mioForm
    {
    }
}
Adesso faccio ereditare la mia classe dalla classe Form.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace Project10
{
    class mioForm:Form
    {

    }
}
Aggiungo il metodo statico Main();
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace Project10
{
    class mioForm:Form
    {


        public static void Main()
        {

        }
    }
}
Facendo partire questo, ottengo solo una fugace visualizzazione di una console.

Ora dichiaro e istanzio la mia classe derivata da Form, e faccio partire l'applicazione con il mio oggetto:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace Project10
{
    class mioForm:Form
    {


        public static void Main()
        {
            mioForm frm = new mioForm();
            Application.Run(frm);
        }
    }
}
Ottengo una console e un form, che resta lì e devo chiudere con la "crocetta" in alto a destra per terminare l'esecuzione.

Ecco che mi viene fuori un codice generato automaticamente:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace Project10
{
    class mioForm:Form
    {


        public static void Main()
        {
            mioForm frm = new mioForm();
            Application.Run(frm);
        }

        private void InitializeComponent()
        {
            this.SuspendLayout();
            // 
            // mioForm
            // 
            this.ClientSize = new System.Drawing.Size(284, 261);
            this.Name = "mioForm";
            this.Load += new System.EventHandler(this.mioForm_Load);
            this.ResumeLayout(false);

        }

        private void mioForm_Load(object sender, EventArgs e)
        {

        }
    }
}
In più mi viene fuori un errore relativo al Drawing:
Errore 1 Il tipo 'System.Drawing.Size' è definito in un assembly di cui manca il riferimento. Aggiungere un riferimento all'assembly 'System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'. c:\users\antonello\documents\visual studio 2010\Projects\Project10\Project10\mioForm.cs 24 13 Project10
Errore 2 Il tipo o il nome dello spazio dei nomi 'Drawing' non esiste nello spazio dei nomi 'System'; probabilmente manca un riferimento a un assembly c:\users\antonello\documents\visual studio 2010\Projects\Project10\Project10\mioForm.cs 24 42 Project10
Introduco il riferimento a Drawing...

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Drawing;
Adesso funziona di nuovo.
Bene.
Il codice che si genera automaticamente una volta che viene fatto "partire" il form è:
        private void InitializeComponent()
        {
            this.SuspendLayout();
            // 
            // mioForm
            // 
            this.ClientSize = new System.Drawing.Size(284, 261);
            this.Name = "mioForm";
            this.Load += new System.EventHandler(this.mioForm_Load);
            this.ResumeLayout(false);

        }

        private void mioForm_Load(object sender, EventArgs e)
        {

        }
ossia il codice che inizializza il Form.
Però questo codice non viene eseguito all'atto della creazione del form.
Provo a cambiare il tipo di applicazione da "Applicazione Console" a "Applicazione WindowsForm" e ugualmente noto che il codice non viene eseguito, in quanto se cambio i parametri non risultano modificati.
Cambio le dimensioni del form:
        private void InitializeComponent()
        {
            this.SuspendLayout();
            
            // 
            // mioForm
            // 
            this.ClientSize = new System.Drawing.Size(584, 261);
            this.Name = "mioForm";
            this.Load += new System.EventHandler(this.mioForm_Load);
            this.ResumeLayout(false);

        }

        private void mioForm_Load(object sender, EventArgs e)
        {
           
        }
e il form mi viene sempre delle dimensioni standard.
Dunque devo ricreare il costruttore del form e metterci dentro la chiamata a InitializeComponent():
    class mioForm:Form
    {

        public mioForm()
        {
            InitializeComponent();
        }

        public static void Main()
        {
            mioForm frm = new mioForm();
            Application.Run(frm);
        }

        private void InitializeComponent()
        {
            this.SuspendLayout();
            
            // 
            // mioForm
            // 
            this.ClientSize = new System.Drawing.Size(584, 261);
            this.Name = "mioForm";
            this.Load += new System.EventHandler(this.mioForm_Load);
            this.ResumeLayout(false);

        }

        private void mioForm_Load(object sender, EventArgs e)
        {
           
        }

        
    }
e adesso il form mi viene delle nuove dimensioni!


sabato 6 dicembre 2014

Pagina web di riferimento

Il device è quello che dà accesso diretto all'adattatore grafico.
Diretto accesso all'hardware.
Ovviamente, il device va dichiarato.
E su questo non abbiamo problemi.
namespace WindowsFormsApplication12
{
    public partial class Form1 : Form
    {
        private Device device;

        public Form1()
        {
            InitializeComponent();
            
        }

        static void Main()
        {
            
            Application.Run(new Form1());
        }
        private void Form1_Load(object sender, EventArgs e)
        {
        
        }     
    }
}
Bene.
Una volta dichiarato, come per tutte le variabili, bisogna istanziarlo.
Quindi sarà d'obbligo usare qualcosa tipo device = new Device(....).
Vediamo come.
Credo che sia il caso di istanziarlo nel costruttore.
mmmhhh... mi sa che qui viene istanziato nel metodo Main...
Ma andiamo per gradi.
Il costruttore del Device richiede come parametri PresentationParameters, e quindi viene creato un metodo InitializeDevice che setta i parametri e inizializza il device.
        public void InitializeDevice()
        {
            PresentParameters presentparams = new PresentParameters();
            presentparams.Windowed = true;
            presentparams.SwapEffect = SwapEffect.Discard;

            device = new Device(0, DeviceType.Hardware, this, CreateFlags.SoftwareVertexProcessing, presentparams);
        }
Ecco, i parametri vanno inizializzati soltanto relativamente ad "applicazione a finestra", ossia non fullscreen, e a "scartare lo swapeffect", che a quanto ho capito consiste nello scrivere nel dispositivo mediante un buffer che viene presentato a runtime.

Quindi il costruttore del device richiede una serie di parametri, che magari vedo successivamente.
Per il momento mi basta aver dichiarato e istanziato il device con questi due pezzi di codice: la dichiarazione nel contesto delle variabili del form e l'istanziazione (inizializzazione) nel contesto del metodo InitializeDevice().
Ora inserisco il richiamo al metodo InitializeDevice() nel metodo Main() e poi avvio, e funziona.
C'è solo un form, uno stupidissimo form del tutto normale. Però dovrebbe essere stato creato un device.
Mi fido sulla parola!

venerdì 5 dicembre 2014

Ora apro un progetto di tipo Windows Form.
Se ci metto una Main come metodo nel form mi crea casini perché dice che è definito più di un punto di ingresso.
Perché?
Ma ecco: cosa ti vedo? Io creo un nuovo progetto di tipo Windows Form e oltre alla classe Form.cs mi si crea automaticamente una classe Program.cs, in cui è comunque contenuto un metodo Main.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;

namespace WindowsFormsApplication12
{
    static class Program
    {
        /// 
        /// Punto di ingresso principale dell'applicazione.
        /// 
        [STAThread]
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new Form1());
        }
    }
}
E' qui che sta la Main!
E' questo, il punto di ingresso!
Sperimentiamoci sopra...

    static class Program
    {
        /// 
        /// Punto di ingresso principale dell'applicazione.
        /// 
        [STAThread]
        static void Main()
        {
            MessageBox.Show("Ciao, bello");
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new Form1());
        }
    }
Ecco, così facendo prima di mostrarmi il Form mi appare la MessageBox con il messaggio "Ciao, bello".
Da notare che il metodo Main è statico, e anche la classe è statica.
Adesso faccio diversamente e metto il Main nel contesto del Form.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace WindowsFormsApplication12
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        static void Main()
        {
            
            Application.Run(new Form1());
        }
        private void Form1_Load(object sender, EventArgs e)
        {

        }
    }
}
E si apre regolarmente.
Però per far questo devo eliminare l'altro metodo Main che fa parte della classe statica Program.cs.

mercoledì 3 dicembre 2014

Studio dei rudimenti delle classi in C#

Ho aperto un'applicazione tipo Windows Form.
Ecco cosa mi trovo:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace WindowsFormsApplication9
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {

        }
    }
}
Ora, anziché fare iniziare il programma dal Form, voglio farlo iniziare con una Main.
Come fare? Credo che qui si possano solo creare classi...

Ecco, la cosa mi è stata risolta in parte automaticamente.
Se ho una classe da cui far partire il programma, essa dovrà essere static ed essere messa in un modulo a parte che abbia lo stesso nome della classe.
Ecco il modulo inizio.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
using System.Drawing;

namespace WindowsFormsApplication9
{
    static class Program
    {

        static void Main()
        {
            MessageBox.Show("Ciao mondo crudele");
            Form1 ciccio=new Form1();
            ciccio.BackColor = Color.Green;
            Application.Run(ciccio);

        }
    }
}
E questo è il modulo del Form1, Form1.cs:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace WindowsFormsApplication9
{
    partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {

        }
    }

    public class inizio
    {
        void Main()
        {
            MessageBox.Show("Ciao mondo crudele");
        }
    }
}

Il metodo Main della classe inizio.cs istanzia un oggetto di tipo Form1, lo colora di verde e lo mostra dopo aver esibito una MessageBox:
        static void Main()
        {
            MessageBox.Show("Ciao mondo crudele");
            Form1 ciccio=new Form1();
            ciccio.BackColor = Color.Green;
            Application.Run(ciccio);

        }
    }
Cominciamo a "quagliare"...

Brancolando nel buio con il DirectX senza un'adeguata preparazione sul C#

Credo di aver trovato un tutorial piuttosto valido...

Cominciamo a seguirlo, tentando di ricordare e rafforzare il mio approccio di apprendimento...




Per prima cosa, stando al tutorial, devo aprire un progetto di C# tipo Window...
Proviamo...
Fatto.

Ora aggiungiamo i riferimenti.
Fatto.
Inseriamo le linee di codice per l'uso delle librerie referenziate.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Microsoft.DirectX;
using Microsoft.DirectX.Direct3D;

namespace DirectX
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {

        }
    }
}
Bene.
Adesso il tutorial dice di variare le dimensioni del form e il suo nome... giusto a titolo di esercizio.
Facciamolo.
Si fa dal metodo InitializeComponents(). Ora, InitializeComponents viene chiamato dal costruttore del form, ma non è presente sul modulo principale del form, bensì su quello chiamato Designer,dove c'è l'altra parte della partial class del Form...
Lo apro e ce lo trovo...
namespace DirectX
{
    partial class Form1
    {
        /// 
        /// Variabile di progettazione necessaria.
        /// 
        private System.ComponentModel.IContainer components = null;

        /// 
        /// Liberare le risorse in uso.
        /// 
        /// ha valore true se le risorse gestite devono essere eliminate, false in caso contrario.
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }

        #region Codice generato da Progettazione Windows Form

        /// 
        /// Metodo necessario per il supporto della finestra di progettazione. Non modificare
        /// il contenuto del metodo con l'editor di codice.
        /// 
        private void InitializeComponent()
        {
            this.SuspendLayout();
            // 
            // Form1
            // 
            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
            this.ClientSize = new System.Drawing.Size(284, 261);
            this.Name = "Form1";
            this.Text = "Form1";
            this.Load += new System.EventHandler(this.Form1_Load);
            this.ResumeLayout(false);

        }

        #endregion
    }
}
Provo a modificare, in questo metodo, i parametri.
        private void InitializeComponent()
        {
            this.SuspendLayout();
            // 
            // Form1
            // 
            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
            this.ClientSize = new System.Drawing.Size(500, 500);
            this.Name = "Form1";
            this.Text = "Form del cavolo";
            this.Load += new System.EventHandler(this.Form1_Load);
            this.ResumeLayout(false);

        }
Nessun problema...

Adesso mi dice di modificare la Main...

Bene, ho problemi perché avendo aperto un'applicazione tipo Windows non ho una Main...

Retrocediamo e studiamo un po' come si può avere un inizio da una Main che istanzia un form, anziché da un form stesso.

lunedì 1 dicembre 2014

Primi passi con il device (DirectX) in C#

Diamo una definizione di polimorfismo.
Un oggetto di un tipo può assumere valori di un tipo derivato dal suo tipo.
Un parametro di un certo tipo può essere sostituito da un parametro di un tipo derivato.

Dunque quando nel metodo OnPaint di un oggetto di classe derivata da form si mette la parola chiave override questo significa che questo metodo overridda (scavalca) quello della classe base.

Questo OnPaint è un metodo, non un evento.

Ma adesso trovo un codice diverso che non fa uso di OnPaint...

Il nucleo di questo codice è:
        static void Main()
        {
            MioForm frm = new MioForm();
            frm.initGraphics();

            frm.Show();

            while(frm.Created){
            frm.Render();
            Application.DoEvents();
            }
            
        }

La prima riga del metodo non fa altro che istanziare un nuovo frm di classe MioForm la quale è una classe derivata da Form.
Quindi chiama initGraphics che è il metodo nel quale viene creato il device.
        void initGraphics()
        {
            PresentParameters pp = new PresentParameters();
            pp.Windowed = true;
            pp.SwapEffect = SwapEffect.Discard;

            dispositivo = new Device(0, DeviceType.Hardware, this, CreateFlags.SoftwareVertexProcessing, pp);
        }
Quindi si mostra il form, semplicemente:
frm.Show();
e quindi si usa frm.Created.
Che roba è?
Mentre il controllo esiste, si eseguono le successive istruzioni comprese fra parentesi graffe...
Se provo a sostituire while con if, il form sparisce, probabilmente perché la condizione di esistenza del form viene verificata solo una volta.
            while(frm.Created){
            frm.Render();
            Application.DoEvents();
            }


Quindi riassumendo inizialmente si crea il device, quindi si mostra il form e mentre il form esiste si esegue il metodo Render, che "aziona" il device evocandone dei metodi che portano al mostrare il form con certe caratteristiche...

Cominciamo a decifrare...