CODINGSDCC TUT'S PAR STEPHBB75 ★ 3D Tracé points ★

Sdcc - 17 - 3D - Trace PointsCoding Sdcc Tut's Par Stephbb75

3D temps IREEL

Tracé points


On vas se faire ici un programme pour afficher un cube en point, on vas faire comme le programme basic que je vous est présenté juste avant.
J'ai ajouté une fonction GetTime_s qui permet de récupérer le timer du CPC, celui ci augmente de 1 tout les 1/300 de seconde, donc pour avoir le temps en seconde, on divise le nombre affiché par 300.
Voici le programme :

On vas se faire ici un programme pour afficher un cube en point, on vas faire comme le programme basic que je vous est présenté juste avant.
J'ai ajouté une fonction GetTime_s qui permet de récupérer le timer du CPC, celui ci augmente de 1 tout les 1/300 de seconde, donc pour avoir le temps en seconde, on divise le nombre affiché par 300.
Voici le programme :

////////////////////////////////////////////////////////////////////////
// cube1.c
// Affichage d'un cube 3d en point
// VERSION
////////////////////////////////////////////////////////////////////////
#include "conio2.h"
#include
#include

#define KM_WAIT_CHAR_s
    __asm
    call #0xBB06
    __endasm

#define  SCR_SET_MODE1_s
    __asm    ld a,#1
    call #0xBC0E
    __endasm;

typedef struct
{
  long x,y,z;
} point3D;

typedef struct
{
  int x,y;
} point2D;


point3D Sommet[8];   // les sommets du cube
point3D Point3D[8];  // les sommets apres rotation
point2D Point2D[8];  // les sommets apres projection

int Nb_points;

int Xoff;
int Yoff;
int Zoff;

float Sin[360],Cos[360];   /* Tableaux precalcules de sinus et cosinus */
float matrice[3][3];       /* Matrice de rotation 3*3 */

int xa,ya,za;

void PutPixelMode1(int nX, unsigned char nY, unsigned char nColor)
{
  int nPixel = nX % 4;
  unsigned char *pAddress = (unsigned char *)((unsigned int)(0xC000 + ((nY / 8) * 80) + ((nY % 8) * 2048) + (nX / 4)));
   
  if(nPixel == 0)
  {
    *pAddress &= 119;

    if(nColor & 1)
      *pAddress |= 128;
    if(nColor & 2)
      *pAddress |= 8;
  }
  else if(nPixel == 1)
  {
    *pAddress &= 187;

    if(nColor & 1)
      *pAddress |= 64;
    if(nColor & 2)
      *pAddress |= 4;
  }
  else if(nPixel == 2)
  {
    *pAddress &= 221;

    if(nColor & 1)
      *pAddress |= 32;
    if(nColor & 2)
      *pAddress |= 2;
  }
  else //nPixel == 3
  {
    *pAddress &= 238;

    if(nColor & 1)
      *pAddress |= 16;
    if(nColor & 2)
      *pAddress |= 1;
  }
}

void Init_Sinus(void)
{
    int i;
    // pAddress, c'est juste pour faire clignoter un point sur l'ecran, istoire de voire qu'il se passe quelque chose !
    unsigned char *pAddress = (unsigned char *)((unsigned int)0xC004);
    *pAddress = 0xff;
        
    for(i=0;i<360;i++)
    {
        Sin[i]=sinf( (i * 3.1415927 / 180) );
        Cos[i]=cosf( (i * 3.1415927 / 180) );

        *pAddress = !*pAddress;
    }
}


void Rotation(int Xa, int Ya, int Za)
{
  int i;

  // Calcul de la matrice de rotation 3*3
  matrice[0][0] = Cos[Za]*Cos[Ya];
  matrice[1][0] = Sin[Za]*Cos[Ya];
  matrice[2][0] = -Sin[Ya];

  matrice[0][1] = Cos[Za]*Sin[Ya]*Sin[Xa] - Sin[Za]*Cos[Xa];
  matrice[1][1] = Sin[Za]*Sin[Ya]*Sin[Xa] + Cos[Xa]*Cos[Za];
  matrice[2][1] = Sin[Xa]*Cos[Ya];

  matrice[0][2] = Cos[Za]*Sin[Ya]*Cos[Xa] + Sin[Za]*Sin[Xa];
  matrice[1][2] = Sin[Za]*Sin[Ya]*Cos[Xa] - Cos[Za]*Sin[Xa];
  matrice[2][2] = Cos[Xa]*Cos[Ya];


  // Rotation des sommets de l'objet
  for(i=0;i < Nb_points;i++)
  {
    Point3D[i].x =   matrice[0][0]*Sommet[i].x
                   + matrice[1][0]*Sommet[i].y
                   + matrice[2][0]*Sommet[i].z;

    Point3D[i].y =   matrice[0][1]*Sommet[i].x
                   + matrice[1][1]*Sommet[i].y
                   + matrice[2][1]*Sommet[i].z;

    Point3D[i].z =   matrice[0][2]*Sommet[i].x
                   + matrice[1][2]*Sommet[i].y
                   + matrice[2][2]*Sommet[i].z;
  }
}

