Planète Casio - Projets de programmation - Flux RSS http://www.planet-casio.com Programmes Casio, Jeux, Cours pour Calculatrices Casio fr-FR https://www.planet-casio.com/images/logo.gif Planète Casio - Projets de programmation - Flux RSS http://www.planet-casio.com 55 50 Programmes Casio, Jeux, Cours pour Calculatrices Casio. Mon, 16 Jun 2025 04:23:46 GMT Mon, 16 Jun 2025 04:23:46 GMT contact@planet-casio.com (Planet Casio) contact@planet-casio.com (Planet Casio) 5 MQ : Émulateur add-ins universel https://www.planet-casio.com/Fr/forums/topic18782--.html Parmi les projets de 2025 il y a tout un plan pour préserver les contenus du site, notamment les vieux programmes. La base de programmes de Planète Casio n'est pas beaucoup maintenue et on ne traque pas vraiment ce qui est encore jouable ou pas. Les projets d'émulateurs c'est pas nouveau, c.f. *, *, * et j'en oublie. Initialement je pensais repartir d'un existant, mais finalement j'en ai commencé un from scratch en voyant le cahier des charges : Il faut pouvoir émuler à la fois les Graph mono et les Prizm et à la fois les SH3 et les SH4 ; Il faut que ça puisse tourner sur le site donc compiler vers WebAssembly et optimiser raisonnablement (téléphones etc. ont pas des perfs de dingue) ; Il faut émuler pas mal de trucs matériels, donc assez bas-niveau, pour bien couvrir les add-ins et potentiellement l'appli PRGM pour émuler les programmes Basic ; Et si on fait tout ça ce serait criminel de pas s'en servir pour développer/debugger, ce pour quoi une GUI plus grosse que juste l'écran est nécessaire (et/ou gdb). Les détails techniques, pour ceux que ça intéresse, c'est : pur C, tourne sur Azur par facilité (GUI en OpenGL avec ImGui + compile pour Linux et WebAssembly), le décodeur est un arbre de `switch` généré automatiquement et la mémoire est hiérarchique par blocs de 1 Mo, 4 ko, et 1 octet. L'état actuel (Mai 2025) c'est : on peut faire tourner quelques add-ins sur CG, y'a des syscalls mais peu, y'a une partie du matériel émulé pour faire tourner gint ; en gros si vous prenez un add-in aléatoire ça va probablement pas marcher, mais pas loin. Voici le dépôt et au passage à quoi ressemble l'interface : y'a tous les trucs techniques nécessaires pour debugger. » Dépôt Git Lephenixnoir/mq « https://www.planet-casio.com/storage/forums/2025-05-24.21-44-17-18782.png J'ai pas encore de build pour le web sur lequel vous pouvez cliquer et tester tout de suite, mais vous pouvez compiler depuis le dépôt. Voilà plus de nouvelles bientôt j'espère. ^^ Wed, 28 May 2025 20:22:25 +0200 Devlog : La renaissance de Zelda Tears of the NES https://www.planet-casio.com/Fr/forums/topic18752--.html Bien le bonjour les gens ! Aujourd’hui, et pendant tout le reste du mois, je vais partager avec vous le développement de la nouvelle version de Zelda: Tears of the NES. Je me suis lancé le défi de reprendre mon ancien prototype et d’en faire un vrai jeu, propre, fini, jouable. Je vais organiser ça en épisodes, ou chapitres, et je mettrai à jour ce topic au fur et à mesure de l’avancement du projet. Chapitre 1 – Un passé lointain : Particule Si tu traînes régulièrement sur ce site, tu sais peut-être déjà que ça fait 5 ans 0_0 que je bosse sur un moteur de jeu nommé Particule. J’en parle peu, mais pourtant il a bien évolué. Pas mal de bugs ont été corrigés, et plusieurs optimisations ont été apportées. Pourquoi je t’en parle ici ? Tout simplement parce que ce jeu va tourner sur Particule. Qu’est-ce que ça apporte ? Comment ça fonctionne ? Particule est divisé en trois parties : -Particule API -Particule Engine -Particule Editor ▸ Particule API La Particule API est une interface qui permet de compiler un même projet sur plusieurs plateformes (tant qu’elles sont prises en charge), sans modifier une seule ligne de code ! 8-) Voici un exemple de fichier de configuration : { "common": { "is_library": false, "clean": false, "debug": false, "source_files": [ "Particule/Engine/src/Components/Camera.cpp", "Particule/Engine/src/Core/Coroutine/CoroutineManager.cpp", "Particule/Engine/src/Core/GameObject.cpp", "Particule/Engine/src/Core/Transform.cpp", "Particule/Engine/src/Scene/Scene.cpp", "Particule/Engine/src/Scene/SceneManager.cpp", "Sources/src/main.cpp", "Sources/src/Sys/Game.cpp", "Sources/src/Scenes/MainMenuScene.cpp" ], "include_paths": ["Particule/Engine/include","Sources/include"], "library_paths": [], "defines": {}, "build_dir": "build", "bin_dir": "bin", "project_name": "ZeldaTOTN" }, "CasioCg": { "libraries": [], "compile_flags": "-Wall -Wextra -Werror", "link_flags": "", "assets_files": { "textures": [ {"path": "Assets/common/Images/UI/UI.png","reference_path":"assets/Images/UI/UI.png", "format": "p8", "alpha":true, "external":false}, {"path": "Assets/common/Images/UI/MainLogo.png","reference_path":"assets/Images/UI/MainLogo.png", "format": "p8", "alpha":true, "external":false} ], "fonts": [ {"path": "Assets/common/Fonts/PressStart2P.ttf","reference_path":"assets/Fonts/PressStart2P.font", "resolution": 8, "charset": " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~éèêëôöûüçàâäæœÉÈÊËÔÖÛÜÇÀÂÄÆŒ"}, {"path": "Assets/common/Fonts/The Wild Breath of Zelda.otf","reference_path":"assets/Fonts/The Wild Breath of Zelda.font", "resolution": 32, "charset": " 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz."} ], "other": [] }, "inputs": {"UP":"KEY_UP", "DOWN":"KEY_DOWN", "LEFT":"KEY_LEFT", "RIGHT":"KEY_RIGHT", "ENTER":"KEY_EXE", "ENTER2":"KEY_SHIFT"}, "display_name": "", "icon_uns": "Assets/cg/icon-uns.png", "icon_sel": "Assets/cg/icon-sel.png", "output_file": "ZeldaTOTN", "memtrack": false }, "Windows": { "assets_files": { "textures": [ {"path": "Assets/common/Images/UI/UI.png","reference_path":"assets/Images/UI/UI.png"}, {"path": "Assets/common/Images/UI/MainLogo.png","reference_path":"assets/Images/UI/MainLogo.png"} ], "fonts": [ {"path": "Assets/common/Fonts/PressStart2P.ttf","reference_path":"assets/Fonts/PressStart2P.font", "resolution": 8, "charset": " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~éèêëôöûüçàâäæœÉÈÊËÔÖÛÜÇÀÂÄÆŒ"}, {"path": "Assets/common/Fonts/The Wild Breath of Zelda.otf","reference_path":"assets/Fonts/The Wild Breath of Zelda.font", "resolution": 32, "charset": " 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz."} ], "audio": [], "other": [] }, "inputs": {"UP":"SDLK_UP", "DOWN":"SDLK_DOWN", "LEFT":"SDLK_LEFT", "RIGHT":"SDLK_RIGHT", "ENTER":"SDLK_RETURN", "ENTER2":"SDLK_KP_ENTER"}, "icon": "Assets/win/icon.ico", "console": true, "architecture": "x64", "lib_api": "SDL2", "compiler": "MSVC", "output_file": "ZeldaTOTN" }, "Linux": { "assets_files": { "textures": [ {"path": "Assets/common/Images/UI/UI.png","reference_path":"assets/Images/UI/UI.png"}, {"path": "Assets/common/Images/UI/MainLogo.png","reference_path":"assets/Images/UI/MainLogo.png"} ], "fonts": [ {"path": "Assets/common/Fonts/PressStart2P.ttf","reference_path":"assets/Fonts/PressStart2P.font", "resolution": 8, "charset": " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~éèêëôöûüçàâäæœÉÈÊËÔÖÛÜÇÀÂÄÆŒ"}, {"path": "Assets/common/Fonts/The Wild Breath of Zelda.otf","reference_path":"assets/Fonts/The Wild Breath of Zelda.font", "resolution": 32, "charset": " 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz."} ], "audio": [], "other": [] }, "inputs": {"UP":"SDLK_UP", "DOWN":"SDLK_DOWN", "LEFT":"SDLK_LEFT", "RIGHT":"SDLK_RIGHT", "ENTER":"SDLK_RETURN", "ENTER2":"SDLK_KP_ENTER"}, "lib_api": "SDL2", "output_file": "ZeldaTOTN" } } Je lui donne ça… et il fait le reste tout seul, automatiquement. Deux grosses "nouveautés" à noter : -la gestion des fonts ; -la gestion des textures. 📌 Les fonts Le système convertit une font .ttf ou .otf en un format spécial. Ce format permet de stocker uniquement un charset donné (super pratique pour économiser de l’espace), gère automatiquement les unicodes, et permet de dessiner avec différentes tailles. Par exemple : si tu sauvegardes une font à 16 px, tu peux l’afficher à l’écran en 19 px sans souci. Tu peux bien sûr changer la couleur; et le spacing entre les caractères reste fidèle à la font d’origine (et oui, tous les caractères n’ont pas la même largeur). 🖼️ Les textures Tu sais sûrement que gint propose 3 types de compression d’image (P4, P8, RGB565). Particule, lui, prend tout ça en charge. Peu importe le format, si tu fais image->GetPixel(x, y), tu obtiens un type Color optimisé, sans te prendre la tête. Et si tu veux afficher un pixel, tu peux utiliser image->PutPixel(xTexture, yTexture, xScreen, yScreen) pour le dessiner directement à l’écran. Évidemment, pour les affichages classiques, on a aussi Draw, DrawSub, DrawSubSize, DrawSubSizeColor, etc. Tu peux afficher une image entière ou une portion, à la taille que tu veux, avec la couleur que tu veux, et même la retourner (flip horizontal/vertical) en donnant une taille négative. 👉 Pour l’instant, la rotation (en degré) n’est pas encore supportée. ▸ Particule Engine Le Particule Engine, c’est une copie maison de Unity 3D. Son fonctionnement est similaire : scènes, GameObjects, composants… Je te laisse imaginer le fonctionnement à la Unity : une scène contient des objets, chaque objet peut avoir des composants qui lui ajoutent des comportements ou propriétés. J’ai même intégré un système de Coroutine, très proche de IEnumerator, pour faire des fonctions asynchrones. Par exemple, l’animation du logo au lancement du jeu est maintenant gérée via une coroutine. ▸ Particule Editor Là on parle de l’éditeur. Tu vois Unity ? Ben c’est pareil. Sauf que ça fait 5 ans que j’essaie de faire cet éditeur à la noix… :argh: J’ai tenté de le faire 4 fois en Python avec Tkinter : ça ramait, c’était instable. Une horreur. Mais cette fois… c’est la bonne. Pourquoi ? Parce que le Particule Editor est développé avec… Particule API. La boucle est bouclée. ^^ En résumé : Particule, c’est génial, il fait tout le sale boulot pour toi Chapitre 2 – Le Commencement : Menu principal Maintenant qu’on a l’API et le moteur, on peut passer à la suite : le menu principal. Il a été entièrement refait, façon Unity 3D. Avant, j’avais une seule ligne d’exécution. Maintenant, plusieurs processus se partagent les tâches, et il faut bien les gérer. C’est vrai que pour l’interface utilisateur, c’est pas toujours pratique. J’ai mis en place un système de sprites dans l’API. L’idée ? Sur une seule texture, tu regroupes plusieurs icônes. Par exemple : toutes les icônes de l’UI sur une image. Ensuite, tu les découpes en sprites, et rien qu’avec ça, tu peux générer tout le menu principal. https://i.ibb.co/YTZ1qrnd/Screen-UI-Zelda-TOTN.png https://i.ibb.co/Gf5kY9xS/casio-menu-gif.gif Chapitre 3 – l'Éditeur de Sprites J’ai développé un éditeur de sprites bien pratique pour faciliter le travail sur les assets du jeu. Il permet de charger une image (sprite sheet, tileset, etc.) et de découper visuellement les sprites directement dans le logiciel. C’est super intuitif : tu traces les zones que tu veux, et chaque sprite est enregistré, le tout dans un fichier .json. Tu peux ensuite : renommer chaque sprite pour t’y retrouver facilement ; modifier ou corriger une découpe si tu t’es trompé ; et même changer la couleur de fond pour un meilleur contraste visuel, selon ton image. C’est un petit outil maison, mais franchement, il me fait gagner un temps fou. Et surtout, il s’intègre parfaitement au reste de l’écosystème Particule. https://i.ibb.co/whDyTbrK/Capture-d-cran-2025-05-12-013515.png Chapitre 5 – La Skybox La skybox, c’est le fond visuel de ta scène. Dans mon cas, j’ai opté pour un système simple, léger et efficace : un dégradé vertical. Elle est composée de deux couleurs : - une couleur pour le haut du ciel (top) ; - une couleur pour le bas (bottom). Chaque ligne de l’écran est ensuite coloriée par interpolation linéaire entre ces deux teintes. Résultat : un joli dégradé qui donne de la profondeur et évite le vide noir souvent présent dans les rendus 3D sans skybox. C’est rapide à calculer, visuellement agréable, et largement suffisant. Chapitre 6 – La projection 3D Entrons maintenant dans le vif du sujet : la projection 3D. L’objectif est simple à formuler mais complexe à mettre en œuvre : prendre un modèle 3D et calculer où ses points (appelés sommets) doivent apparaître à l’écran en 2D. Mais comment ça fonctionne ? Chaque objet a : - une position (où il est dans l’espace), - une rotation (dans quelle direction il est orienté), - une échelle (s’il est agrandi ou réduit). On commence par appliquer tous ces paramètres à chaque sommet du modèle. Translation par rapport à la caméra Ensuite, on place l’objet par rapport à la caméra. En gros, on « recentre » la scène pour que ce que la caméra voit soit bien positionné. Rotation de la caméra Après avoir bougé les objets, il faut les orienter comme si on tournait la tête. La rotation de la caméra est appliquée à chaque sommet pour simuler cette vue. Projection en 2D Une fois les sommets bien placés et orientés, on les projette sur l’écran. C’est comme regarder à travers une vitre : on trace une ligne entre l’œil (la caméra) et le point 3D, et on regarde où cette ligne touche la surface de l’écran. Le calcul principal ici ressemble à : x à l’écran = (x dans l’espace / profondeur) * facteur C’est ce qui donne l’effet de perspective : plus un objet est loin, plus il paraît petit. https://i.ibb.co/pBsjb4DX/casio.gif Chapitre 7 – Rendu 3D : dessiner les textures Maintenant que les sommets sont bien positionnés à l’écran, il est temps de dessiner les faces du modèle 3D : on entre dans la phase de rendu. Le principe des UV Chaque face du modèle (triangle ou quadrilatère) est mappée à une texture, une image qu’on applique sur la surface. Les coordonnées UV servent à dire quelle partie de l’image correspond à chaque coin de la face. (U pour l’axe horizontal, V pour l’axe vertical) C’est comme découper une image pour la coller précisément sur un objet en 3D. Et comment je m’y prends ? Selon la forme de la face, plusieurs stratégies sont utilisées : Si la face est un quadrilatère : C’est un rectangle ? → j’utilise une fonction optimisée pour les rectangles (plus rapide). C’est un parallélogramme ? → j’ai une autre fonction dédiée, qui prend en compte l’inclinaison. Autre cas ? → je divise la face en deux triangles pour un rendu plus universel. Si la face est déjà un triangle : → je la dessine telle quelle, en utilisant un algorithme de rendu triangle + texture. Ces choix sont faits pour optimiser les performances, car chaque méthode est adaptée à la géométrie qu’elle traite. Et voilà le résultat à l’écran : https://zupimages.net/up/25/20/2b37.gif Chapitre 8 – Construire le monde : l’éditeur de map Passons maintenant à un élément fondamental dans tout jeu d’aventure : la carte du monde. Il est évident que définir chaque bloc manuellement, ID par ID, serait non seulement fastidieux, mais totalement contre-productif. C’est pourquoi j’ai opté pour une solution plus efficace : un éditeur de map sur mesure. Pourquoi Unity 3D ? Par manque de temps (et parce que je tiens à avancer rapidement sur le projet), j’ai choisi de développer l’éditeur de Map avec Unity 3D. L’outil est robuste, bien documenté, et me permet de concevoir une interface intuitive beaucoup plus rapidement qu’en repartant de zéro avec Particule. Un RPG Maker… mais en 3D L’objectif était clair : créer une version 3D de mon ancien moteur inspiré de RPG Maker. Ce choix me permet de générer une grande variété de blocs avec une texture basique. Créer cet éditeur m’a pris un bon moment, mais franchement, le confort que ça apporte en vaut largement. Comment ça fonctionne ? Je n’entre pas ici dans les détails techniques, car j’ai déjà expliqué le fonctionnement dans un ancien post que tu peux consulter ici. https://zupimages.net/up/25/21/7tn5.gif Voilà où j’en suis pour le moment. Les prochains chapitres arrivent très bientôt ! ^^ Mon, 12 May 2025 01:37:39 +0200 Je speedrun un ancien projet https://www.planet-casio.com/Fr/forums/topic18739--.html Hello les gens ! Comme vous le savez, j’adore créer des jeux. Le souci, c’est que la plupart ne sont que des prototypes que j’ai laissés de côté depuis trop longtemps… et ça me fait mal au cœur de les voir prendre la poussière. Alors j’ai pris une décision : je vais tous les ressusciter ! C’est un peu comme si je me lançais un concours perso. (Si certains d’entre vous veulent me filer un coup de main, je ne dirai pas non :lol: ) L’objectif : terminer chaque projet en 2 semaines maximum. Si je n’y arrive pas… j’aurai un gage 0_0 Petite précision : je vais uniquement faire des Add-ins (donc les projets initialement faits en Basic Casio seront portés et rendus compatibles avec les Casio FX). Voici les projets en attente de résurrection : -Mario Land / New Mario Maker (même moteur pour les deux) -Zelda BOTN -Isocraft -Super Mario 3D -Zelda: Tears of the NES (vu sa complexité, j’aurai 3 - 4 semaines pour celui-là) -RPG Maker Maintenant, c’est à vous de jouer : Votez pour le projet que vous voulez voir terminé en premier, et proposez un gage (soyez sympas hein 😅). Vous avez jusqu’au 7 mai pour voter. Et une fois qu’un projet est terminé… on enchaîne avec le suivant ! Sat, 03 May 2025 16:24:43 +0200 Xeno Threat (Jeu pour Graph 25) https://www.planet-casio.com/Fr/forums/topic18725--.html Bonsoir tout le monde ! Je passe faire un petit coucou pour faire un état des lieux de mon petit projet de jeu que je développe sur ma vieille Graph 25. https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhJXZJNQBjg4gPrTtDDs1jATCf3Xx3kNBXlPjBT5enh2spIIfRKqy8SncftemsvUj2cXJs831iqdsOVNu9Yzrp0zSZBOKQDvxMpCylq_Rm3LrShPLeyqDZstuxJ7KkXSsTzEpEkIWKeWlwEVAPKLVu5NmPzG95Oudn-yI3mB7GX4KqDsAET0mGnT6W9CImf/s1600/IMG_0411-256.jpg Il s’agit d’un petit RPG, en gros un donjon. D’affreux extraterrestres ont envahi votre vaisseau spatial, le Dedalus, et vous devez rejoindre la capsule de sauvetage à l’autre bout de la map pour vous enfuir. Le jeu se joue en vue à la première personne. Comme il n’y a pas la commande GetKey sur Graph 25, l’interface alterne entre illustrations dont on sort avec la touche EXE et phases texte où vous entrez le numéro de l’action que vous voulez effectuer. Du coup, les phases de combat se font naturellement en tour par tour. Petit échantillon de ce que vous pourrez voir en jeu. https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj-M22Dcr2luuYlPGJOuOo8ouxgr2GLD5Bv-FH8dW1ba_9WI2ZoOEjOCRzJGLyXj_6lxeXLzlassW8WkQBGcawjp1JlBKX9xPyECe5y9NrVWlM9Xha9tAQ1WTE56Kk5fyh4h-8TCuo7myRScj5YkeAbPzIfEXdNQdLiEkuyMOsqnCJGE4FVIbe-Iyyx43oZ/s1600/IMG_0412-256.jpghttps://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEif2Im2iKp-2YL0w1NaOASlaa-vg886fPzVELoh-DZe1JaAwnwgVoU6P8ZpPmtxaqBfG3RvS57D8OWMt9l7uwToPKv7Lilw7wFOCeVu1KiIO5XlPsbYxwQuNIF2ctsJemgOLFBJHHjFLgNDiHtCE4YERxx9gaJm7zjSpHc1qO8_Ud0uyY2sFSzZyPhe8TWD/s1600/IMG_0413-256.jpghttps://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg5_jl0A0sUjJne7PY1F1zEA__1XQRW9W66i5awc6jueao726zc6RjJuZCyjDuz3dFigZxC9D3fbz_si4KZQStXssNCCbJrdGXNzOWvfcRoOs2J6L1Ir8ML-TW4fFoGXRNaYYMUq8xlhxgZNuF3yqmqD12N_vaXZfPTcz0gguhH4ba8nJ4Loyyoo5wD8F26/s1600/IMG_0420-256.jpghttps://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgUuRiwaHnZAOsKmlG826BmQeUqdM-cGxPHrjzifCJ2nxWjFd8hjWoLYRylYeXloy8Y09BwahGYYGQLodr7aWjaJ_x4zajA1eKgE83zOF0tT37R5HpCKF2cfZx4uH3WTX62DmFQAqDl8_K0HOnVDW84-aGnmZ3sm5nAlhtOu0foqumGuJ-JNnw1Z0cwfhX3/s1600/IMG_0414-256.jpg Le jeu est terminé sur ma calculette à part quelques ajustements de difficulté. Il me reste encore à le reporter sur mon ordi pour pouvoir le distribuer. Ma petite machine étant trop vieille, je ne peux pas faire de transfert et je dois… Tout recopier à la mimine. x) Avant ça, maintenant que j’ai fait l’acquisition d’une Graph-90, je vais m’empresser d’apprendre les spécificités de casioplot et de PythonExtra pour poster une petite participation à la game jam. Bonne semaine à tous ! :D Tue, 22 Apr 2025 03:08:37 +0200 prog-tools add-in for programming on CG50 https://www.planet-casio.com/Fr/forums/topic18696--.html I've been working on an add-in to do programming on the CG50. It has tabs like tmux, and each tab can be split once either vertically or horizontally allowing for up to 12 programs to run at once. Only the currently selected program runs until you switch to another tab or split. I think this will work better than the way the built-in Python does it where you have to save the file and lose your place every time you want to run something. https://raw.githubusercontent.com/JoeyShepard/prog-tools/refs/heads/main/images/planet-casio/pt-main.png https://raw.githubusercontent.com/JoeyShepard/prog-tools/refs/heads/main/images/planet-casio/pt-split.png Each of the 12 splits has its own memory in the 2MB of RAM starting at 0x8c200000. When you start a program or move back to a program that's already running, the add-in shifts the memory for the selected program to the top of the heap so it's contiguous with the rest of the free memory and easy to expand. https://raw.githubusercontent.com/JoeyShepard/prog-tools/refs/heads/main/images/planet-casio/pt-mem.png I'm close to being finished with a simple shell so I can manipulate files without having to leave the add-in. Thanks to LephenixNoir for the help with file system operations and everything else. I plan to add a Forth interpreter next to write programs that run on the calculator. https://raw.githubusercontent.com/JoeyShepard/prog-tools/refs/heads/main/images/planet-casio/pt-command-line.png I made a small framework with SDL2 for testing the add-in. It configures the video memory the same as the CG50 so writing a pixel there works exactly the same as on the calculator. It reimplements some of the gint functionality too so I can compile the add-in for linux which is very convenient for testing. I'll add some more information as I finish more features. Please let me know if you have any suggestions! GitHub repo here. Sat, 05 Apr 2025 18:42:09 +0200 MemTrack - Détection de fuites mémoire https://www.planet-casio.com/Fr/forums/topic18688--.html Hello les gens ! ^^ Voici un petit système pour détecter les fuites mémoire dynamiques dans un programme Casio utilisant gint, compatible aussi bien en C qu’en C++. Le but est simple : à la fin du programme, savoir combien de blocs mémoire n'ont pas été libérés, même ceux alloués dans des libs externes. Fonctionnalités - Remplace malloc/free et new/delete par une version trackée - Compatible avec les appels depuis des libs .a - Affiche automatiquement un message à la fin du programme - Optionnel, activable/désactivable via CMake - Aucun outil externe requis - Ne modifie pas gint ou la libc Intégration 1. Copier le fichier memtrack.h/.hpp dans votre projet : #if !defined(MEMTRACK_H) && defined(MEMTRACK_ENABLED) #define MEMTRACK_H #include <stdlib.h> #include <stdio.h> #include <gint/gint.h> #include <gint/keyboard.h> #include <gint/display.h> #include <gint/kmalloc.h> #ifdef __cplusplus extern "C" { #endif // --- Compteur global --- static int memtrack_alloc_count = 0; void memtrack_init(void) { memtrack_alloc_count = 0; } // --- malloc/free overrides --- void* malloc(size_t size) { ++memtrack_alloc_count; return kmalloc(size, NULL); } void free(void* ptr) { --memtrack_alloc_count; kfree(ptr); } void* calloc(size_t count, size_t size) { ++memtrack_alloc_count; return kmalloc(count * size, NULL); } void* realloc(void* ptr, size_t size) { return krealloc(ptr, size); } // --- Report à la fin du programme --- __attribute__((destructor)) static void memtrack_report_leaks(void) { dclear(C_BLACK); if(memtrack_alloc_count > 0) { char buffer[64]; snprintf(buffer, sizeof(buffer), "Memory leak: %d block(s)", memtrack_alloc_count); dprint(1, 1, C_WHITE, buffer); } else { dprint(1, 1, C_WHITE, "No memory leaks!"); } dupdate(); getkey(); // pause } #ifdef __cplusplus } #endif // --- Opérateurs C++ --- #ifdef __cplusplus #include <new> void* operator new(std::size_t size) { return malloc(size); } void* operator new[](std::size_t size) { return malloc(size); } void operator delete(void* ptr) noexcept { free(ptr); } void operator delete[](void* ptr) noexcept { free(ptr); } void operator delete(void* ptr, unsigned int) { free(ptr); } void operator delete[](void* ptr, unsigned int) { free(ptr); } #endif // __cplusplus #endif // MEMTRACK_ENABLED 2. Dans main() : reset du compteur #include "memtrack.hpp" int main(void) { memtrack_init(); // Ignore les allocations faites avant main() //code... return 1; } 3. Dans CMakeLists.txt Ajouter en haut cette ligne (ON ou OFF) : option(MEMTRACK "Enable memory leak tracking" ON) Et ajouter les lignes suivantes : if(MEMTRACK) target_compile_definitions(myaddin PRIVATE MEMTRACK_ENABLED=1) target_compile_options(myaddin PRIVATE -fno-builtin-malloc -fno-builtin-free -fno-builtin-realloc -fno-builtin-calloc -fno-builtin-new -fno-builtin-delete ) endif() Voilà en espérant que cela peut vous être utile ^^ PS : Je me suis cassé la tête à chercher dans tout gint la fonction builtin de malloc et free, j'ai trouvé que ça, s'il y a un problème, signalé le moi Wed, 02 Apr 2025 19:40:32 +0200 Sudoku in python https://www.planet-casio.com/Fr/forums/topic18681--.html As my first python program I decided to make Sudoku. https://i.imgur.com/i5zmGs9.jpeg Here's the link It's really not bad though IMHO- I'm a bit of a perfectionist. It has a nice interface and even a custom small number font. The code is probably not very pythonic or optimized though. I also had to keep it under 300 lines so I could use the Casio python script editor. Of course this would not have been possible without ExtraPython, so thank you to everyone involved in that! The game can only run on the ExtraPython add-in. Unfortunately there are no screenshots as I don't know how to build/run the emulator. Maybe someone else can take a few ss/gif? For this version there are no save states, 4 difficulties, and a limited amount of games available. Lephe tells me support for file read/write will hopefully be added to EP in the near future, and then I can add save states and 100s of games. Also possibly on the agenda for the future is a reveal/reveal all option. Let me know what you think, because I'm unsure if that's even a positive feature. If you have any other features requests/comments please let me know! Fri, 28 Mar 2025 02:54:20 +0100 Un équivalent graphique de std::cout et de printf pour Casio https://www.planet-casio.com/Fr/forums/topic18675--.html Hello les gens ! ^^ Pour simplifier le debugging de mes projets casio, j’ai conçu un flux de sortie graphique inspiré de std::cout, appelé casio::dout, et je vais vous le partager. J'ai aussi ajouté un équivalent de printf. Équivalent de std::cout pour C++ Il gère : -La composition de flux avec << -Les retours à la ligne \n -Les fins de lignes avec casio::end -Les types string, int, float, etc. Exemple d’utilisation casio::dout(10, 20, C_WHITE) << "Valeur : " << 42 << casio::end; casio::dout(10, 60, C_WHITE) << "Pi ~ " << 3.14159f << "\nApproximatif" << casio::end; Comment ça marche ? Le système repose sur une classe DoutStream qui encapsule : -Les coordonnées (x, y) initiales -La couleur du texte -Un curseur de position mis à jour dynamiquement Le texte est découpé ligne par ligne, chaque mot est affiché avec dtext(), et les sauts de ligne sont simulés en ajustant les coordonnées via dsize(). Intégration Incluez simplement le fichier dout.hpp dans votre projet, et utilisez casio::dout() comme un flux standard. Code : #ifndef DOUSTREAM_HPP #define DOUSTREAM_HPP #include <gint/gint.h> #include <gint/display.h> #include <string> #include <sstream> #include <iostream> namespace casio { struct DoutEnd {}; inline DoutEnd end; class DoutStream { public: DoutStream(int x, int y, int color) : startX(x), curX(x), curY(y), color(color) {} template<typename T> DoutStream& operator<<(const T& value) { std::ostringstream oss; oss << value; processText(oss.str()); return *this; } DoutStream& operator<<(DoutEnd) { // Force une nouvelle ligne newline(); return *this; } private: int startX; int curX; int curY; int color; void processText(const std::string& text) { std::string line; for (char ch : text) { if (ch == '\n') { if (!line.empty()) draw(line); newline(); line.clear(); } else { line += ch; } } if (!line.empty()) draw(line); } void draw(const std::string& text) { dtext(curX, curY, color, text.c_str()); int w = 0, h = 0; dsize(text.c_str(), dfont_default(), &w, &h); curX += w; // Avancer horizontalement } void newline() { curX = startX; int h = 0; dsize("A", dfont_default(), nullptr, &h); // Hauteur de ligne curY += h + 1; } }; // Interface comme std::cout struct dout_creator { DoutStream operator()(int x, int y, int color) { return DoutStream(x, y, color); } }; inline dout_creator dout; inline void formatFloat(float val, char* out) { int sign = val < 0 ? -1 : 1; val = val < 0 ? -val : val; int int_part = static_cast<int>(val); int dec_part = static_cast<int>((val - int_part) * 1000 + 0.5f); // arrondi sprintf(out, "%s%d.%03d", (sign < 0 ? "-" : ""), int_part, dec_part); } inline DoutStream& operator<<(casio::DoutStream& out, float val) { char buf[32]; formatFloat(val, buf); return out << buf; } inline DoutStream& operator<<(casio::DoutStream& out, double val) { char buf[32]; formatFloat(static_cast<float>(val), buf); return out << buf; } } #endif Équivalent de printf pour C dprint est une réimplémentation simplifiée de printf Ce n’est pas un printf complet : -Pas de gestion des drapeaux (-, +, 0, etc.) -Pas d’alignement ou largeur (%5d, %05d, etc.) -Pas de support Unicode ou internationalisation Fonctionnalités prises en charge -Position (x, y) initiale personnalisable -Couleur personnalisée via int color -Gestion des \n comme retour à la ligne visuel -Reconnaissance et rendu des formats : ▬► %d / %i → int ▬► %u / %lu / %ld → unsigned int, long, unsigned long ▬► %zu → size_t ▬► %f / %.Nf → float ou double avec précision personnalisée ▬► %x → hexadécimal (minuscule) ▬► %p → pointeur ▬► %s → chaîne de caractères ▬► %b → booléen (true/false) ▬► %% → pour afficher un % (Le format %b n’existe pas dans printf, mais dprint le supporte) Exemple d’utilisation dprint(10, 10, C_WHITE, "Bonjour\ntout le monde !"); dprint(10, 30, C_WHITE, "Nom: %s Score: %d", "Alice", 42); dprint(10, 50, C_WHITE, "Pi ≈ %.3f", 3.14159f); dprint(10, 70, C_WHITE, "Taille: %zu octets", (size_t)512); dprint(10, 90, C_WHITE, "État: %b", true); dprint(10, 110, C_WHITE, "Adresse: %p", (void*)0x12345678); dprint(10, 130, C_WHITE, "Hex: %x", 255); dprint(10, 150, C_WHITE, "Progression: 100%%"); Code : #ifndef DPRINT_H #define DPRINT_H #include <gint/gint.h> #include <gint/display.h> #include <stdarg.h> #include <stdio.h> #include <string.h> #include <math.h> inline void formatFloat(float val, char* out, int precision) { int sign = val < 0 ? -1 : 1; val = val < 0 ? -val : val; int int_part = (int)val; int dec_part = (int)((val - int_part) * pow(10,precision) + 0.5f); // arrondi sprintf(out, "%s%d.%03d", (sign < 0 ? "-" : ""), int_part, dec_part); } void dprint(int x, int y, int color, const char* fmt, ...) { char buffer[256] = {0}; int cx = x; int cy = y; va_list args; va_start(args, fmt); while (*fmt) { if (*fmt == '%') { fmt++; int precision = -1; if (*fmt == '.') { fmt++; precision = 0; while (*fmt >= '0' && *fmt <= '9') { precision = precision * 10 + (*fmt - '0'); fmt++; } } char temp[64] = {0}; switch (*fmt) { case 'd': case 'i': sprintf(temp, "%d", va_arg(args, int)); break; case 'u': sprintf(temp, "%u", va_arg(args, unsigned int)); break; case 'x': sprintf(temp, "%x", va_arg(args, unsigned int)); break; case 'l': fmt++; if (*fmt == 'd') sprintf(temp, "%ld", va_arg(args, long)); else if (*fmt == 'u') sprintf(temp, "%lu", va_arg(args, unsigned long)); break; case 'z': fmt++; if (*fmt == 'u') sprintf(temp, "%zu", va_arg(args, size_t)); break; case 'f': { double f = va_arg(args, double); if (precision == -1) precision = 3; formatFloat(f, temp, precision); break; } case 's': snprintf(temp, sizeof(temp), "%s", va_arg(args, char*)); break; case 'p': sprintf(temp, "%p", va_arg(args, void*)); break; case 'b': snprintf(temp, sizeof(temp), "%s", va_arg(args, int) ? "true" : "false"); break; case 'c': snprintf(temp, sizeof(temp), "%c", va_arg(args, int)); break; case '%': strcpy(temp, "%"); break; default: snprintf(temp, sizeof(temp), "%%%c", *fmt); // Unknown format break; } dtext(cx, cy, color, temp); int w = 0, h = 0; dsize(temp, dfont_default(), &w, &h); cx += w; } else if (*fmt == '\n') { int h; dsize("A", dfont_default(), NULL, &h); cx = x; cy += h; } else { buffer[0] = *fmt; buffer[1] = '\0'; dtext(cx, cy, color, buffer); int w = 0, h = 0; dsize(buffer, dfont_default(), &w, &h); cx += w; } fmt++; } va_end(args); } #endif Sun, 23 Mar 2025 19:06:51 +0100 programmation de jeux game boy. https://www.planet-casio.com/Fr/forums/topic18645--.html Bonjour, j'aimerais vous présenter une idée de programmer des jeux game boy avec gb studio. Je mettrais ici tous les jeux que j' aurais créés et si vous voulez en rajouter, dite le moi. ( gb studio est installable sur Windows, Linux et MacOS ) Fri, 28 Feb 2025 15:29:31 +0100 Convertir des addins Graph 90+E/Prizm vers Graph Math+ https://www.planet-casio.com/Fr/forums/topic18627--.html Hello, bon, s'ouvre désormais devant nous un vaste chantier de conversion des addins Prizm/Graph 90+E (les fx-CG10/20/50) vers la nouvelle plateforme Graph Math+ (fx-CG100). Comme vous avez pu voir par ailleurs, tout ne fonctionne pas direct out-of-the-box, et dans un certain nombre de cas, il va falloir mettre les mains dans le cambouis pour convertir les addins pour qu'ils tournent vers cette nouvelle machine. Je crée donc ce fil pour collecter et partager l'expérience de conversion, avec les succès mais aussi les galères afin de rapidement acquérir de l'expérience et partager dans la communauté. Idéalement le but est que ça communique. Mon, 10 Feb 2025 08:56:57 +0100