gint : un noyau pour développer des add-ins
Posté le 20/02/2015 17:30
Ce topic fait partie de la série de topics du fxSDK.
En plus des options de programmation intégrée comme le Basic Casio ou Python, la plupart des calculatrices Casio supportent des
add-ins, des programmes natifs très polyvalents avec d'excellentes performances. Les add-ins sont généralement programmés en C/C++ avec l'aide d'un ensemble d'outils appelé SDK.
Plusieurs SDK ont été utilisés par la communauté avec le temps. D'abord le
fx-9860G SDK de Casio avec fxlib pour Graph monochromes (plus maintenu depuis longtemps). Puis le
PrizmSDK avec libfxcg pour Prizm et Graph 90+E (encore un peu actif sur Cemetech). Et plus récemment celui que je maintiens, le
fxSDK, dont gint est le composant principal.
gint est un unikernel, ce qui veut dire qu'il embarque essentiellement un OS indépendant dans les add-ins au lieu d'utiliser les fonctions de l'OS de Casio. Ça lui permet beaucoup de finesse sur le contrôle du matériel, notamment la mémoire, le clavier, l'écran et les horloges ; mais aussi de meilleures performances sur le dessin, les drivers et la gestion des interruptions, plus des choses entièrement nouvelles comme le moteur de gris sur Graph monochromes.
Les sources de gint sont sur la forge de Planète Casio :
dépôt Gitea Lephenixnoir/gint
Aperçu des fonctionnalités
Les fonctionnalités phares de gint (avec le fxSDK) incluent :
- Toutes vos images et polices converties automatiquement depuis le PNG, sans code à copier (via fxconv)
- Un contrôle détaillé du clavier, avec un GetKey() personnalisable et un système d'événements à la SDL
- Une bibliothèque standard C plus fournie que celle de Casio (voir fxlibc), et la majorité de la bibliothèque C++
- Plein de raccourcis pratiques, comme pour afficher la valeur d'une variable : dprint(1,1,"x=%d",x)
- Des fonctions de dessin, d'images et de texte optimisées à la main et super rapides, surtout sur Graph 90+E
- Des timers très précis (60 ns / 30 µs selon les cas, au lieu des 25 ms de l'OS), indispensables pour les jeux
- Captures d'écran et capture vidéo des add-ins par USB, en temps réel (via fxlink)
Avec quelques mentions spéciales sur les Graph monochromes :
Un moteur de gris pour faire des jeux en 4 couleurs !
La compatibilité SH3, SH4 et Graph 35+E II, avec un seul fichier g1a
Une API Unix/POSIX et standard C pour accéder au système de fichiers (Graph 35+E II seulement)
Et quelques mentions spéciales sur les Graph 90+E :
Une nouvelle police de texte, plus lisible et économe en espace
Le dessin en plein écran, sans les bordures blanches et la barre de statut !
Un driver écran capable de triple-buffering
Une API Unix/POSIX et standard C pour accéder au système de fichiers
Galerie d'add-ins et de photos
Voici quelques photos et add-ins réalisés avec gint au cours des années !
Arena (2016) — Plague (2021)
Rogue Life (2021)
Momento (2021)
Communication avec le PC (cliquez pour agrandir)
Utiliser gint pour développer des add-ins
Les instructions pour installer et utiliser gint sont données dans les divers tutoriels recensés dans le
topic du fxSDK. Il y a différentes méthodes de la plus automatique (GiteaPC) à la plus manuelle (compilation/installation de chaque dépôt). Le fxSDK est compatible avec Linux, Mac OS, et marche aussi sous Windows avec l'aide de WSL, donc normalement tout le monde est couvert
Notez en particulier qu'il y a des
tutoriels de développement qui couvrent les bases ; tout le reste est expliqué dans les en-têtes (fichiers
.h) de la bibliothèque que vous pouvez
consulter en ligne, ou dans les ajouts aux changelogs ci-dessous.
Changelog et informations techniques
Pour tester les fonctionnalités et la compatibilité de gint, j'utilise un add-in de test appelé gintctl (
dépôt Gitea Lephenixnoir/gintctl). Il contient aussi une poignée d'utilitaires d'ordre général.
Ci-dessous se trouve la liste des posts indiquant les nouvelles versions de gint, et des liens vers des instructions/tutoriels supplémentaires qui accompagnent ces versions.
Anecdotes et bugs pétés
Ô amateurs de bas niveau, j'espère que vous ne tomberez pas dans les mêmes pièges que moi.
TODO list pour les prochaines versions (2023-04-03)
gint 2.11
- Changements de contextes CPU. À reprendre du prototype de threading de Yatis pour permettre l'implémentation d'un véritable ordonnanceur. Demandé par si pour faire du threading Java.
- Applications USB. Ajouter le support de descripteurs de fichiers USB. Potentiellement pousser jusqu'à avoir GDB pour debugger.
- Support de scanf() dans la fxlibc. Codé par SlyVTT, plus qu'à nettoyer et fusionner.
Non classé
- Regarder du côté serial (plus facile que l'USB) pour la communication inter-calculatrices (multijoueur) et ultimement l'audio (libsnd de TSWilliamson).
- Un système pour recompiler des add-ins mono sur la Graph 90+E avec une adaptation automatique.
- Support des fichiers en RAM pour pouvoir utiliser l'API haut-niveau sur tous les modèles et éviter la lenteur de BFile à l'écriture quand on a assez de RAM.
Citer : Posté le 20/06/2020 22:37 | #
Aha RIP. Ça m'est arrivé une fois aussi, j'ai tout recompilé dans le doute. Sinon tu fous des liens symboliques pour tout le monde non ?
Ajouté le 20/06/2020 à 23:06 :
J'ai poussé sur la branche dev une modification de la fonction timer_setup() qui permet de configurer les timers. Je sais que c'est un point compliqué pour pas mal de gens, donc j'ai essayer de simplifier ça sans casser le code qui veut exploiter toute la puissance du système.
La nouvelle fonction a un prototype largement plus simple avec seulement trois arguments obligatoires :
• Le timer que vous voulez utiliser (vous pouvez aussi laisser gint en choisir un)
• Le délai en micro-secondes
• La fonction à appeler une fois le délai écoulé
Modification 1 : plus besoin de gérer les numéros de timers. En général vous vous en foutez pas mal de savoir qui est un TMU et qui est un ETMU, disponible ou pas, et si la précision est de 0.3 ms ou 0.3 µs. Et en général perso j'ai pas envie de traquer quel timer j'ai utilisé à quel endroit. Et donc on peut simplifier les deux situations en mettant TIMER_ANY en premier argument. gint se charge de trouver un timer disponible qui est capable d'attendre le délai que vous demandez.
int timer = timer_setup(TIMER_ANY, 25000, f);
if(timer >= 0) timer_start(timer);
Évidemment il faut quand même vérifier qu'un timer libre existe bel et bien; timer_setup() renvoie -1 si aucun timer n'est disponible pour répondre à votre demande.
Modification 2 : le délai directement en micro-secondes. Mais si vous voulez utiliser explicitement un timer par son ID, le délai est traité comme une valeur de TCOR, comme avant (utile pour libprof et le moteur de gris, notamment). Mais bon les power users peuvent lire le header, je détaille pas ici.
Modification 3 : plus de type bizarre sur les fonctions de callback . Grâce à de la magie noire de GCC, timer_setup() accepte différents types de callbacks, notamment int f(void) (aucun argument). Dans ce cas vous n'êtes pas obligés de passer un argument à timer_setup(). Le callback peut avoir au plus un argument qui doit forcément être de 4 octets (en gros : un entier ou un pointeur).
int f(void) { ... return TIMER_STOP; }
int timer = timer_setup(TIMER_ANY, 25000, f);
if(timer >= 0) timer_start(timer);
/* Exécuter g(5) dans 25 ms */
int g(int x) { ... x ... return TIMER_STOP; }
int timer = timer_setup(TIMER_ANY, 25000, g, 5);
if(timer >= 0) timer_start(timer);
Comme avant le callback doit renvoyer un entier indiquant au timer s'il doit continuer à tourner ou s'arrêter. Mais au lieu de 0 et 1, ils s'appellent maintenant TIMER_CONTINUE et TIMER_STOP, ce qui est quand même plus agréable.
Pour adapter votre code. La plupart des appels à timer_setup() jusque-là avaient cette forme :
La façon safe de transposer ça dans la nouvelle API sans risquer de problème est ceci :
Mais ça c'est que si vous voulez utiliser explicitement le timer <id>. Si au fond n'importe quel timer vous convient, vous pouvez utiliser TIMER_ANY et dans de cas gint calculer timer_delay() pour vous. Votre code devient :
Enfin si votre callback ne prend au fond pas d'argument (avant vous étiez obligés d'en avoir un de type volatile void *), vous pouvez le retirer (votre callback et alors de type int callback(void)) et ne plus le passer à timer_setup(). Votre code devient :
Voilà, j'espère que ça vous simplifiera les choses pour aborder tranquillement les timers sans maux de tête. J'ai fait de mon mieux pour garder l'API proche de l'ancienne version pour que les changements soient faciles pour vous.
Ajouté le 29/06/2020 à 21:32 :
Je continue à bosser sur la prochaine release. Actuellement, j'essaie de rendre gint compatible avec l'émulateur officiel Graph 90+E. La plupart des choses semblent fonctionner, mais l'affichage à l'écran non (ce qui rend difficile le test dans la plupart des cas !).
J'ai déjà déterminé que la méthode naïve pour afficher des données (envoyer chaque pixel à l'écran par l'action du CPU) fonctionne, seule la méthode DMA semble échouer. Je vais voir ce que je peux trouver là-dessus, au pire cas je peux toujours utiliser la méthode naïve car les problèmes de performance ne sont pas aussi intéressants sur l'émulateur que sur la calculatrice.
S'il s'est passé un bon moment depuis la dernière update (9 jours) c'est qu'en décortiquant l'émulateur j'ai trouvé plein d'infos intéressants sur le SH7305 et j'ai pris un moment pour évaluer les conséquences sur le reverse-engineering du matériel avec Yatis.
Ajouté le 02/07/2020 à 11:21 :
J'ai progressé. En fait je crois que sur la calculatrice la RAM est à 8c000000 (ou ac000000) tandis que sur l'émulateur elle est à 88000000 (ou 8c000000). La preuve c'est que je me sers de cette méthode pour différencier Prizm et Graph 90+E et l'émulateur est détecté comme une Prizm ! De plus, les problèmes d'affichage n'étaient pas liés au DMA mais au fait que j'utilisais une zone de RAM qui n'existait pas (puisque pas au bon endroit dans la RAM).
Il est donc possible que l'émulateur est la Graph 90+E n'utilisent pas tout à fait le même OS. Ça mérite d'être étudié.
Ajouté le 02/07/2020 à 16:08 :
Alright, donc grâce aux mécanismes de compatibilité Prizm de gint, la transition vers l'émulateur s'est faite sans problème. Le fx-CG Manager de Casio est désormais officiellement une platforme supportée par gint
Je pense que c'est le bon moment pour tester sur Prizm aussi.
--
Sentaro21, a couple months ago you mentioned that you might be able to test the project on fx-CG 20. If you can still do it, please download the test application gintctl.g3a (you will need to rename it).
The application has many tests but I'm interested in the following information in the GINT tab:
• In "Hardware", the "MPU/CPU" page should show "Calculator model: Prizm fx-CG 20"
• In "Memory dump", you should be able to press F3 then F6 to dump some of the RS RAM to a file called RS00.bin without a crash
• In "Switch to OS", you shoud be able to press F1 (SWITCH) repeatedly without a crash, and you should also be able to press F3 (MENU) to switch between the main menu and the add-in.
• In "TLB management", pressing F5 (MISS) and F6 (TIMER) should map new pages (more squares should be green).
• In "Timers", you should see TMU2 and ETMU5 running, and pressing F1 (SLEEP) sould make TMU0 run for about a second
Finally, in the MEMORY tab of the main menu, you should be able to press F3 (ROM) then Up and have a red "TLB error" on screen.
Because it works on fx-CG 50 and in the fx-CG Manager which behaves like an fx-CG 20, I am confident this will work.
Citer : Posté le 04/07/2020 10:28 | #
Hello, une date de realease en vu pour une version 2 stable ? De ce que j'ai compris elle est quasiment prête t'es en train de faire quelques petits correctifs ?
Pourras-tu survivre plus de 20 secondes dans ce fameux tunnel appelé Graviton
Rebondis entre les murs en évitant les piques dans SpikeBird
Pourras-tu éviter de te faire écraser dans FallBlocs (élu Jeu Du Mois)
La version 2048 tactile amélioré au plus haut point : 2048 Delux !
Pars à la recherche des morceaux d'étoile dans Lumyce (élu Jeu Du Mois)
Citer : Posté le 04/07/2020 11:02 | #
Yo ! Donc en effet je suis en bêta là, la plus récente étant la 2.0.2-beta.
Voilà la TODO list des features avant la fameuse 2.1 que je tease depuis un moment :
• Faire les fonctions de mémoire optimisées : memcpy, memcmp, memset, et pour memmove je reste naïf (je suis là tout de suite dessus) [4]
• Supporter la Prizm fx-CG 20, normalement c'est bon j'attends juste un test (non bloquant pour la 2.1)
• Double-buffer les paramètres du moteur de gris (en gros : activation frame-perfect du moteur) [2-3]
• Supporter les polices Unicode dans topti (pour uf5x7 et virer les anciens charsets) [2-3]
• Gérer le spread spectrum sur Graph 90+E, les timers sont pas tout à fait précis actuellement [1]
• Ajouter une valeur de retour de main() qui permet de revenir au menu au lieu de quitter l'add-in et donc de revenir [1]
Voici les choses que je dois casser :
• Supprimer image_t qui a été renommé bopti_image_t par clarté
• Supprimer la branche compat, maintenant tout le monde doit utiliser master ou dev
• Unifier les fonctions g*() avec les d*() ; vu que le moteur de gris est double-buffer, plus besoin de séparer [2]
Et voici des choses qui iront dans les releases suivantes :
• Système de fichiers propre
• Overclock
• Musique avec la méthode de TSWilliamson
• Communication série et USB
• Jouer avec le DSP, si ça peut aider
J'ai mis entre crochets une estimation du nombre d'heures pour faire marcher les points principaux. Le temps que j'arrive à passer sur gint est assez instable cette semaine mais j'espère pousser la release à la fin de la semaine prochaine ou au début de la semaine suivante, donc autour du 12-14 Juillet.
Citer : Posté le 04/07/2020 16:04 | #
C'est quoi le truc du double buffer ? ça va améliorer le moteur de gris ?
Le retour au menu c'est une grande première dans les Add-In haha !
C'est cool pour la branche master ça fait plus propre .
Les release suivante sont dans l'ordre ou pas là ? Car je pense que la communication est assez importante comparé aux autres.
Okay bon, tkt si ça prend un mois c'est pas grave c'est déjà ouf ce que tu produis !
Pourras-tu survivre plus de 20 secondes dans ce fameux tunnel appelé Graviton
Rebondis entre les murs en évitant les piques dans SpikeBird
Pourras-tu éviter de te faire écraser dans FallBlocs (élu Jeu Du Mois)
La version 2048 tactile amélioré au plus haut point : 2048 Delux !
Pars à la recherche des morceaux d'étoile dans Lumyce (élu Jeu Du Mois)
Citer : Posté le 04/07/2020 22:01 | #
C'est quoi le truc du double buffer ? ça va améliorer le moteur de gris ?
En gros quand tu fais gray_start() ou gray_stop(), au lieu d'activer ou de désactiver le moteur de gris tout de suite, ça ne le modifie qu'au prochain dupdate(). Comme ça tu as le temps de pousser ton premier frame en gris (ou ton premier frame mono après l'arrêt du moteur de gris) sans risquer que des VRAMs impropres s'affichent brièvement.
Ouh là non c'est pas encore un plan tout ça ! Une partie de ces choses dépend de résultats de reverse-engineering qu'on est encore en train d'établi donc c'est vraiment dur de donner une estimation.
Merci ! Ça devrait pas prendre un mois quand même. Je me suis débarrassé des fonctions de mémoire tout à l'heure.
Ajouté le 06/07/2020 à 18:24 :
J'ai trouvé des problèmes bizarres sur le retour au menu, en particulier sur SH3, donc j'enquête. Je reprendrai les ajustements sur le moteur de gris quand j'aurai trouvé.
Citer : Posté le 07/07/2020 12:58 | #
Hi, are there any plans to implement some standard math library functions? I would use the newlib port but I can't find any working repos for it (I did manage to implement the cosine function I needed in my code).
Citer : Posté le 07/07/2020 20:45 | #
Maybe you can look at the Memallox' port of Newlib : https://gitea.planet-casio.com/PlaneteCasio/libc
I do not know if it includes math functions, but it's definitely the more complete project of a libc on Casio calcs
Citer : Posté le 08/07/2020 02:56 | # | Fichier joint
That refuses to build for some reason, the compiler finds errors in /libc/newlib/libc/include/ieeefp.h and stops. I don't know enough to try messing around with the header and fix them, I've attached a text file containing the output.
EDIT: Adding a
EDIT 2: Hooray! After adding -lm to the compiler flags for the addin everything seems to be working perfectly! Thanks for the link to the repo, all the ones I could find were dead.
Citer : Posté le 08/07/2020 09:34 | #
You're welcome
If you think your patch is clean enough to be integrated to the code repository, we'll pleased to create you an account on the Gitea, so you can post a merge request. Maybe you can add some notes/hints too.
Citer : Posté le 08/07/2020 14:32 | #
Unfortunately, unless someone can reproduce it, I can't be sure if it was a missing define somewhere or if I messed up earlier building the bootstrap GCC.
I do think the newlib/gcc tutorials should say that '-lm' needs to be added to the compiler options (or in the fxSDK project config) when compiling an addin for the math library to be linked, I was worried for a bit that I didn't build newlib/gcc properly
Citer : Posté le 08/07/2020 16:47 | #
Interesting, I didn't have this problem when building the library. I did experience some crashes with core memory functions like memcpy() using this port (that did not appear with naive implementations), so if you encounter trouble know that newlib might (?) be in fault.
My stance on the standard library is not very clear yet. I wanted to use this newlib port at some point but Memallox has unfortunately not developed it for a while. gint currently provides a couple optimized memory and string functions but I haven't yet gone all the way and implemented the whole set.
As for the math library, I think we can at least port an independent libm as the Prizm SDK does (although it ships libm.a directly without explaining how to build it so it's not that useful). Just for completeness, you can find that file here (I don't know whether there is an official PrizmSDK repository so I pointed to TSWilliamson's personal version - the binary libraries should be the same).
Hope this helps clarify the situation. Also, thanks for your interest in this project
Ajouté le 08/07/2020 à 17:29 :
J'ai trouvé des problèmes bizarres sur le retour au menu, en particulier sur SH3, donc j'enquête. Je reprendrai les ajustements sur le moteur de gris quand j'aurai trouvé.
J'ai continué et j'ai trouvé... pas mal de problèmes sur SH3, wow. Ils sont apparus avec le changement de l'API timer mais ça n'a pas vraiment de raison d'être lié. Visiblement la zone dans laquelle j'installe la VBR et la mémoire mappée de gint est vraiment pas fiable. Il faut que je voie au plus vite si je peux m'en débarrasser, même si c'est pas gagné. En gros j'ai besoin d'une zone non virtualisée dans P1 ou P2 pour avoir la VBR et une poignée de fonctions auxiliaires. Une fois les trivialités éliminées, en gros il me faut une zone de RAM d'environ 8k. Pour l'instant j'étudie mes options, je vous tient au courant.
Ajouté le 10/07/2020 à 11:56 :
Okay donc petite explication de ce qui se passe ici. Il y a grosso modo 3 types de mémoire sur la calto : la ROM, la RAM, et la mémoire on-chip. Quand on lance un add-in, on a le code dans la ROM et les données dans la RAM. Pour accéder à la ROM et à la RAM, normalement on utilise des adresses "absolues" qui accèdent exactement à l'octet qu'on demande.
Cela pose deux problèmes pour les add-ins. D'une part le code est dans le fichier g1a/g3a, qui est fragmenté dans la ROM, donc il n'est pas continu (l'instruction qui suit l'instruction actuelle peut être à l'autre bout de la ROM). D'autre part la zone de RAM que l'OS nous donne n'est pas au même endroit ni de la même taille d'une version de l'OS à l'autre. Tout cela fait qu'il est quasi-impossible de savoir où le code et les données sont.
Pour pallier à ce problème (et d'autres !), un outil matériel appelé le MMU a été inventé. Le MMU présente des adresses "virtuelles" à l'add-in et les traduit en adresses "absolues" de façon transparente. Ainsi, le système peut configurer le MMU pour me présenter le code de mon add-in dans des adresse virtuelles consécutives tout en les redirigeant individuellement vers les fragments du fichier g1a/g3a qui peuvent être éparpillés dans la ROM. De même, il peut présenter une adresse virtuelle fixe pour la RAM même si l'adresse absolue change. En pratique, on n'utilise quasiment que ces adresses virtuelles.
Mais dans gint, j'ai une poignée de code et de données que je dois absolument désigner par une adresse absolue dans la RAM. Sur Graph 90+E, j'accède au MMU pour connaître l'adresse absolue accordée à l'add-in et je m'installe là. Sur Graph mono, historiquement je me plaçais à une addresse fixe qui semblait inutilisée.
Donc ce que j'ai découvert récemment à travers le retour au menu c'est que la zone est effectivement utilisée et que revenir au menu provoque une écriture dedans. Ça veut dire que chaque fois qu'on revient au menu, des variables et tableaux de gint se font modifier de façon aléatoire. Comme vous pouvez vous en douter, ce n'est pas une situation acceptable.
Donc ce que j'ai commencé à faire c'est préparer le terrain pour déplacer mes données sensible au début de la zone de RAM accordée par l'OS, comme je le fais sur Graph 90+E. Mais cela pose quelques difficultés. Sur SH3, il n'y a que 8k de RAM disponible, et mes données sensibles prennent de base.... 8k aussi. Donc j'ai commencé à agencer tout ça de façon à le faire tenir dans moins, même si c'est pas tout à fait gagné encore. J'espère tout fait tenir dans 3k-4k.
Actuellement je suis en train de debugger le déplacement ; j'espère faire marcher tout ça ce soir. Ça veut dire que je dois attendre un peu pour faire les autres modifications (celles du moteur de gris), mais je vais faire au plus vite.
Ajouté le 10/07/2020 à 17:08 :
Voilà, j'ai fait ces modifications. Tout confondu j'arrive à faire tenir les données dans environ 4k, donc il reste 4k de variables globales sur SH3 (j'envisage de gratter 1k en déplaçant la VRAM). Notez que ces problèmes de taille c'est vraiment spécifique à la SH3, il reste aisément 28k sur SH4 et plus de 500k sur Graph 90. J'en ai profité pour réduire un peu l'empreinte mémoire de gint et gintctl de façon générale. Au total gintctl utilise que 500 octets sur les 4k qui restent donc vous voyez que si on fait un peu attention même une grosse appli a pas besoin de beaucoup de mémoire.
En fin de compte ça m'a pris un moment mais ça a bien nettoyé les facteurs d'incertitudes/instabilité dans gint. Cela explique et résoud en même temps les quelques bugs de retour au menu sur Graph mono que j'avais laissés il y a quelques mois. Il me reste quelques observations étranges sur SH3, mais pas reproductibles donc pour l'instant je ne peux rien y faire. (Assurer la compatibilité sur plusieurs plateformes est plus dur que ça peut en avoir l'air, toutes ces calculatrices ont quand même des sales différences qui rendent le boulot compliqué. xD)
Donc je reprends la liste des modifs que j'ai indiquée à Kirafi et j'espère ne pas croiser d'autre problème majeure du type avant la prochaine release.
Nouvelle bêta : gint 2.0.3-beta
Nouvelles fonctionnalités :
• Ajouté une fonction drect_border() pour les rectangles avec des bordures de tailles et couleurs variables
• Ajouté deux fonctions dtext_opt() et dprint_opt() permettant de contrôler l'alignement du texte
• Compatibilité Prizm fx-CG 20 (encore à tester sur une vraie machine, que je n'ai pas)
• Compatibilité avec l'émulateur fx-CG Manager
• Ajouté des valeurs par défaut correctes pour le moteur de gris sur les Graph mono autres que la Graph 35+E II
• Fonctions memcpy(), memset(), memcmp() et memmove() optimisées à fond à la fois sur SH3 et SH4
Changements :
• dtext() et dprint() ne spécifient plus la couleur de fond, c'est désormais géré par dtext_opt() et dprint_opt()
• Supprimé le boot log, un vieux mécanisme de debuggage
• Retiré l'utilisation d'une région "rram" héritée des Graph mono sur Graph 90
• Ultime modification de l'API timer pour vous simplifier la vie sans casser le code existant. Instructions de migration ici.
• Modifié la structure de la VBR sur SH3 pour économiser de la mémoire.
• En conséquence du point précédent, supprimé la région "rram" pour utiliser une partie des 8k de mémoire utilisateur à la place
Corrections de bug : plein, mais aucun qui m'a été rapporté. Principalement :
• Instabilités sur SH3 lorsque le retour au menu est utilisé.
Ajouté le 11/07/2020 à 15:50 :
Super nouvelle, Sentaro21 a pu tester l'application de test, gintctl, sur sa Prizm. Et ça marche sans problème ! gint supporte donc à divers degrés de perfectionnement toutes les calculatrices Casio hors Classpad sorties depuis 10 ou 15 ans
Citer : Posté le 13/07/2020 17:23 | # | Fichier joint
J'ai poussé sur dev une modification importante de l'API du moteur de gris. Ce changement simplifie grandement la gestion du gris pour vous et pour moi.
Modification 1 : alignment de dgray() avec dupdate()
Le moteur de gris est maintenant géré par une fonction dgray() qui se met d'accord avec le module de rendu pour n'activer et désactiver l'illusion de gris que lorsque vous envoyez la VRAM avec dupdate(). De cette façon, aucun frame ne peut apparaître à l'écran, ce qui était possible avant dans l'intervalle entre l'appel à gray_start() (qui démarre l'illusion) et gupdate() (qui fournit le premier frame en gris).
L'activation du moteur de gris se passe donc en deux étapes : on allume le moteur avec dgray(), ce qui active le rendu en gris (voyez la Modification 2) mais sans activer l'illusion de gris, et ensuite on appelle dupdate() pour envoyer notre premier frame gris à l'écran et activer en même temps l'illusion. De même à l'extinction, on arrête le moteur avec dgray(), ce qui revient au rendu mono mais sans désactiver l'illusion de gris, et ensuite on appelle dupdate() pour envoyer notre premier frame mono à l'écran et désactiver en même temps l'illusion.
Modification 2 : remplacement des fonctions de rendu g*() par d*()
Les fonctions de rendu du moteur de gris ont toujours été très redondantes par rapport aux fonctions de rendu mono. Désormais, dgray() remplace les fonctions d*() pour utiliser les versions appropriées du moteur de gris. Pour certaines raison de nommage, cela réduit la quantité de code à dupliquer entre le rendu mono et le rendu gris. Vous avez peut-être remarqué que quand j'ai ajoué dtext_opt() et drect_border() j'ai oublié d'ajouter leurs équivalents pour le moteur de gris ; grâce à la redondance supprimée ça ne se produira plus.
La façon correcte de dessiner dans le moteur de gris est désormais d'utiliser d*() comme avant. On peut donc écrire dtext(x, y, C_LIGHT, str) lorsque le rendu gris est activé.
Modification 3 : ajout d'une fonctionnalité de sauvegarde de l'état
Une fonction qui utilise le moteur de gris ne peut souvent pas juste l'allumer, l'utiliser et l'éteindre. Parce que si la fonction appelante l'utilisait déjà, alors l'éteindre va casser ou gêner son affichage. Et si par exemple ma carte du monde peut s'ouvrir à la fois depuis la map (qui est en niveau de gris) et le menu (qui est en noir et blanc), il n'y a pas de comportement fixe qui convienne.
Pour cette raison, la nouvelle API fournit DGRAY_PUSH_ON et DGRAY_PUSH_OFF qui sauvegardent l'état actuel du moteur avant de l'allumer ou l'éteindre. On les utilise au début d'une fonction en gris et d'une fonction mono, respectivement. À la fin de ces fonctions, on utilise DGRAY_POP qui restaurent l'état sauvegardé au début. De cette façon, dans ma carte du monde qui commence par DGRAY_PUSH_ON, l'appel à DGRAY_POP conservera le moteur allumé si je suis venu par la map et l'éteindra si je suis venu par le menu !
Pour adapter votre code. Il n'y a quasiment que du remplacement brut à faire pour adapter votre code à cette nouvelle API.
• Remplacez gray_start() par dgray(DGRAY_ON) et gray_stop() par dgray(DGRAY_OFF).
• Remplacez les fonctions de rendu comme gclear par leurs équivalents usuels comme dclear.
Les fonctions moins courantes du moteur de gris ont aussi été groupées sous le préfixe dgray() :
• gray_delays() → dgray_setdelays()
• gray_config() → dgray_getdelays() (l'état est donné par dgray_enabled())
• gvram() → dgray_getvram()
Attention, les modifications de dtext() et dprint() qui n'avaient pas été propagées à gtext() et gprint() (un oubli de ma part) s'appliquent maintenant. Pour rappel :
• gtext(x, y, str, fg, bg) → dtext(x, y, fg, str)
• gprint(x, y, fg, bg, format, ...) → dprint(x, y, fg, format, ...)
Pour choisir un fond non transparent, utilisez dtext_opt() et dprint_opt().
Le seul changement auquel vous devez faire attention est l'ordre d'activation et dessin du premier frame. Vous devez toujours activer le gris dans cet ordre-là :
dgray(DGRAY_ON);
/* On dessine le premier frame en gris */
dclear(C_LIGHT);
dline(0, 0, 10, 10, C_DARK);
/* On envoie le frame, ce qui active l'illusion de gris */
dupdate();
Si vous avez utilisé un autre ordre (notamment dessiné le premier frame avant d'activer le moteur de gris), vous devrez échanger les appels pour obtenir l'ordre ci-dessus.
Vous pouvez aussi utiliser les modes DGRAY_PUSH_ON, DGRAY_PUSH_OFF et DGRAY_POP si ça s'applique à votre cas d'usage, mais vous n'en avez pas besoin pour continuer à travailler avec la nouvelle API.
(Je mets un fichier joint stupide pour forcer la création d'un nouveau message, j'aurai besoin du permalink plus tard.)
Citer : Posté le 14/07/2020 15:24 | # | Fichier joint
Et voici une fonctionnalité que j'attendais depuis un bon moment : les polices Unicode !
Pour adapter vos programmes. Vous devez mettre à jour et réinstaller le fxSDK, ensuite mettre à jour et réinstaller gint, puis recompiler intégralement vos programmes avec make -B.
Voilà par exemple les chaînes de caractères telles que je les ai tapées dans gintctl et le résultat à l'écran avec la police uf5x7.
"Text rendering",
"Eurêka! UTF-8!",
"∀Δ, ∀f : P(Δ)→Δ,",
"∃(A,B)⊆Δ, f(A)=f(B)",
"2 = Λα.λf.λn.f (f n)",
NULL,
};
C'est aussi facile que ça et ça fait un bien fout de pouvoir mettre les accents où il faut sans se poser de questions !
Donc voilà comment ça marche. Les polices Unicode peuvent contenir n'importe quel ensemble de caractères donc une seule image ne suffit pas ; à la place on met une image par bloc et on nomme le fichier avec le numéro du premier caractère représenté (exemple ici). Mais dans l'esprit c'est pareil que les autres, on met juste un dossier complet dans assets-{fx,cg}/fonts au lieu d'une seule image.
Dans project.cfg on indique charset:unicode pour la police en question, et ensuite c'est comme d'habitude ! On récupère la police avec extern font_t font_<name>, dfont() pour l'activer, et c'est parti !
Citer : Posté le 14/07/2020 17:48 | #
Propre. J'attends plus que la release sur master pour mettre à jour les paquets
Citer : Posté le 15/07/2020 08:34 | #
This has probably been talked about before, but having flags in dsubimage to mirror the sprite horizontally or vertically when drawn would be great for stuff like animations. I don't know how bopti_image_t stores the sprite data though (is it packed like the VRAM is?), or if it's worth adding flags and code for something that wouldn't be used too much.
Citer : Posté le 15/07/2020 08:45 | #
You guessed everything correctly, it's been mentioned but it's not easily possible specifically because the data is packed for maximum rendering speed.
I could hack it to oblivion to make it work, but then it won't handle 90-degree rotations (genuinely impossible with this format), upscaling, etc.
A while ago I implemented an external library called libimg (topic here, repository here) to do exactly this. It uses a simple bitmap format (1 byte per pixel on fx-9860G as opposed to 3 bits in a gray transparent sprite in bopti) and supports horizontal flipping and much more.
It's integrated into fxconv so the procedure is not too different from bopti.
Citer : Posté le 15/07/2020 08:59 | #
Probably a bit easier just to make separate mirrored spritesheets for my use case , though libimg does seem like it might come in handy at some point.
Citer : Posté le 15/07/2020 09:02 | #
Yes it's clearly easier, I personally prefer to start this way because when detailing the sprites, versions that were initially symmetrical often become completely different so the flipping method isn't useful (unless you have storage problems in your g1a file).
Citer : Posté le 15/07/2020 09:31 | #
Also, I've had a weird issue after updating gint a couple of days ago - whenever I create a new sprite, the transparent pixels in the PNG are drawn as black in the addin. Existing sprites don't have this problem, though, and since it's fxconv that makes the sprites I'm a bit confused.
EDIT: It might actually be because the images could have more than 4 colours, I'm using some sprites taken from the actual game and might have missed a few pixels.
EDIT 2: Nope, definitely something fishy, I made a sprite with 4 colours and transparency and the transparent bit's getting drawn as black.
Citer : Posté le 15/07/2020 10:05 | #
I have such a test image in gintctl and it's displaying correctly even now. Can you please check the fxconv command-line for this image to see if a profile was specified (maybe in project.cfg)?
Citer : Posté le 15/07/2020 10:09 | # | Fichier joint
The command-line looks normal - "fxconv --bopti-image assets-fx/img/Untitled.png -o build-fx/assets/img/Untitled.png.o --fx --toolchain=sh-elf name:img_Untitled" (Untitled.png is the test image)
Ajouté le 15/07/2020 à 10:42 :
Looks like it only happens when you have too many transparent pixels?
Ajouté le 15/07/2020 à 11:25 :
I've been experimenting with it and it's really inconsistent. A fully transparent image will be drawn fine, but put a few black pixels in and the whole thing turns black. Some other sprites have no problems with transparency. This is on the latest commit of the dev branch. dtext and dprint also appears to be broken, when I build the default addin it hangs the calc