|
|
|
|
|
Le site de Steph : Le CPC |
|
|
|
|
|
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 :
////////////////////////////////////////////////////////////////////////
// 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 ecran 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
|
|
|
|
|