void Projection(void)
{
  int i;

  for(i=0;i < Nb_points;i++)
  {
    Point2D[i].x=(Point3D[i].x<<8)/(Point3D[i].z+Zoff)+Xoff;
    Point2D[i].y=(Point3D[i].y<<8)/(Point3D[i].z+Zoff)+Yoff;
  }
}

void Initialiser(void)
{
  Sommet[0].x = -100;  Sommet[0].y = -100;  Sommet[0].z = -100;
  Sommet[1].x =  100;  Sommet[1].y = -100;  Sommet[1].z = -100;
  Sommet[2].x =  100;  Sommet[2].y =  100;  Sommet[2].z = -100;
  Sommet[3].x = -100;  Sommet[3].y =  100;  Sommet[3].z = -100;
  Sommet[4].x =  100;  Sommet[4].y = -100;  Sommet[4].z =  100;
  Sommet[5].x = -100;  Sommet[5].y = -100;  Sommet[5].z =  100;
  Sommet[6].x = -100;  Sommet[6].y =  100;  Sommet[6].z =  100;
  Sommet[7].x =  100;  Sommet[7].y =  100;  Sommet[7].z =  100;
}

void DesPoint(unsigned char couleur)
{
unsigned char i;

  for (i=0;i < Nb_points;i++)
  {
    PutPixelMode1(Point2D[i].x, Point2D[i].y, couleur);
  }
}

void Afficher(unsigned char couleur)
{
    // ON EFFACE TOUT
    __asm
        call #0xBBDB
    __endasm;
    
    // On dessine
    // Que les point
    DesPoint(couleur);
}

unsigned char char3,char4;
// donne le temps écoule en 1/300' de seconde depuis l'allumage du CPC
// ou BD10: positionne le compteur interne à une valeur précise
unsigned int GetTime_s()
{
    unsigned int nTime = 0;

    __asm
    CALL #0xBD0D ;KL TIME PLEASE
    PUSH HL
    POP DE
    LD HL, #_char3
    LD (HL), D
    LD HL, #_char4
    LD (HL), E
    __endasm;

    nTime = (char3 << 8) + char4;

    return nTime;
}


void main()
{
    unsigned int nTimeStart = 0;
    unsigned int nTime1 = 0;
    unsigned int nTime2 = 0;

    Nb_points = 8;

    Xoff = 160;
    Yoff = 100;
    Zoff = 600;
 
    //SCR_SET_MODE 1
    __asm
        ld a,#1
        call #0xBC0E
    __endasm;


    nTimeStart = GetTime_s();
    // calcule des table Sin et Cos...
    Init_Sinus();
    nTime1 = GetTime_s() - nTimeStart;  
    gotoxy(1,1);printf("Time calculate Sin/Cos : %d", nTime1);
    KM_WAIT_CHAR_s;

    // initialise les valeurs de lobjet 3D (le cube)
    Initialiser();
    xa=ya=za=0;


    // Animation de note cube jusqu'a pression d'une touche
    while( 1 )
    {
        nTimeStart = GetTime_s();
        Rotation(xa,ya,za);
        Projection();
        nTime1 = GetTime_s() - nTimeStart;

        nTimeStart = GetTime_s();
        Afficher(1);
        nTime2 = GetTime_s() - nTimeStart;

        xa=(xa+2)%360;
        ya=(ya+6)%360;
        za=(za+2)%360;

        gotoxy(1,1);printf("Time calculate 3D : %d", nTime1);
        gotoxy(1,2);printf("Time draw 3D : %d", nTime2);

        if(kbhit())
            break;
    }

    gotoxy(1,20);printf("FIN unetouche pour finir");
    KM_WAIT_CHAR_s;
}

On exécute pour la 1ère fois avec un run"cubep1". Et la on voit un petit point clignoter su l'écran, il est donc en train de calculer les tableaux des Sin et Cos...
et on attend, ... attend...,
et oui c'est long !!
Voici le temps que vas mettre le CPC à calculer ces tableaux :


