Voilà, je débute sur la scène DS :p (avec PAlib pour l'instant, c'est quand même bien pratique !)
Je voulais donc voir comment détecter la pression du stylet, et après quelques recherches infructueuses je décidais de regarder la dsTek...
Puis j'ai découvert ceci : http://forum.gbadev.org/viewtopic.php?t=14396&highlight=pressure
et celà : http://focus.ti.com/lit/ds/symlink/tsc2100.pdf
J'ai aussi découvert l'existence de Stylus.Pressure dans Palib (j'avoue que j'ai mis du temps à le voir celui là :whst:). Mais ce dernier ne me donnait vraiment pas satisfaction côté précision. J'ai fait une petite fonction inspirée de l'aide de Jesse qui marche plutôt bien, la voilà donc :
#define STYLUS_PRESSURE_MIN 60
#define STYLUS_PRESSURE_MAX 90
u8 stylusPressure(void)
{
static u8 pression = STYLUS_PRESSURE_MIN;
u8 pression_new = (IPC->touchX * IPC->touchZ2) / (IPC->touchZ1 << 6) - (IPC->touchX >> 6);
if(Stylus.Held != 1)
{//Si le stylet n'est pas utilisé, on renvoi 0
pression = STYLUS_PRESSURE_MIN;
return 0;
}
//Limitations aux bornes
if(pression_new < STYLUS_PRESSURE_MIN)
pression_new = pression;
if(pression_new > STYLUS_PRESSURE_MAX)
pression_new = STYLUS_PRESSURE_MAX;
//Affaiblissement du mouvement par frame pour éviter les sauts brutaux
if(pression != 0)
pression += (s8)(pression_new - pression) / 2;
else
pression = pression_new;
return (pression - STYLUS_PRESSURE_MIN);
}
La fonction renvoi donc un entier de 0 à 29 :
-0 si pas de contact du stylet
-sinon, plus le chiffre est faible plus la pression est forte
J'ai volontairement laissé Stylus.Pressure tranquille, mais rien de vous empèche de remplacer la variable "pression" par Stylus.Pressure afin de l'utiliser comme le reste de Stylus...
Je vous encourage aussi vivement à calibrer la pression, la valeur min et max pouvant différer selon les consoles et lez zones de l'écran.
Voilà, j'espère que ça pourra servir ^^
Si vous avez des idées d'optimisation ou autre, n'hésitez pas :)
dolarcles
02/02/2008, 12h37
Hé non, jamais utilisé Colors, je suis trop mauvais en dessin. M
Mais je suis surpris car malgré les nombreux jeux auxquels j'ai joué, je n'ai pas mémoire d'une quelconque utilisation de cette possiblité.
Je suis nouveau, donc je ne connais pas vraiment Arialia :p
Arialia a déjà fait quelque chose en rapport avec ça ? (désolé si la question est bête ou quoique ce soit, mais je ne connais réellement aucun d'entre vous ^^)
De toutes façons je pense pouvoir le faire assez rapidement, dès que j'ai un peu de temps :)
Chose promise...
Voilà donc un "calibrateur" qui marche plutôt bien (testé sur deux DS ayant des sensibilités très différentes, sans doute dues aux écrans protecteurs), mais probablement largement perfectionnable...
Voici le fichier "stylet.h"
#define STYLUS_PRESSURE_MIN 55
#define STYLUS_PRESSURE_MAX 95
#define STYLUS_PRESSURE_DIF 40
typedef struct
{
u32 pressionMin : 8;//127 max
u32 pressionMax : 8;
u32 checkMin : 1;
u32 checkMax : 1;
u32 coefMin : 7;//Plus le coefficient est élevé, plus la valeur est fiable
u32 coefMax : 7;
float32 taux;
} pressionEcran;
pressionEcran etat_ecran[32][24];
u8 stylusPressureRough(void)
{//Pression système initiale (approximative)
static u8 pression = 0;
u8 pressionNew;
pressionNew = (IPC->touchX * IPC->touchZ2) / (IPC->touchZ1 << 6) - (IPC->touchX >> 6);
/*Affaiblissement du mouvement par frame pour éviter les sauts brutaux
et les différences trop importantes entre les zones*/
if(pression != 0)
pression += (s8)(pressionNew - pression) / 3;
else
pression = pressionNew;
return pression;
}
u8 stylusPressure(void)
{//Version avec calibrage
static u8 pression = STYLUS_PRESSURE_MIN;
u8 pressionNew = (IPC->touchX * IPC->touchZ2) / (IPC->touchZ1 << 6) - (IPC->touchX >> 6);
u8 x = IPC->touchXpx / 8, y = IPC->touchYpx / 8;
if(Stylus.Held != 1)
{//Si le stylet n'est pas utilisé, on renvoi 0
pression = STYLUS_PRESSURE_MIN;
return 0;
}
//Limitations aux bornes
if(pressionNew < etat_ecran[x][y].pressionMin)
pressionNew = pression;
if(pressionNew > etat_ecran[x][y].pressionMax)
pressionNew = etat_ecran[x][y].pressionMax;
//Affaiblissement du mouvement par frame pour éviter les sauts brutaux
if(pression != 0)
pression += (s8)(pressionNew - pression) / 2;
else
pression = pressionNew;
//Mise en place du taux
return (u8)((float32)(pression - etat_ecran[x][y].pressionMin) * (float32)etat_ecran[x][y].taux);
}
u8 stylusPressureOld(void)
{//Ancienne version, sans calibrage
static u8 pression = STYLUS_PRESSURE_MIN;
u8 pressionNew = (IPC->touchX * IPC->touchZ2) / (IPC->touchZ1 << 6) - (IPC->touchX >> 6);
if(Stylus.Held != 1)
{//Si le stylet n'est pas utilisé, on renvoi 0
pression = STYLUS_PRESSURE_MIN;
return 0;
}
//Limitations aux bornes
if(pressionNew < STYLUS_PRESSURE_MIN)
pressionNew = pression;
if(pressionNew > STYLUS_PRESSURE_MAX)
pressionNew = STYLUS_PRESSURE_MAX;
//Affaiblissement du mouvement par frame pour éviter les sauts brutaux
if(pression != 0)
pression += (s8)(pressionNew - pression) / 2;
else
pression = pressionNew;
return (pression - STYLUS_PRESSURE_MIN);
}
void initialisePressure(void)
{//Initialise les valeurs de pression
u8 i, j;
for(i = 0; i < 32; i++)
{
for(j = 0; j < 24; j++)
{
etat_ecran[i][j].pressionMin = STYLUS_PRESSURE_MAX;//valeur absurde pour être modifiée
etat_ecran[i][j].pressionMax = STYLUS_PRESSURE_MIN;
etat_ecran[i][j].checkMin = 0;
etat_ecran[i][j].checkMax = 0;
etat_ecran[i][j].coefMin = 0;
etat_ecran[i][j].coefMax = 0;
etat_ecran[i][j].taux = 1.0;
}
}
}
void adjustPressure(void)
{//Passe à une différence de STYLUS_PRESSURE_DIF si possible, sinon fixe un taux
u8 i, j;
for(i = 0; i < 32; i++)
{
for(j = 0; j < 24; j++)
{
//Valeurs par défaut si nécessaire
if(etat_ecran[i][j].checkMin == 0)
etat_ecran[i][j].pressionMin = STYLUS_PRESSURE_MIN;
if(etat_ecran[i][j].checkMax == 0)
etat_ecran[i][j].pressionMax = STYLUS_PRESSURE_MAX;
//Ajustement des valeurs
if((etat_ecran[i][j].pressionMax - etat_ecran[i][j].pressionMin) > STYLUS_PRESSURE_DIF)
{//On réduit l'écart à STYLUS_PRESSURE_DIF si possible
etat_ecran[i][j].pressionMax = etat_ecran[i][j].pressionMin + STYLUS_PRESSURE_DIF;
}
else if((etat_ecran[i][j].pressionMax - etat_ecran[i][j].pressionMin) < STYLUS_PRESSURE_DIF)
{//Sinon on calcule un multiplicateur
etat_ecran[i][j].taux = (float32)STYLUS_PRESSURE_DIF / (float32)(etat_ecran[i][j].pressionMax - etat_ecran[i][j].pressionMin);
}
}
}
}
void adjustPressureXY(u8 x, u8 y)
{
//Ajustement des valeurs
if((etat_ecran[x][y].pressionMax - etat_ecran[x][y].pressionMin) > STYLUS_PRESSURE_DIF)
{//On réduit l'écart à STYLUS_PRESSURE_DIF si possible
etat_ecran[x][y].pressionMax = etat_ecran[x][y].pressionMin + STYLUS_PRESSURE_DIF;
etat_ecran[x][y].taux = 1.0;
}
else if((etat_ecran[x][y].pressionMax - etat_ecran[x][y].pressionMin) < STYLUS_PRESSURE_DIF)
{//Sinon on calcule un multiplicateur
etat_ecran[x][y].taux = (float32)STYLUS_PRESSURE_DIF / (float32)(etat_ecran[x][y].pressionMax - etat_ecran[x][y].pressionMin);
}
}
void updatePressure(void)
{
u8 x, y, pression;
x = IPC->touchXpx / 8;
y = IPC->touchYpx / 8;
if(Stylus.Held == 1)
{
x = IPC->touchXpx / 8;
y = IPC->touchYpx / 8;
pression = stylusPressureRough();
if(((etat_ecran[x][y].coefMax < 127) && (pression > etat_ecran[x][y].pressionMax)) || (etat_ecran[x][y].checkMax == 0))
{
etat_ecran[x][y].pressionMax = pression;
etat_ecran[x][y].checkMax = 1;
etat_ecran[x][y].coefMax++;
adjustPressureXY(x, y);
// etat_ecran[x][y].taux = (float32)STYLUS_PRESSURE_DIF / (float32)(etat_ecran[x][y].pressionMax - etat_ecran[x][y].pressionMin);
}
else if(((etat_ecran[x][y].coefMin < 127) && (pression > 30) && (pression < etat_ecran[x][y].pressionMin)) || (etat_ecran[x][y].checkMin == 0))
{
etat_ecran[x][y].pressionMin = pression;
etat_ecran[x][y].checkMin = 1;
etat_ecran[x][y].coefMin++;
adjustPressureXY(x, y);
// etat_ecran[x][y].taux = (float32)STYLUS_PRESSURE_DIF / (float32)(etat_ecran[x][y].pressionMax - etat_ecran[x][y].pressionMin);
}
}
}
void checkWeakPressure(void)
{//Prend les valeurs de la pression la plus faible
u8 i, j, x, y, pression;
while(Pad.Newpress.A != 1)
{
if(Stylus.Held == 1)
{
x = IPC->touchXpx / 8;
y = IPC->touchYpx / 8;
pression = stylusPressureRough();
if(pression > 70)
{
etat_ecran[x][y].pressionMax = (etat_ecran[x][y].pressionMax > pression)?(etat_ecran[x][y].pressionMax):(pression);
if(etat_ecran[x][y].coefMax < 127)
etat_ecran[x][y].coefMax++;
if(etat_ecran[x][y].checkMax == 0)
{
etat_ecran[x][y].checkMax = 1;
}
}
PA_OutputText(1, 0, 12, "Pression : %03d", pression);
}
for(i = 0; i < 24; i++)
{
for(j = 0; j < 32; j++)
{
PA_OutputText(0, j, i, "%d", etat_ecran[j][i].checkMax);
}
}
PA_WaitForVBL();
}
}
void checkStrongPressure(void)
{//Prend les valeurs de la pression la plus forte
u8 i, j, x, y, pression;
while(Pad.Newpress.B != 1)
{
if(Stylus.Held == 1)
{
x = IPC->touchXpx / 8;
y = IPC->touchYpx / 8;
pression = stylusPressureRough();
if(pression > 30)
{
etat_ecran[x][y].pressionMin = (etat_ecran[x][y].pressionMin <= pression)?(etat_ecran[x][y].pressionMin):(pression);
if(etat_ecran[x][y].coefMin < 127)
etat_ecran[x][y].coefMin++;
if(etat_ecran[x][y].checkMin == 0)
{
etat_ecran[x][y].checkMin = 1;
}
}
PA_OutputText(1, 0, 12, "Pression : %03d", pression);
}
for(i = 0; i < 24; i++)
{
for(j = 0; j < 32; j++)
{
PA_OutputText(0, j, i, "%d", etat_ecran[j][i].checkMin);
}
}
PA_WaitForVBL();
}
}
et "main.c"
#include <PA9.h> // Include pour PA_Lib
#include "stylet.h"
#include <stdlib.h>
int main(void)
{
u8 pression;
u8 x, y, checkPressure = 0;
PA_Init(); // Initialisation de la PA_Lib
PA_InitVBL(); // Initialisation d'un VBL standard
PA_InitText(0, 0);
PA_InitText(1, 0);
PA_SetTextCol(0, 0, 31, 0);
PA_SetTextCol(1, 24, 24, 24);
initialisePressure();//Important pour la calibration !
while(1)
{
if(checkPressure == 0)
{
PA_OutputSimpleText(1, 0, 5, "Test de la pression minimale");
PA_OutputSimpleText(1, 0, 7, "Passez le stylet doucement sur");
PA_OutputSimpleText(1, 0, 8, "tout l'écran jusqu'à n'avoir");
PA_OutputSimpleText(1, 0, 9, " plus que des 1");
PA_OutputSimpleText(1, 0, 11, "('A' pour quitter)");
checkWeakPressure();
PA_OutputSimpleText(1, 0, 5, "Test de la pression maximale");
PA_OutputSimpleText(1, 0, 7, "Passez le stylet fortement sur");
PA_OutputSimpleText(1, 0, 8, "tout l'écran jusqu'à n'avoir");
PA_OutputSimpleText(1, 0, 9, " plus que des 1");
PA_OutputSimpleText(1, 0, 11, "('B' pour quitter)");
checkStrongPressure();
adjustPressure();
PA_OutputSimpleText(1, 0, 5, " ");
PA_OutputSimpleText(1, 0, 7, " ");
PA_OutputSimpleText(1, 0, 8, " ");
PA_OutputSimpleText(1, 0, 9, " ");
PA_OutputSimpleText(1, 0, 11, " ");
checkPressure = 1;
}
PA_OutputSimpleText(1, 0, 5, " ");
PA_OutputSimpleText(1, 0, 7, " ");
PA_OutputSimpleText(1, 0, 8, " ");
PA_OutputSimpleText(1, 0, 9, " ");
PA_OutputSimpleText(1, 0, 11, " ");
PA_OutputText(1, 0, 10, "Pression Init : %03d", Stylus.Pressure);
pression = stylusPressure();
x = IPC->touchXpx / 8;
y = IPC->touchYpx / 8;
PA_OutputText(1, 0, 11, "Pression Opt : %03d", pression);
PA_OutputText(1, 0, 12, "Pression Old : %03d", stylusPressureOld());
PA_OutputText(1, 0, 13, "Min : %03d\t\tMax : %03d", etat_ecran[x][y].pressionMin, etat_ecran[x][y].pressionMax);
PA_OutputText(1, 0, 14, "Coef : Min : %03d\tMax : %03d", etat_ecran[x][y].coefMin, etat_ecran[x][y].coefMax);
PA_OutputText(1, 0, 15, "Taux : %f3", etat_ecran[x][y].taux);
updatePressure();
PA_WaitForVBL();
}
return (EXIT_SUCCESS);
}
Vous pouvez donc lancer la calibration à part avec checkWeakPressure(), checkStrongPressure() puis adjustPressure(), et/ou avoir une calibration constante (qui s'affine lors de l'execution de programme) avec updatePressure().
Y'a un bug d'affichage sur le taux, si quelqu'un sait pourquoi, merci :p
Sinon, la valeur retournée oscille maintenant entre 0 et 40, mais parfois un peu plus j'ai cru remarquer (sans doute à cause des arrondis des floats). Aussi, une forte pression peut maintenant renvoyer 0, donc n'utilisez ces fonctions que pour ce pour quoi elles ont été crées ;)
Enfin, si quelqu'un voit un bug ou quoi que ce soit de bizarre, n'hésitez pas à le signaler :) J'ai peut-être fait ça un peu vite, il y a donc pas mal de chances pour qu'il y ait un ou deux bugs ^^'
P.S : les fonctions necessitent PAlib, mais pas dans leurs fonctionnements même, uniquement pour l'affichage... Donc si quelqu'un passant dans le coin ayant une bonne connaissance du bas niveau pour DS a une soudaine envie de transformer ça pour que ce soit portable, merci d'avance :D C'est que pour l'instant je ne connais que PAlib >_<
Edith me dit de vous dire que vous pouvez réduire le "jumping" du stylet en augmentant la valeur du dénominateur à la ligne "pression += (s8)(pressionNew - pression) / 2;" dans la fonction "stylusPressure". Ça pourra être bien plus confortable mais du coup, la fonction aura plus de mal à renvoyer les valeurs extrèmes.
vBulletin® v.3.7.2, Copyright ©2000-2008, Jelsoft Enterprises Ltd. Tous droits réservés - Version française vbulletin-fr.org