QUOI, il a mis presque 100 secondes à faire ce calcule !!!!
Oui, on vas optimiser cela alors, d'une façon simple, on vas mettre toute les valeurs dans un fichier que l'on chargeras, cela iras bien plus vite.

Pour l'affichage c'est pareil, on est très loin du temps réel :

  


On voie bien sur les deux première images que l'on met presque 1,5 seconde pour faire le calcule pure, et 0,1 seconde pour effacer et afficher les points !
Pour le calcule, on verra plus tard si on peut y faire quelque chose, on va déjà tenter d'optimiser le temps pour l'afficher.
On commence par l'effacement de l'écran, on va utiliser un CLS qui utilise un détournement de l'utilisation de la pile pour aller plus vite. On ajoute donc la fonction suivante :

// Efface l'ecran en utilisent la pile
// détournéméne de la pile pour faire un cls super rapide !
int PILE;
void CLS_WidthPile()
{
__asm
       DI
       LD           ;(#_PILE),SP
       LD           ;B,#0
       LD           ;SP,#0 ; pile a 0 (car 0 - 1 = 0xFFFF fin de l écran quand il est en 0xC000), comme cela on remonte jusqu a 0xC000
       LD           ;DE,#0
BOUC:   PUSH         ;DE
       PUSH         ;DE
       PUSH         ;DE
       PUSH         ;DE
       PUSH         ;DE
       PUSH         ;DE
       PUSH         ;DE
       PUSH         ;DE
       PUSH         ;DE
       PUSH         ;DE
       PUSH         ;DE
       PUSH         ;DE
       PUSH         ;DE
       PUSH         ;DE
       PUSH         ;DE
       PUSH         ;DE
       PUSH         ;DE
       PUSH         ;DE
       PUSH         ;DE
       PUSH         ;DE
       PUSH         ;DE
       PUSH         ;DE
       PUSH         ;DE
       PUSH         ;DE
       PUSH         ;DE
       PUSH         ;DE
       PUSH         ;DE
       PUSH         ;DE
       PUSH         ;DE
       PUSH         ;DE
       PUSH         ;DE
       PUSH         ;DE
       DJNZ         ;BOUC
       LD           ;SP,(#_PILE)
       EI
       RET
       ;
__endasm;
}

Et dans le fonction Afficher on retirer "// ON EFFACE TOUT " et on le remplace par CLS_WidthPile(); ce qui donne :

void Afficher(unsigned char couleur)
{
    CLS_WidthPile();
    
    // On dessine
    // Que les point
    DesPoint(couleur);
}

On va aussi optimiser le calcule des tableaux Sin Cos avec un chargement des valeurs, on fait un tit programme qui permet de les calculer et de les sauver (vous le trouverez dans le ZIP)
et on modifie notre programme pour charger se fichier en y ajoutant une fonction de chargement de fichier ReadFileBin. On vas aussi utiliser directement la mémoire pour accédé au données des tableaux,
donc modifier la déclaration de ceux ci par la création de pointeurs que l'on initialise dans la main.
Tout ceci est fait dans le fichier cubep2.c qui se trouve dans le ZIP. Une fois compiler voyons ce que cela donne avec un run"cubep2.


Donc pour les tables on passe de plus de 100 secondes à moins de 3 secondes, pas trop mal ;-)
Et pour l'affichage :

  


La on voir que pour l'affichage on passe de 0,1 seconde à 600 millièmes de seconde, belle progression.

Il faudra voire pour optimiser un peut le calcule, mais on verras cela plus tard...

Voila, comme d'hab, le tout se trouve dans se ZIP

stephbb75

★ ANNÉE: 2013
★ AUTEUR: Stephbb75

Page précédente : Sdcc - 16 - 3D - Temps Reel Basic

CPCrulez[Content Management System] v8.7-desktop/cache
Page créée en 080 millisecondes et consultée 930 fois

L'Amstrad CPC est une machine 8 bits à base d'un Z80 à 4MHz. Le premier de la gamme fut le CPC 464 en 1984, équipé d'un lecteur de cassettes intégré il se plaçait en concurrent  du Commodore C64 beaucoup plus compliqué à utiliser et plus cher. Ce fut un réel succès et sorti cette même années le CPC 664 équipé d'un lecteur de disquettes trois pouces intégré. Sa vie fut de courte durée puisqu'en 1985 il fut remplacé par le CPC 6128 qui était plus compact, plus soigné et surtout qui avait 128Ko de RAM au lieu de 64Ko.