From 3b8b7b74d1a205171fd6fbbb0e513394d66c422e Mon Sep 17 00:00:00 2001 From: dborth Date: Sun, 21 Mar 2010 19:52:22 +0000 Subject: [PATCH] new font, rewritten PNGU, menu tweaks, optimized text code --- source/ngc/fonts/font.ttf | Bin 29244 -> 55620 bytes source/ngc/gui/gui_filebrowser.cpp | 2 +- source/ngc/gui/gui_imagedata.cpp | 35 +- source/ngc/gui/gui_text.cpp | 238 ++++----- source/ngc/lang/fr.lang | 468 ++++++++++++++++-- source/ngc/menu.cpp | 36 +- source/ngc/pngu.c | 755 ++++++++++++++--------------- source/ngc/pngu.h | 50 +- 8 files changed, 946 insertions(+), 638 deletions(-) diff --git a/source/ngc/fonts/font.ttf b/source/ngc/fonts/font.ttf index 934f65ee6e0d9dbfe4919f3a67374ed4a17b1778..01ce58166c4c97ca7ed556833ac8ecd30a40823c 100644 GIT binary patch literal 55620 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

2kn2N! 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 G$ob#i=3n6e diff --git a/source/ngc/gui/gui_filebrowser.cpp b/source/ngc/gui/gui_filebrowser.cpp index 4caf25f..50f51fb 100644 --- a/source/ngc/gui/gui_filebrowser.cpp +++ b/source/ngc/gui/gui_filebrowser.cpp @@ -109,7 +109,7 @@ GuiFileBrowser::GuiFileBrowser(int w, int h) fileListText[i] = new GuiText(NULL, 20, (GXColor){0, 0, 0, 0xff}); fileListText[i]->SetAlignment(ALIGN_LEFT, ALIGN_MIDDLE); fileListText[i]->SetPosition(5,0); - fileListText[i]->SetMaxWidth(380); + fileListText[i]->SetMaxWidth(450); fileListBg[i] = new GuiImage(bgFileSelectionEntry); fileListIcon[i] = NULL; diff --git a/source/ngc/gui/gui_imagedata.cpp b/source/ngc/gui/gui_imagedata.cpp index b9fbf80..bc2f1e3 100644 --- a/source/ngc/gui/gui_imagedata.cpp +++ b/source/ngc/gui/gui_imagedata.cpp @@ -20,40 +20,7 @@ GuiImageData::GuiImageData(const u8 * i) height = 0; if(i) - { - PNGUPROP imgProp; - IMGCTX ctx = PNGU_SelectImageFromBuffer(i); - - if(!ctx) - return; - - int res = PNGU_GetImageProperties(ctx, &imgProp); - - if(res == PNGU_OK) - { - int len = (imgProp.imgWidth * imgProp.imgHeight) <<2; - if(len%32) len += (32-len%32); - data = (u8 *)memalign (32, len); - - if(data) - { - res = PNGU_DecodeTo4x4RGBA8 (ctx, imgProp.imgWidth, imgProp.imgHeight, data, 255); - - if(res == PNGU_OK) - { - width = imgProp.imgWidth; - height = imgProp.imgHeight; - DCFlushRange(data, len); - } - else - { - free(data); - data = NULL; - } - } - } - PNGU_ReleaseImageContext (ctx); - } + data = DecodePNG(i, &width, &height); } /** diff --git a/source/ngc/gui/gui_text.cpp b/source/ngc/gui/gui_text.cpp index 11d431b..9d0c9f3 100644 --- a/source/ngc/gui/gui_text.cpp +++ b/source/ngc/gui/gui_text.cpp @@ -237,126 +237,130 @@ void GuiText::Draw() fontSystem[newSize] = new FreeTypeGX(newSize); currentSize = newSize; } + + u8 maxChar; - if(maxWidth > 0) - { - char * tmpText = strdup(origText); - u8 maxChar = int((float((maxWidth<<1))) / (float(newSize))); - - if(!textDyn) - { - if(strlen(tmpText) > maxChar) - tmpText[maxChar] = 0; - textDyn = charToWideChar(tmpText); - } - - if(textScroll == SCROLL_HORIZONTAL) - { - int textlen = strlen(origText); - - if(textlen > maxChar && (FrameTimer % textScrollDelay == 0)) - { - if(textScrollInitialDelay) - { - --textScrollInitialDelay; - } - else - { - ++textScrollPos; - if(textScrollPos > textlen-1) - { - textScrollPos = 0; - textScrollInitialDelay = TEXT_SCROLL_INITIAL_DELAY; - } - - strncpy(tmpText, &origText[textScrollPos], maxChar-1); - tmpText[maxChar-1] = 0; - - int dynlen = strlen(tmpText); - - if(dynlen+2 < maxChar) - { - tmpText[dynlen] = ' '; - tmpText[dynlen+1] = ' '; - strncat(&tmpText[dynlen+2], origText, maxChar - dynlen - 2); - } - if(textDyn) delete[] textDyn; - textDyn = charToWideChar(tmpText); - } - } - if(textDyn) - fontSystem[currentSize]->drawText(this->GetLeft(), this->GetTop(), textDyn, c, style); - } - else if(wrap) - { - int lineheight = newSize + 6; - int txtlen = wcslen(text); - int i = 0; - int ch = 0; - int linenum = 0; - int lastSpace = -1; - int lastSpaceIndex = -1; - wchar_t * textrow[20]; - - while(ch < txtlen) - { - if(i == 0) - textrow[linenum] = new wchar_t[txtlen + 1]; - - textrow[linenum][i] = text[ch]; - textrow[linenum][i+1] = 0; - - if(text[ch] == ' ' || ch == txtlen-1) - { - if(wcslen(textrow[linenum]) >= maxChar) - { - if(lastSpace >= 0) - { - textrow[linenum][lastSpaceIndex] = 0; // discard space, and everything after - ch = lastSpace; // go backwards to the last space - lastSpace = -1; // we have used this space - lastSpaceIndex = -1; - } - ++linenum; - i = -1; - } - else if(ch == txtlen-1) - { - ++linenum; - } - } - if(text[ch] == ' ' && i >= 0) - { - lastSpace = ch; - lastSpaceIndex = i; - } - ++ch; - ++i; - } - - int voffset = 0; - - if(alignmentVert == ALIGN_MIDDLE) - voffset = (lineheight >> 1) * (1-linenum); - - int left = this->GetLeft(); - int top = this->GetTop() + voffset; - - for(i=0; i < linenum; ++i) - { - fontSystem[currentSize]->drawText(left, top+i*lineheight, textrow[i], c, style); - delete[] textrow[i]; - } - } - else - { - fontSystem[currentSize]->drawText(this->GetLeft(), this->GetTop(), textDyn, c, style); - } - free(tmpText); - } - else + if(maxWidth == 0) { fontSystem[currentSize]->drawText(this->GetLeft(), this->GetTop(), text, c, style); + goto done; } + + maxChar = int((float((maxWidth<<1))) / (float(newSize))); // approximate + + if(wrap) + { + int lineheight = newSize + 6; + int txtlen = wcslen(text); + int i = 0; + int ch = 0; + int linenum = 0; + int lastSpace = -1; + int lastSpaceIndex = -1; + wchar_t * textrow[20]; + + while(ch < txtlen) + { + if(i == 0) + textrow[linenum] = new wchar_t[txtlen + 1]; + + textrow[linenum][i] = text[ch]; + textrow[linenum][i+1] = 0; + + if(text[ch] == ' ' || ch == txtlen-1) + { + if(wcslen(textrow[linenum]) >= maxChar) + { + if(lastSpace >= 0) + { + textrow[linenum][lastSpaceIndex] = 0; // discard space, and everything after + ch = lastSpace; // go backwards to the last space + lastSpace = -1; // we have used this space + lastSpaceIndex = -1; + } + ++linenum; + i = -1; + } + else if(ch == txtlen-1) + { + ++linenum; + } + } + if(text[ch] == ' ' && i >= 0) + { + lastSpace = ch; + lastSpaceIndex = i; + } + ++ch; + ++i; + } + + int voffset = 0; + + if(alignmentVert == ALIGN_MIDDLE) + voffset = (lineheight >> 1) * (1-linenum); + + int left = this->GetLeft(); + int top = this->GetTop() + voffset; + + for(i=0; i < linenum; ++i) + { + fontSystem[currentSize]->drawText(left, top+i*lineheight, textrow[i], c, style); + delete[] textrow[i]; + } + goto done; + } + + if(textScroll == SCROLL_HORIZONTAL) + { + char *tmpText = strdup(gettext(origText)); + char *tmpText2 = strdup(tmpText); + int textlen = strlen(tmpText); + + if(textlen > maxChar && (FrameTimer % textScrollDelay == 0)) + { + if(textScrollInitialDelay) + { + --textScrollInitialDelay; + } + else + { + ++textScrollPos; + if(textScrollPos > textlen-1) + { + textScrollPos = 0; + textScrollInitialDelay = TEXT_SCROLL_INITIAL_DELAY; + } + + strncpy(tmpText, &tmpText2[textScrollPos], maxChar-1); + tmpText[maxChar-1] = 0; + + int dynlen = strlen(tmpText); + + if(dynlen+2 < maxChar) + { + tmpText[dynlen] = ' '; + tmpText[dynlen+1] = ' '; + strncat(&tmpText[dynlen+2], tmpText2, maxChar - dynlen - 2); + } + if(textDyn) delete[] textDyn; + textDyn = charToWideChar(tmpText); + } + } + free(tmpText); + free(tmpText2); + } + + if(!textDyn) + { + char *tmpText = strdup(gettext(origText)); + if(strlen(tmpText) > maxChar) + tmpText[maxChar] = 0; + textDyn = charToWideChar(tmpText); + free(tmpText); + } + + fontSystem[currentSize]->drawText(this->GetLeft(), this->GetTop(), textDyn, c, style); +done: this->UpdateEffects(); } diff --git a/source/ngc/lang/fr.lang b/source/ngc/lang/fr.lang index 5a00d09..da999b3 100644 --- a/source/ngc/lang/fr.lang +++ b/source/ngc/lang/fr.lang @@ -1,23 +1,53 @@ -msgid " " -msgstr " " - msgid "&" msgstr "&" msgid "16:9 Correction" msgstr "Correction 16:9" +msgid "7z decompression failed: Archive contains too many files" +msgstr "La décompression 7z a échoué : l'archive contient trop de fichiers" + +msgid "7z decompression failed: Failed to read file data" +msgstr "La décompression 7z a échoué : la lecture des données du fichier a échoué" + +msgid "7z decompression failed: File is corrupt" +msgstr "La décompression 7z a échoué : le fichier est corrompu" + +msgid "7z decompression failed: File is corrupt (CRC mismatch)" +msgstr "La décompression 7z a échoué : le fichier est corrompu (erreur de contrôle de redondance cyclique - CRC)" + +msgid "7z decompression failed: File uses too high of compression settings (dictionary size is too large)" +msgstr "La décompression 7z a échoué : le fichier utilise un paramètre de compression trop élevé (taille du dictionnaire trop haute)" + +msgid "7z decompression failed: File uses unsupported compression settings" +msgstr "La décompression 7z a échoué : le fichier utilise des paramètres de compression non supportés" + +msgid "A (Rapid)" +msgstr "A (Rapide)" + +msgid "Aim Offscreen" +msgstr "Visée hors champ" + msgid "An update is available!" -msgstr "Une mise à jour est disponible!" +msgstr "Une mise à jour est disponible !" msgid "Are you sure that you want to reset this game? Any unsaved progress will be lost." msgstr "Êtes-vous sûr de vouloir redémarrer ce jeu ? Toute progression non sauvegardée sera perdue." msgid "Are you sure that you want to reset your mappings?" -msgstr "Êtes-vous sûr de vouloir réinitialiser les touches?" +msgstr "Êtes-vous sûr de vouloir réinitialiser les touches ?" msgid "Are you sure that you want to reset your settings?" -msgstr "Êtes-vous sûr de vouloir réinitialiser les paramètres?" +msgstr "Êtes-vous sûr de vouloir réinitialiser tout les paramètres ?" + +msgid "Maintain Aspect Ratio" +msgstr "Conserver les proportions" + +msgid "Attempting to determine load device..." +msgstr "Tentative de détection du périphérique d'entrée..." + +msgid "Attempting to determine save device..." +msgstr "Tentative de détection du périphérique de sauvegarde..." msgid "Auto" msgstr "Auto" @@ -34,6 +64,9 @@ msgstr "Sauvegarde Auto" msgid "Automatic (Recommended)" msgstr "Automatique (Recommandé)" +msgid "B (Rapid)" +msgstr "B (Rapide)" + msgid "Back" msgstr "Retour" @@ -56,7 +89,7 @@ msgid "Cheats" msgstr "Cheats" msgid "Cheats file not found!" -msgstr "Fichier Cheats non trouvé!" +msgstr "Fichier Cheats non trouvé !" msgid "Cheats Folder" msgstr "Dossier Cheats" @@ -74,7 +107,13 @@ msgid "Coding" msgstr "Programmation" msgid "Coding & menu design" -msgstr "Program. & design du menu" +msgstr "Prog. & design du menu" + +msgid "Compressed GBA files are not supported!" +msgstr "Les fichiers GBA compressés ne sont pas supportés !" + +msgid "Connecting to network share..." +msgstr "Connection au partage réseau en cours..." msgid "Controller" msgstr "Contrôleur" @@ -88,12 +127,30 @@ msgstr "Dossier des jaquettes" msgid "Credits" msgstr "Crédits" +msgid "Cropping" +msgstr "Recadrage" + +msgid "Crosshair" +msgstr "Réticule de visée" + +msgid "Cursor" +msgstr "Curseur" + +msgid "Data DVD" +msgstr "Données DVD" + msgid "Default" msgstr "Par défaut" +msgid "Directory name is too long!" +msgstr "Le nom du répertoire est trop long !" + msgid "Disabled" msgstr "Désactivé" +msgid "DISABLED" +msgstr "DÉSACTIVÉ" + msgid "distributed, or modified under the terms of the" msgstr "distribuée, ou modifiée selon les termes de" @@ -106,17 +163,65 @@ msgstr "Bas" msgid "DOWN" msgstr "BAS" +msgid "Downloading..." +msgstr "Téléchargement en cours..." + +msgid "Dutch" +msgstr "Néerlandais" + +msgid "Empty or invalid ZIP file!" +msgstr "Fichier ZIP vide ou invalide !" + msgid "Enabled" msgstr "Activé" +msgid "ENABLED" +msgstr "ACTIVÉ" + +msgid "English" +msgstr "Anglais" + msgid "Error" msgstr "Erreur" +msgid "Error - Invalid ZIP file!" +msgstr "Erreur - Fichier ZIP invalide !" + +msgid "Error creating file!" +msgstr "Une erreur est survenue à la création du fichier !" + +msgid "Error loading game!" +msgstr "Erreur de chargement du jeu !" + +msgid "Error opening archive!" +msgstr "Erreur lors de l'ouverture de l'archive !" + +msgid "Error opening directory!" +msgstr "Erreur lors de l'ouverture du répertoire !" + +msgid "Error opening file!" +msgstr "Erreur lors de l'ouverture du fichier !" + +msgid "Error reading file!" +msgstr "Une erreur est survenue à la lecture du fichier !" + +msgid "Error saving file!" +msgstr "Erreur lors de la sauvegarde du fichier !" + msgid "Exit" msgstr "Sortir" msgid "Exit Action" -msgstr "Sortie de SNES9xGx" +msgstr "Sortie de l'émulateur" + +msgid "Failed to connect to network share." +msgstr "La connection au partage réseau a échoué." + +msgid "FDS BIOS file is invalid!" +msgstr "Le fichier du BIOS du FDS (Famicom Disk System) est invalide !" + +msgid "FDS BIOS file not found!" +msgstr "Le fichier du BIOS du FDS (Famicom Disk System) est introuvable !" msgid "Filtered" msgstr "Filtré" @@ -124,6 +229,18 @@ msgstr "Filtré" msgid "Filtering" msgstr "Filtrage" +msgid "Fire" +msgstr "Tirer" + +msgid "French" +msgstr "Français" + +msgid "GBA Screen Zoom" +msgstr "Zoom écran GBA" + +msgid "Game Genie ROM not found!" +msgstr "La ROM Game Genie est introuvable !" + msgid "Game Settings" msgstr "Configuration" @@ -136,9 +253,21 @@ msgstr "Configuration - Cheats" msgid "Game Settings - Video" msgstr "Configuration - Vidéo" +msgid "Game Timing" +msgstr "Timing du jeu" + +msgid "Game Genie DISABLED" +msgstr "Game Genie Désactivé" + +msgid "Game Genie ENABLED" +msgstr "Game Genie Activé" + msgid "GameCube Controller" msgstr "Manette Gamecube" +msgid "German" +msgstr "Allemand" + msgid "GNU General Public License (GPL) Version 2." msgstr "la Licence Publique Générale (GPL) GNU Version 2." @@ -151,8 +280,56 @@ msgstr "Horizontal" msgid "Information" msgstr "Information" +msgid "Initializing network..." +msgstr "Initialisation du réseau en cours..." + +msgid "Insert Coin" +msgstr "Insérer une pièce" + +msgid "Insert Coin / Switch Disk" +msgstr "Insér. une pièce/Chang. disq." + +msgid "Invalid file size!" +msgstr "Taille du fichier invalide" + +msgid "Invalid game file!" +msgstr "Taille du fichier du jeu invalide" + +msgid "Invalid network settings - Check settings.xml." +msgstr "Paramètres réseau invalides - Veuillez vérifier le fichier settings.xml." + +msgid "Invalid network settings - Share IP is blank." +msgstr "Paramètres réseau invalides - L'IP partagée n'est pas renseignée." + +msgid "Invalid network settings - Share name is blank." +msgstr "Paramètres réseau invalides - Le nom du partage n'est pas renseigné." + +msgid "Invalid save file" +msgstr "Fichier de sauvegarde invalide" + +msgid "Invalid state file" +msgstr "Fichier de sauvegarde d'état invalide" + +msgid "Italian" +msgstr "Italien" + +msgid "Japanese" +msgstr "Japonais" + msgid "Justifier" -msgstr "Justifier" +msgstr "Konami Justifier" + +msgid "Justifier - GameCube Controller" +msgstr "Konami Justifier - Manette GameCube" + +msgid "Justifier - Wiimote" +msgstr "Konami Justifier - Wiimote" + +msgid "Korean" +msgstr "Coréen" + +msgid "L TRIG" +msgstr "L" msgid "Language" msgstr "Langage" @@ -166,6 +343,9 @@ msgstr "Gauche" msgid "LEFT" msgstr "GAUCHE" +msgid "Left Button" +msgstr "Clic gauche" + msgid "Load" msgstr "Charger" @@ -181,9 +361,24 @@ msgstr "Charger une partie" msgid "Loading" msgstr "Chargement" +msgid "Loading DVD..." +msgstr "Chargement du DVD en cours..." + +msgid "Loading patch..." +msgstr "Chargement du patch en cours..." + +msgid "Loading..." +msgstr "Chargement en cours..." + msgid "Main Menu" msgstr "Menu Principal" +msgid "Match Wii Controls" +msgstr "Jouabilité Wii identique" + +msgid "Maximum filepath length reached!" +msgid "La longueur maximale du chemin d'accés est atteinte !" + msgid "Menu" msgstr "Menu" @@ -202,21 +397,54 @@ msgstr "Volume de la Musique" msgid "Mute" msgstr "Muet" +msgid "NES Controller" +msgstr "Manette NES" + +msgid "NES Controllers (2)" +msgstr "Manettes NES (2)" + +msgid "NES Controllers (4)" +msgstr "Manettes NES (4)" + +msgid "NES Zapper" +msgstr "Nintendo Zapper" + msgid "Network" msgstr "Réseau" +msgid "Network Share" +msgstr "Partage réseau" + msgid "New" -msgstr "Nouv." +msgstr "Nouvelle" + +msgid "New Snapshot" +msgstr "Nouvelle sauvegarde d'état" + +msgid "New SRAM" +msgstr "Nouvelle sauvegarde SRAM" msgid "No" -msgstr "Non" +msgstr "Non" -msgid "None" -msgstr "Aucun" +msgid "No data to save!" +msgstr "Pas de données (RAM) à sauvegarder !" + +msgid "No disc inserted!" +msgstr "Aucun disque inséré !" + +msgid "No SRAM data to save!" +msgstr "Pas de données SRAM à sauvegarder !" + + msgid "No game saves found." msgstr "Aucune sauvegarde trouvée." +msgid "None" + +msgstr "Aucun" + msgid "NTSC (480i)" msgstr "NTSC (480i)" @@ -226,9 +454,15 @@ msgstr "Nunchuk" msgid "Off" msgstr "Off" +msgid "Official Site: http://code.google.com/p/fceugc/" +msgstr "Site Officiel: http://code.google.com/p/fceugc/" + msgid "Official Site: http://code.google.com/p/snes9x-gx/" msgstr "Site Officiel: http://code.google.com/p/snes9x-gx/" +msgid "Official Site: http://code.google.com/p/vba-wii/" +msgstr "Site Officiel: http://code.google.com/p/vba-wii/" + msgid "OK" msgstr "OK" @@ -238,20 +472,56 @@ msgstr "On" msgid "Original" msgstr "Original" +msgid "Out of memory!" +msgstr "Mémoire insuffisante !" + +msgid "Out of memory: too many files!" +msgstr "Mémoire insuffisante : trop de fichiers !" + +msgid "P 1" +msgstr "J1" + +msgid "P2" +msgstr "J2" + +msgid "P3" +msgstr "J3" + +msgid "P4" +msgstr "J4" + msgid "PAL (50Hz)" msgstr "PAL (50Hz)" msgid "PAL (60Hz)" msgstr "PAL (60Hz)" +msgid "Palette saved" +msgstr "La palette est sauvegardée" + +msgid "Partial Stretch" +msgstr "Étirer partiellement" + +msgid "Pause" +msgstr "Pause" + +msgid "Please install IOS 202 for DVD support." +msgstr "Veuillez installer l'IOS 202 pour le support du DVD" + msgid "Please Wait" msgstr "Veuillez patienter" msgid "PLUS" msgstr "PLUS" +msgid "Portuguese" +msgstr "Portugais" + msgid "Power off Wii" -msgstr "Eteindre la Wii" +msgstr "Éteindre la Wii" + +msgid "Preferences saved" +msgstr "Les préférences ont été sauvegardés" msgid "Press any button on the Classic Controller now. Press Home to clear the existing mapping." msgstr "Appuyer sur un bouton de la manette Classique. Appuyer sur HOME pour effacer le paramètre actuel." @@ -277,6 +547,12 @@ msgstr "Quitter le Jeu" msgid "Quit this game? Any unsaved progress will be lost." msgstr "Quitter ce jeu ? Toute progression non sauvegardée sera perdue." +msgid "R TRIG" +msgstr "R" + +msgid "RAM saving is not available for FDS games!" +msgstr "La sauvegarde RAM n'est pas disponible pour les jeux sur disquette (Famicom Disk System) !" + msgid "Reboot" msgstr "Redémarrer" @@ -289,6 +565,9 @@ msgstr "Réinitialiser" msgid "Reset Game" msgstr "Réinitialiser le Jeu" +msgid "Reset this game? Any unsaved progress will be lost." +msgstr "Redémarrer ce jeu ? Toute progression non sauvegardée sera perdue." + msgid "Reset Mappings" msgstr "Réinit. les touches" @@ -310,6 +589,9 @@ msgstr "Droite" msgid "RIGHT" msgstr "DROITE" +msgid "Right Button" +msgstr "Clic droit" + msgid "Rumble" msgstr "Vibration" @@ -319,17 +601,29 @@ msgstr "Sauver" msgid "Save Device" msgstr "Périph. de sauvegarde" +msgid "Save failed!" +msgstr "La sauvegarde a échoué !" + +msgid "Save file not found" +msgstr "Pas de fichier de sauvegarde trouvé" + msgid "Save Folder" msgstr "Dossier des sauv." msgid "Save Game" msgstr "Sauvegarder la partie" +msgid "Save RAM and State?" +msgstr "Sauver la RAM et la position du jeu (sauvegarde d'état) ?" + msgid "Save Snapshot?" -msgstr "Sauver la position du jeu ?" +msgstr "Sauver la position du jeu (sauvegarde d'état) ?" msgid "Save SRAM and Snapshot?" -msgstr "Sauver la SRAM et la position du jeu ?" +msgstr "Sauver la SRAM et la position du jeu (sauvegarde d'état) ?" + +msgid "Save State?" +msgstr "Sauver la position du jeu (sauvegarde d'état) ?" msgid "Save successful" msgstr "Sauvegarde réussie" @@ -337,6 +631,12 @@ msgstr "Sauvegarde réussie" msgid "Saving" msgstr "Sauvegarde" +msgid "Saving preferences..." +msgstr "Sauvegarde des préférences en cours..." + +msgid "Saving..." +msgstr "Sauvegarde en cours..." + msgid "Scaling" msgstr "Format" @@ -346,6 +646,12 @@ msgstr "Position de l'écran" msgid "Screen Zoom" msgstr "Zoom écran" +msgid "Select" +msgstr "Select" + +msgid "Seek error!" +msgstr "Erreur de positionnement ! (seek error)" + msgid "Settings" msgstr "Paramètres" @@ -356,25 +662,37 @@ msgid "Settings - Network" msgstr "Paramètres - Réseau" msgid "Settings - Saving & Loading" -msgstr "Paramètres - Sauv. & Chargement" +msgstr "Paramètres - Sauvegarde & Chargement" + +msgid "SD Card" +msgstr "Carte SD" + +msgid "SD card not found!" +msgstr "Carte SD introuvable !" msgid "Shift" msgstr "Maj" +msgid "Simp_chinese" +msgstr "Chinois simplifié" + msgid "SMB Share IP" -msgstr "IP Partage SMB" +msgstr "IP partagée SMB" msgid "SMB Share Name" -msgstr "Nom Partage SMB" +msgstr "Nom du Partage SMB" msgid "SMB Share Password" -msgstr "Mot de passe partage SMB" +msgstr "Mot de passe de partage SMB" msgid "SMB Share Username" -msgstr "Utilisateur Partage SMB" +msgstr "Nom d'utilisateur de partage SMB" msgid "Snapshot" -msgstr "Sauv. d'état" +msgstr "Sauvegarde d'état" + +msgid "Snapshot (Auto)" +msgstr "Sauv. d'état (Auto)" msgid "SNES Controller" msgstr "Manette SNES" @@ -385,27 +703,93 @@ msgstr "Manettes SNES (2)" msgid "SNES Controllers (4)" msgstr "Manettes SNES (4)" -msgid "SNES Mouse" -msgstr "Souris SNES" +msgid "SNES Controller - Classic Controller" +msgstr "Manette SNES - Manette Classique" + +msgid "SNES Controller - GameCube Controller" +msgstr "Manette SNES - Manette GameCube" + +msgid "SNES Controller - Nunchuk + Wiimote" +msgstr "Manette SNES - Nunchuk + Wiimote" + +msgid "SNES Controller - Wiimote" +msgstr "Manette SNES - Wiimote" msgid "SNES Mouse" msgstr "Souris SNES" +msgid "SNES Mouse - GameCube Controller" +msgstr "Souris SNES - Manette GameCube" + +msgid "SNES Mouse - Wiimote" +msgstr "Souris SNES - Wiimote" + msgid "Snes9x - Copyright (c) Snes9x Team 1996 - 2006" msgstr "Snes9x - Copyright (c) Snes9x Team 1996 - 2006" msgid "Sound Effects Volume" msgstr "Volume des effets sonores" -msgid "Super Scope" +msgid "Spanish" +msgstr "Espagnol" + +msgid "Sprite Limit" +msgstr "Limite de Sprites" + +msgid "SRAM file not found" +msgstr "Pas de sauvegarde SRAM trouvée" + +msgid "State" +msgstr "Sauvegarde d'état" + +msgid "State (Auto)" +msgstr "Sauv. d'état (Auto)" + +msgid "State file not found" +msgstr "Pas de sauvegarde d'état trouvée" + +msgid "Stretch to Fit" +msgstr "Plein écran" + +msgid "Superscope" msgstr "Super Scope" +msgid "Superscope - GameCube Controller" +msgstr "Super Scope - Manette GameCube" + +msgid "Superscope - Wiimote" +msgstr "Super Scope - Wiimote" + msgid "This software is open source and may be copied," msgstr "Cette application est libre et peut être copiée," +msgid "Trad_chinese" +msgstr "Chinois traditionnel" + +msgid "Unable to initialize network!" +msgstr "Impossible d'initialiser le réseau !" + +msgid "Unable to locate a load device!" +msgstr "Périphérique d'entrée introuvable !" + +msgid "Unable to locate a save device!" +msgstr "Périphérique de sauvegarde introuvable !" + +msgid "Unable to open snapshot!" +msgstr "Impossible d'ouvrir la sauvegarde d'état" + msgid "Unfiltered" msgstr "Non-filtré" +msgid "Unknown file type!" +msgstr "Type de fichier inconnu !" + +msgid "Unrecognized DVD format." +msgstr "Format du DVD inconnu." + +msgid "Unrecognized file extension!" +msgstr "L'extension du fichier est inconnu !" + msgid "Up" msgstr "Haut" @@ -418,11 +802,23 @@ msgstr "Dossier Parent" msgid "Update Available" msgstr "Mise à jour disponible" +msgid "Update failed!" +msgstr "La mise à jour a échouée !" + msgid "Update later" -msgstr "Mise à jour Plus tard" +msgstr "Mise à jour plus tard" msgid "Update now" -msgstr "Mise à jour Maintenant" +msgstr "Mise à jour maintenant" + +msgid "Update successful!" +msgstr "La mise à jour a réussie !" + +msgid "USB drive not found!" +msgstr "Aucun disque USB n'a été trouvé !" + +msgid "USB Mass Storage" +msgstr "Périphérique de stockage USB" msgid "Vertical" msgstr "Vertical" @@ -433,6 +829,15 @@ msgstr "Vidéo" msgid "Video Mode" msgstr "Mode Vidéo" +msgid "VM8: Unknown page type!" +msgstr "VM8 : Type de page inconnu !" + +msgid "VM16: Unknown page type!" +msgstr "VM16 : Type de page inconnu !" + +msgid "VM32: Unknown page type!" +msgstr "VM32 : Type de page inconnu !" + msgid "Wiimote" msgstr "Wiimote" @@ -441,4 +846,9 @@ msgstr "Orientation de la Wiimote" msgid "Yes" msgstr "Oui" - \ No newline at end of file + +msgid "Zapper" +msgstr "Nintendo Zapper" + +msgid "Zapper Crosshair" +msgstr "Réticule du Zapper" \ No newline at end of file diff --git a/source/ngc/menu.cpp b/source/ngc/menu.cpp index e2dfccc..3a8fad7 100644 --- a/source/ngc/menu.cpp +++ b/source/ngc/menu.cpp @@ -795,41 +795,41 @@ static void WindowCredits(void * ptr) FTGX_JUSTIFY_LEFT | FTGX_ALIGN_TOP, ALIGN_LEFT, ALIGN_TOP); txt[i] = new GuiText("Coding & menu design"); - txt[i]->SetPosition(40,y); i++; + txt[i]->SetPosition(60,y); i++; txt[i] = new GuiText("Tantric"); - txt[i]->SetPosition(335,y); i++; y+=24; + txt[i]->SetPosition(350,y); i++; y+=24; txt[i] = new GuiText("Coding"); - txt[i]->SetPosition(40,y); i++; + txt[i]->SetPosition(60,y); i++; txt[i] = new GuiText("michniewski"); - txt[i]->SetPosition(335,y); i++; y+=24; + txt[i]->SetPosition(350,y); i++; y+=24; txt[i] = new GuiText("Menu artwork"); - txt[i]->SetPosition(40,y); i++; + txt[i]->SetPosition(60,y); i++; txt[i] = new GuiText("the3seashells"); - txt[i]->SetPosition(335,y); i++; y+=24; + txt[i]->SetPosition(350,y); i++; y+=24; txt[i] = new GuiText("Menu sound"); - txt[i]->SetPosition(40,y); i++; + txt[i]->SetPosition(60,y); i++; txt[i] = new GuiText("Peter de Man"); - txt[i]->SetPosition(335,y); i++; y+=48; + txt[i]->SetPosition(350,y); i++; y+=48; txt[i] = new GuiText("Snes9x GX GameCube"); - txt[i]->SetPosition(40,y); i++; + txt[i]->SetPosition(60,y); i++; txt[i] = new GuiText("SoftDev, crunchy2,"); - txt[i]->SetPosition(335,y); i++; y+=24; + txt[i]->SetPosition(350,y); i++; y+=24; txt[i] = new GuiText("eke-eke, others"); - txt[i]->SetPosition(335,y); i++; y+=24; + txt[i]->SetPosition(350,y); i++; y+=24; txt[i] = new GuiText("Snes9x"); - txt[i]->SetPosition(40,y); i++; + txt[i]->SetPosition(60,y); i++; txt[i] = new GuiText("Snes9x Team"); - txt[i]->SetPosition(335,y); i++; y+=24; + txt[i]->SetPosition(350,y); i++; y+=24; txt[i] = new GuiText("libogc / devkitPPC"); - txt[i]->SetPosition(40,y); i++; + txt[i]->SetPosition(60,y); i++; txt[i] = new GuiText("shagkur & wintermute"); - txt[i]->SetPosition(335,y); i++; y+=24; + txt[i]->SetPosition(350,y); i++; y+=24; txt[i] = new GuiText("FreeTypeGX"); - txt[i]->SetPosition(40,y); i++; + txt[i]->SetPosition(60,y); i++; txt[i] = new GuiText("Armin Tamzarian"); - txt[i]->SetPosition(335,y); i++; y+=48; + txt[i]->SetPosition(350,y); i++; y+=48; txt[i]->SetPresets(18, (GXColor){0, 0, 0, 255}, 0, FTGX_JUSTIFY_CENTER | FTGX_ALIGN_TOP, ALIGN_CENTRE, ALIGN_TOP); @@ -3724,7 +3724,7 @@ static int MenuSettingsNetwork() GuiOptionBrowser optionBrowser(552, 248, &options); optionBrowser.SetPosition(0, 108); optionBrowser.SetAlignment(ALIGN_CENTRE, ALIGN_TOP); - optionBrowser.SetCol2Position(275); + optionBrowser.SetCol2Position(290); HaltGui(); GuiWindow w(screenwidth, screenheight); diff --git a/source/ngc/pngu.c b/source/ngc/pngu.c index e3a0293..f621220 100644 --- a/source/ngc/pngu.c +++ b/source/ngc/pngu.c @@ -1,31 +1,41 @@ /******************************************************************************************** - -PNGU Version : 0.2a - -Coder : frontier - -More info : http://frontier-dev.net - -Modified by Tantric, 2009 - +* +* PNGU +* +* Original author: frontier (http://frontier-dev.net) +* Modified by Tantric, 2009-2010 +* ********************************************************************************************/ + #include #include +#include #include "pngu.h" -#include "png.h" +#include // Constants -#define PNGU_SOURCE_BUFFER 1 -#define PNGU_SOURCE_DEVICE 2 +#define PNGU_SOURCE_BUFFER 1 +#define PNGU_SOURCE_DEVICE 2 -// Prototypes of helper functions -int pngu_info (IMGCTX ctx); -int pngu_decode (IMGCTX ctx, PNGU_u32 width, PNGU_u32 height, PNGU_u32 stripAlpha); -void pngu_free_info (IMGCTX ctx); -void pngu_read_data_from_buffer (png_structp png_ptr, png_bytep data, png_size_t length); -void pngu_write_data_to_buffer (png_structp png_ptr, png_bytep data, png_size_t length); -void pngu_flush_data_to_buffer (png_structp png_ptr); -int pngu_clamp (int value, int min, int max); +// Return codes +#define PNGU_OK 0 +#define PNGU_ODD_WIDTH 1 +#define PNGU_ODD_STRIDE 2 +#define PNGU_INVALID_WIDTH_OR_HEIGHT 3 +#define PNGU_FILE_IS_NOT_PNG 4 +#define PNGU_UNSUPPORTED_COLOR_TYPE 5 +#define PNGU_NO_FILE_SELECTED 6 +#define PNGU_CANT_OPEN_FILE 7 +#define PNGU_CANT_READ_FILE 8 +#define PNGU_LIB_ERROR 9 + +// Color types +#define PNGU_COLOR_TYPE_GRAY 1 +#define PNGU_COLOR_TYPE_GRAY_ALPHA 2 +#define PNGU_COLOR_TYPE_PALETTE 3 +#define PNGU_COLOR_TYPE_RGB 4 +#define PNGU_COLOR_TYPE_RGB_ALPHA 5 +#define PNGU_COLOR_TYPE_UNKNOWN 6 // PNGU Image context struct struct _IMGCTX @@ -49,362 +59,42 @@ struct _IMGCTX // PNGU Implementation -IMGCTX PNGU_SelectImageFromBuffer (const void *buffer) +static void pngu_free_info (IMGCTX ctx) { - IMGCTX ctx = NULL; - - if (!buffer) - return NULL; - - ctx = malloc (sizeof (struct _IMGCTX)); - if (!ctx) - return NULL; - - ctx->buffer = (void *) buffer; - ctx->source = PNGU_SOURCE_BUFFER; - ctx->cursor = 0; - ctx->filename = NULL; - ctx->propRead = 0; - ctx->infoRead = 0; - - return ctx; -} - -IMGCTX PNGU_SelectImageFromDevice (const char *filename) -{ - IMGCTX ctx = NULL; - - if (!filename) - return NULL; - - ctx = malloc (sizeof (struct _IMGCTX)); - if (!ctx) - return NULL; - - ctx->buffer = NULL; - ctx->source = PNGU_SOURCE_DEVICE; - ctx->cursor = 0; - - ctx->filename = malloc (strlen (filename) + 1); - if (!ctx->filename) - { - free (ctx); - return NULL; - } - strcpy(ctx->filename, filename); - - ctx->propRead = 0; - ctx->infoRead = 0; - - return ctx; -} - -void PNGU_ReleaseImageContext (IMGCTX ctx) -{ - if (!ctx) - return; - - if (ctx->filename) - free (ctx->filename); - - if ((ctx->propRead) && (ctx->prop.trans)) - free (ctx->prop.trans); - - pngu_free_info (ctx); - free (ctx); -} - -int PNGU_GetImageProperties (IMGCTX ctx, PNGUPROP *imgprop) -{ - int res; - - if (!ctx->propRead) - { - res = pngu_info (ctx); - if (res != PNGU_OK) - return res; - } - - *imgprop = ctx->prop; - return PNGU_OK; -} - -int PNGU_DecodeTo4x4RGBA8 (IMGCTX ctx, PNGU_u32 width, PNGU_u32 height, void *buffer, PNGU_u8 default_alpha) -{ - int result; - PNGU_u32 x, y, qwidth, qheight; - PNGU_u64 alphaMask; - - // width and height need to be divisible by four - if ((width % 4) || (height % 4)) - return PNGU_INVALID_WIDTH_OR_HEIGHT; - - result = pngu_decode (ctx, width, height, 0); - if (result != PNGU_OK) - return result; - - // Init some variables - qwidth = width >> 2; - qheight = height >> 2; - - // Check is source image has an alpha channel - if ( (ctx->prop.imgColorType == PNGU_COLOR_TYPE_GRAY_ALPHA) || (ctx->prop.imgColorType == PNGU_COLOR_TYPE_RGB_ALPHA) ) - { - // Alpha channel present, copy image to the output buffer - for (y = 0; y < qheight; y++) - for (x = 0; x < qwidth; x++) - { - int blockbase = (y * qwidth + x) << 3; - - PNGU_u32 y4 = y << 2; - PNGU_u32 x16 = x << 4; - - PNGU_u64 fieldA = *((PNGU_u64 *)(ctx->row_pointers[y4]+x16)); - PNGU_u64 fieldB = *((PNGU_u64 *)(ctx->row_pointers[y4]+x16+8)); - ((PNGU_u64 *) buffer)[blockbase] = - ((fieldA & 0xFF00000000ULL) << 24) | ((fieldA & 0xFF00000000000000ULL) >> 8) | - ((fieldA & 0xFFULL) << 40) | ((fieldA & 0xFF000000ULL) << 8) | - ((fieldB & 0xFF00000000ULL) >> 8) | ((fieldB & 0xFF00000000000000ULL) >> 40) | - ((fieldB & 0xFFULL) << 8) | ((fieldB & 0xFF000000ULL) >> 24); - ((PNGU_u64 *) buffer)[blockbase+4] = - ((fieldA & 0xFFFF0000000000ULL) << 8) | ((fieldA & 0xFFFF00ULL) << 24) | - ((fieldB & 0xFFFF0000000000ULL) >> 24) | ((fieldB & 0xFFFF00ULL) >> 8); - - fieldA = *((PNGU_u64 *)(ctx->row_pointers[y4+1]+x16)); - fieldB = *((PNGU_u64 *)(ctx->row_pointers[y4+1]+x16+8)); - ((PNGU_u64 *) buffer)[blockbase+1] = - ((fieldA & 0xFF00000000ULL) << 24) | ((fieldA & 0xFF00000000000000ULL) >> 8) | - ((fieldA & 0xFFULL) << 40) | ((fieldA & 0xFF000000ULL) << 8) | - ((fieldB & 0xFF00000000ULL) >> 8) | ((fieldB & 0xFF00000000000000ULL) >> 40) | - ((fieldB & 0xFFULL) << 8) | ((fieldB & 0xFF000000ULL) >> 24); - ((PNGU_u64 *) buffer)[blockbase+5] = - ((fieldA & 0xFFFF0000000000ULL) << 8) | ((fieldA & 0xFFFF00ULL) << 24) | - ((fieldB & 0xFFFF0000000000ULL) >> 24) | ((fieldB & 0xFFFF00ULL) >> 8); - - fieldA = *((PNGU_u64 *)(ctx->row_pointers[y4+2]+x16)); - fieldB = *((PNGU_u64 *)(ctx->row_pointers[y4+2]+x16+8)); - ((PNGU_u64 *) buffer)[blockbase+2] = - ((fieldA & 0xFF00000000ULL) << 24) | ((fieldA & 0xFF00000000000000ULL) >> 8) | - ((fieldA & 0xFFULL) << 40) | ((fieldA & 0xFF000000ULL) << 8) | - ((fieldB & 0xFF00000000ULL) >> 8) | ((fieldB & 0xFF00000000000000ULL) >> 40) | - ((fieldB & 0xFFULL) << 8) | ((fieldB & 0xFF000000ULL) >> 24); - ((PNGU_u64 *) buffer)[blockbase+6] = - ((fieldA & 0xFFFF0000000000ULL) << 8) | ((fieldA & 0xFFFF00ULL) << 24) | - ((fieldB & 0xFFFF0000000000ULL) >> 24) | ((fieldB & 0xFFFF00ULL) >> 8); - - fieldA = *((PNGU_u64 *)(ctx->row_pointers[y4+3]+x16)); - fieldB = *((PNGU_u64 *)(ctx->row_pointers[y4+3]+x16+8)); - ((PNGU_u64 *) buffer)[blockbase+3] = - ((fieldA & 0xFF00000000ULL) << 24) | ((fieldA & 0xFF00000000000000ULL) >> 8) | - ((fieldA & 0xFFULL) << 40) | ((fieldA & 0xFF000000ULL) << 8) | - ((fieldB & 0xFF00000000ULL) >> 8) | ((fieldB & 0xFF00000000000000ULL) >> 40) | - ((fieldB & 0xFFULL) << 8) | ((fieldB & 0xFF000000ULL) >> 24); - ((PNGU_u64 *) buffer)[blockbase+7] = - ((fieldA & 0xFFFF0000000000ULL) << 8) | ((fieldA & 0xFFFF00ULL) << 24) | - ((fieldB & 0xFFFF0000000000ULL) >> 24) | ((fieldB & 0xFFFF00ULL) >> 8); - } - } - else - { - // No alpha channel present, copy image to the output buffer - alphaMask = (((PNGU_u64)default_alpha) << 56) | (((PNGU_u64)default_alpha) << 40) | - (((PNGU_u64)default_alpha) << 24) | (((PNGU_u64)default_alpha) << 8); - - for (y = 0; y < qheight; y++) - for (x = 0; x < qwidth; x++) - { - int blockbase = (y * qwidth + x) << 3; - - PNGU_u32 y4 = y << 2; - PNGU_u32 x12 = x * 12; - - PNGU_u64 field64 = *((PNGU_u64 *)(ctx->row_pointers[y4]+x12)); - PNGU_u64 field32 = (PNGU_u64) *((PNGU_u32 *)(ctx->row_pointers[y4]+x12+8)); - ((PNGU_u64 *) buffer)[blockbase] = - (((field64 & 0xFF00000000000000ULL) >> 8) | (field64 & 0xFF00000000ULL) | - ((field64 & 0xFF00ULL) << 8) | ((field32 & 0xFF0000ULL) >> 16) | alphaMask); - ((PNGU_u64 *) buffer)[blockbase+4] = - (((field64 & 0xFFFF0000000000ULL) << 8) | ((field64 & 0xFFFF0000ULL) << 16) | - ((field64 & 0xFFULL) << 24) | ((field32 & 0xFF000000ULL) >> 8) | (field32 & 0xFFFFULL)); - - field64 = *((PNGU_u64 *)(ctx->row_pointers[y4+1]+x12)); - field32 = (PNGU_u64) *((PNGU_u32 *)(ctx->row_pointers[y4+1]+x12+8)); - ((PNGU_u64 *) buffer)[blockbase+1] = - (((field64 & 0xFF00000000000000ULL) >> 8) | (field64 & 0xFF00000000ULL) | - ((field64 & 0xFF00ULL) << 8) | ((field32 & 0xFF0000ULL) >> 16) | alphaMask); - ((PNGU_u64 *) buffer)[blockbase+5] = - (((field64 & 0xFFFF0000000000ULL) << 8) | ((field64 & 0xFFFF0000ULL) << 16) | - ((field64 & 0xFFULL) << 24) | ((field32 & 0xFF000000ULL) >> 8) | (field32 & 0xFFFFULL)); - - field64 = *((PNGU_u64 *)(ctx->row_pointers[y4+2]+x12)); - field32 = (PNGU_u64) *((PNGU_u32 *)(ctx->row_pointers[y4+2]+x12+8)); - ((PNGU_u64 *) buffer)[blockbase+2] = - (((field64 & 0xFF00000000000000ULL) >> 8) | (field64 & 0xFF00000000ULL) | - ((field64 & 0xFF00ULL) << 8) | ((field32 & 0xFF0000ULL) >> 16) | alphaMask); - ((PNGU_u64 *) buffer)[blockbase+6] = - (((field64 & 0xFFFF0000000000ULL) << 8) | ((field64 & 0xFFFF0000ULL) << 16) | - ((field64 & 0xFFULL) << 24) | ((field32 & 0xFF000000ULL) >> 8) | (field32 & 0xFFFFULL)); - - field64 = *((PNGU_u64 *)(ctx->row_pointers[y4+3]+x12)); - field32 = (PNGU_u64) *((PNGU_u32 *)(ctx->row_pointers[y4+3]+x12+8)); - ((PNGU_u64 *) buffer)[blockbase+3] = - (((field64 & 0xFF00000000000000ULL) >> 8) | (field64 & 0xFF00000000ULL) | - ((field64 & 0xFF00ULL) << 8) | ((field32 & 0xFF0000ULL) >> 16) | alphaMask); - ((PNGU_u64 *) buffer)[blockbase+7] = - (((field64 & 0xFFFF0000000000ULL) << 8) | ((field64 & 0xFFFF0000ULL) << 16) | - ((field64 & 0xFFULL) << 24) | ((field32 & 0xFF000000ULL) >> 8) | (field32 & 0xFFFFULL)); - } - } - - // Free resources - free (ctx->img_data); - free (ctx->row_pointers); - - // Success - return PNGU_OK; -} - -int PNGU_EncodeFromRGB (IMGCTX ctx, PNGU_u32 width, PNGU_u32 height, void *buffer, PNGU_u32 stride) -{ - png_uint_32 rowbytes; - PNGU_u32 y; - - // Erase from the context any readed info - pngu_free_info (ctx); - ctx->propRead = 0; - - // Check if the user has selected a file to write the image - if (ctx->source == PNGU_SOURCE_BUFFER); - - else if (ctx->source == PNGU_SOURCE_DEVICE) - { - // Open file - if (!(ctx->fd = fopen (ctx->filename, "wb"))) - return PNGU_CANT_OPEN_FILE; - } - - else - return PNGU_NO_FILE_SELECTED; - - // Allocation of libpng structs - ctx->png_ptr = png_create_write_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); - if (!(ctx->png_ptr)) + if (ctx->infoRead) { if (ctx->source == PNGU_SOURCE_DEVICE) fclose (ctx->fd); - return PNGU_LIB_ERROR; + + png_destroy_read_struct (&(ctx->png_ptr), &(ctx->info_ptr), (png_infopp)NULL); + + ctx->infoRead = 0; } - - ctx->info_ptr = png_create_info_struct (ctx->png_ptr); - if (!(ctx->info_ptr)) - { - png_destroy_write_struct (&(ctx->png_ptr), (png_infopp)NULL); - if (ctx->source == PNGU_SOURCE_DEVICE) - fclose (ctx->fd); - return PNGU_LIB_ERROR; - } - - if (ctx->source == PNGU_SOURCE_BUFFER) - { - // Installation of our custom data writer function - ctx->cursor = 0; - png_set_write_fn (ctx->png_ptr, ctx, pngu_write_data_to_buffer, pngu_flush_data_to_buffer); - } - else if (ctx->source == PNGU_SOURCE_DEVICE) - { - // Default data writer uses function fwrite, so it needs to use our FILE* - png_init_io (ctx->png_ptr, ctx->fd); - } - - // Setup output file properties - png_set_IHDR (ctx->png_ptr, ctx->info_ptr, width, height, 8, PNG_COLOR_TYPE_RGB, - PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); - - // Allocate memory to store the image in RGB format - rowbytes = width * 3; - if (rowbytes % 4) - rowbytes = ((rowbytes >>2) + 1) <<2; // Add extra padding so each row starts in a 4 byte boundary - - ctx->img_data = malloc(rowbytes * height); - memset(ctx->img_data, 0, rowbytes * height); - - if (!ctx->img_data) - { - png_destroy_write_struct (&(ctx->png_ptr), (png_infopp)NULL); - if (ctx->source == PNGU_SOURCE_DEVICE) - fclose (ctx->fd); - return PNGU_LIB_ERROR; - } - - ctx->row_pointers = malloc (sizeof (png_bytep) * height); - memset(ctx->row_pointers, 0, sizeof (png_bytep) * height); - - if (!ctx->row_pointers) - { - png_destroy_write_struct (&(ctx->png_ptr), (png_infopp)NULL); - if (ctx->source == PNGU_SOURCE_DEVICE) - fclose (ctx->fd); - return PNGU_LIB_ERROR; - } - - for (y = 0; y < height; ++y) - { - ctx->row_pointers[y] = buffer + (y * rowbytes); - } - - // Tell libpng where is our image data - png_set_rows (ctx->png_ptr, ctx->info_ptr, ctx->row_pointers); - - // Write file header and image data - png_write_png (ctx->png_ptr, ctx->info_ptr, PNG_TRANSFORM_IDENTITY, NULL); - - // Tell libpng we have no more data to write - png_write_end (ctx->png_ptr, (png_infop) NULL); - - // Free resources - free (ctx->img_data); - free (ctx->row_pointers); - png_destroy_write_struct (&(ctx->png_ptr), &(ctx->info_ptr)); - if (ctx->source == PNGU_SOURCE_DEVICE) - fclose (ctx->fd); - - // Success - return ctx->cursor; } -int PNGU_EncodeFromGXTexture (IMGCTX ctx, PNGU_u32 width, PNGU_u32 height, void *buffer, PNGU_u32 stride) +// Custom data provider function used for reading from memory buffers. +static void pngu_read_data_from_buffer (png_structp png_ptr, png_bytep data, png_size_t length) { - int res; - PNGU_u32 x,y, tmpy1, tmpy2, tmpyWid, tmpxy; - - unsigned char * ptr = (unsigned char*)buffer; - unsigned char * tmpbuffer = (unsigned char *)malloc(width*height*3); - memset(tmpbuffer, 0, width*height*3); - png_uint_32 offset; - - for(y=0; y < height; y++) - { - tmpy1 = y * 640*3; - tmpy2 = y%4 << 2; - tmpyWid = (((y >> 2)<<4)*width); - - for(x=0; x < width; x++) - { - offset = tmpyWid + ((x >> 2)<<6) + ((tmpy2+ x%4 ) << 1); - tmpxy = x * 3 + tmpy1; - - tmpbuffer[tmpxy ] = ptr[offset+1]; // R - tmpbuffer[tmpxy+1] = ptr[offset+32]; // G - tmpbuffer[tmpxy+2] = ptr[offset+33]; // B - } - } - - res = PNGU_EncodeFromRGB (ctx, width, height, tmpbuffer, stride); - free(tmpbuffer); - return res; + IMGCTX ctx = (IMGCTX) png_get_io_ptr (png_ptr); + memcpy (data, ctx->buffer + ctx->cursor, length); + ctx->cursor += length; } -int pngu_info (IMGCTX ctx) +// Custom data writer function used for writing to memory buffers. +static void pngu_write_data_to_buffer (png_structp png_ptr, png_bytep data, png_size_t length) +{ + IMGCTX ctx = (IMGCTX) png_get_io_ptr (png_ptr); + memcpy (ctx->buffer + ctx->cursor, data, length); + ctx->cursor += length; +} + +// Custom data flusher function used for writing to memory buffers. +static void pngu_flush_data_to_buffer (png_structp png_ptr) +{ + // Nothing to do here +} + +static int pngu_info (IMGCTX ctx) { png_byte magic[8]; png_uint_32 width; @@ -604,7 +294,7 @@ int pngu_info (IMGCTX ctx) return PNGU_OK; } -int pngu_decode (IMGCTX ctx, PNGU_u32 width, PNGU_u32 height, PNGU_u32 stripAlpha) +static int pngu_decode (IMGCTX ctx, PNGU_u32 width, PNGU_u32 height, PNGU_u32 stripAlpha) { png_uint_32 rowbytes; png_uint_32 i, propImgHeight; @@ -679,48 +369,313 @@ int pngu_decode (IMGCTX ctx, PNGU_u32 width, PNGU_u32 height, PNGU_u32 stripAlph return PNGU_OK; } -void pngu_free_info (IMGCTX ctx) +static inline PNGU_u32 coordsRGBA8(PNGU_u32 x, PNGU_u32 y, PNGU_u32 w) { - if (ctx->infoRead) + return ((((y >> 2) * (w >> 2) + (x >> 2)) << 5) + ((y & 3) << 2) + (x & 3)) << 1; +} + +static PNGU_u8 * PNGU_DecodeTo4x4RGBA8 (IMGCTX ctx, PNGU_u32 width, PNGU_u32 height, PNGU_u8 default_alpha) +{ + PNGU_u8 *dst; + PNGU_u32 x, y, offset; + png_byte *pixel; + + if (pngu_decode (ctx, width, height, 0) != PNGU_OK) + return NULL; + + PNGU_u32 newWidth = width; + if(newWidth%4) newWidth += (4-newWidth%4); + PNGU_u32 newHeight = height; + if(newHeight%4) newHeight += (4-newHeight%4); + + int len = (newWidth * newHeight) << 2; + if(len%32) len += (32-len%32); + dst = memalign (32, len); + + if(!dst) + return NULL; + + for (y = 0; y < newHeight; y++) + { + for (x = 0; x < newWidth; x++) + { + offset = coordsRGBA8(x, y, newWidth); + + if(y >= height || x >= width) + { + dst[offset] = 0; + dst[offset+1] = 255; + dst[offset+32] = 255; + dst[offset+33] = 255; + } + else + { + if (ctx->prop.imgColorType == PNGU_COLOR_TYPE_GRAY_ALPHA || + ctx->prop.imgColorType == PNGU_COLOR_TYPE_RGB_ALPHA) + { + pixel = &(ctx->row_pointers[y][x*4]); + dst[offset] = pixel[3]; // Alpha + dst[offset+1] = pixel[0]; // Red + dst[offset+32] = pixel[1]; // Green + dst[offset+33] = pixel[2]; // Blue + } + else + { + pixel = &(ctx->row_pointers[y][x*3]); + dst[offset] = default_alpha; // Alpha + dst[offset+1] = pixel[0]; // Red + dst[offset+32] = pixel[1]; // Green + dst[offset+33] = pixel[2]; // Blue + } + } + } + } + + // Free resources + free (ctx->img_data); + free (ctx->row_pointers); + + DCFlushRange(dst, len); + return dst; +} + +IMGCTX PNGU_SelectImageFromBuffer (const void *buffer) +{ + IMGCTX ctx = NULL; + + if (!buffer) + return NULL; + + ctx = malloc (sizeof (struct _IMGCTX)); + if (!ctx) + return NULL; + + ctx->buffer = (void *) buffer; + ctx->source = PNGU_SOURCE_BUFFER; + ctx->cursor = 0; + ctx->filename = NULL; + ctx->propRead = 0; + ctx->infoRead = 0; + + return ctx; +} + +IMGCTX PNGU_SelectImageFromDevice (const char *filename) +{ + IMGCTX ctx = NULL; + + if (!filename) + return NULL; + + ctx = malloc (sizeof (struct _IMGCTX)); + if (!ctx) + return NULL; + + ctx->buffer = NULL; + ctx->source = PNGU_SOURCE_DEVICE; + ctx->cursor = 0; + + ctx->filename = malloc (strlen (filename) + 1); + if (!ctx->filename) + { + free (ctx); + return NULL; + } + strcpy(ctx->filename, filename); + + ctx->propRead = 0; + ctx->infoRead = 0; + + return ctx; +} + +void PNGU_ReleaseImageContext (IMGCTX ctx) +{ + if (!ctx) + return; + + if (ctx->filename) + free (ctx->filename); + + if ((ctx->propRead) && (ctx->prop.trans)) + free (ctx->prop.trans); + + pngu_free_info (ctx); + free (ctx); +} + +int PNGU_GetImageProperties (IMGCTX ctx, PNGUPROP *imgprop) +{ + int res; + + if (!ctx->propRead) + { + res = pngu_info (ctx); + if (res != PNGU_OK) + return res; + } + + *imgprop = ctx->prop; + return PNGU_OK; +} + +PNGU_u8 * DecodePNG(const PNGU_u8 *src, int * width, int * height) +{ + PNGUPROP imgProp; + IMGCTX ctx = PNGU_SelectImageFromBuffer(src); + PNGU_u8 *dst = NULL; + + if(!ctx) + return NULL; + + if(PNGU_GetImageProperties(ctx, &imgProp) == PNGU_OK) + { + dst = PNGU_DecodeTo4x4RGBA8 (ctx, imgProp.imgWidth, imgProp.imgHeight, 255); + + *width = imgProp.imgWidth; + *height = imgProp.imgHeight; + } + + PNGU_ReleaseImageContext (ctx); + return dst; +} + +int PNGU_EncodeFromRGB (IMGCTX ctx, PNGU_u32 width, PNGU_u32 height, void *buffer, PNGU_u32 stride) +{ + png_uint_32 rowbytes; + PNGU_u32 y; + + // Erase from the context any readed info + pngu_free_info (ctx); + ctx->propRead = 0; + + // Check if the user has selected a file to write the image + if (ctx->source == PNGU_SOURCE_BUFFER); + + else if (ctx->source == PNGU_SOURCE_DEVICE) + { + // Open file + if (!(ctx->fd = fopen (ctx->filename, "wb"))) + return PNGU_CANT_OPEN_FILE; + } + + else + return PNGU_NO_FILE_SELECTED; + + // Allocation of libpng structs + ctx->png_ptr = png_create_write_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); + if (!(ctx->png_ptr)) { if (ctx->source == PNGU_SOURCE_DEVICE) fclose (ctx->fd); - - png_destroy_read_struct (&(ctx->png_ptr), &(ctx->info_ptr), (png_infopp)NULL); - - ctx->infoRead = 0; + return PNGU_LIB_ERROR; } + + ctx->info_ptr = png_create_info_struct (ctx->png_ptr); + if (!(ctx->info_ptr)) + { + png_destroy_write_struct (&(ctx->png_ptr), (png_infopp)NULL); + if (ctx->source == PNGU_SOURCE_DEVICE) + fclose (ctx->fd); + return PNGU_LIB_ERROR; + } + + if (ctx->source == PNGU_SOURCE_BUFFER) + { + // Installation of our custom data writer function + ctx->cursor = 0; + png_set_write_fn (ctx->png_ptr, ctx, pngu_write_data_to_buffer, pngu_flush_data_to_buffer); + } + else if (ctx->source == PNGU_SOURCE_DEVICE) + { + // Default data writer uses function fwrite, so it needs to use our FILE* + png_init_io (ctx->png_ptr, ctx->fd); + } + + // Setup output file properties + png_set_IHDR (ctx->png_ptr, ctx->info_ptr, width, height, 8, PNG_COLOR_TYPE_RGB, + PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); + + // Allocate memory to store the image in RGB format + rowbytes = width * 3; + if (rowbytes % 4) + rowbytes = ((rowbytes >>2) + 1) <<2; // Add extra padding so each row starts in a 4 byte boundary + + ctx->img_data = malloc(rowbytes * height); + memset(ctx->img_data, 0, rowbytes * height); + + if (!ctx->img_data) + { + png_destroy_write_struct (&(ctx->png_ptr), (png_infopp)NULL); + if (ctx->source == PNGU_SOURCE_DEVICE) + fclose (ctx->fd); + return PNGU_LIB_ERROR; + } + + ctx->row_pointers = malloc (sizeof (png_bytep) * height); + memset(ctx->row_pointers, 0, sizeof (png_bytep) * height); + + if (!ctx->row_pointers) + { + png_destroy_write_struct (&(ctx->png_ptr), (png_infopp)NULL); + if (ctx->source == PNGU_SOURCE_DEVICE) + fclose (ctx->fd); + return PNGU_LIB_ERROR; + } + + for (y = 0; y < height; ++y) + { + ctx->row_pointers[y] = buffer + (y * rowbytes); + } + + // Tell libpng where is our image data + png_set_rows (ctx->png_ptr, ctx->info_ptr, ctx->row_pointers); + + // Write file header and image data + png_write_png (ctx->png_ptr, ctx->info_ptr, PNG_TRANSFORM_IDENTITY, NULL); + + // Tell libpng we have no more data to write + png_write_end (ctx->png_ptr, (png_infop) NULL); + + // Free resources + free (ctx->img_data); + free (ctx->row_pointers); + png_destroy_write_struct (&(ctx->png_ptr), &(ctx->info_ptr)); + if (ctx->source == PNGU_SOURCE_DEVICE) + fclose (ctx->fd); + + // Success + return ctx->cursor; } -// Custom data provider function used for reading from memory buffers. -void pngu_read_data_from_buffer (png_structp png_ptr, png_bytep data, png_size_t length) +int PNGU_EncodeFromGXTexture (IMGCTX ctx, PNGU_u32 width, PNGU_u32 height, void *buffer, PNGU_u32 stride) { - IMGCTX ctx = (IMGCTX) png_get_io_ptr (png_ptr); - memcpy (data, ctx->buffer + ctx->cursor, length); - ctx->cursor += length; -} + int res; + PNGU_u32 x,y, tmpy1, tmpy2, tmpyWid, tmpxy; -// Custom data writer function used for writing to memory buffers. -void pngu_write_data_to_buffer (png_structp png_ptr, png_bytep data, png_size_t length) -{ - IMGCTX ctx = (IMGCTX) png_get_io_ptr (png_ptr); - memcpy (ctx->buffer + ctx->cursor, data, length); - ctx->cursor += length; -} + unsigned char * ptr = (unsigned char*)buffer; + unsigned char * tmpbuffer = (unsigned char *)malloc(width*height*3); + memset(tmpbuffer, 0, width*height*3); + png_uint_32 offset; + + for(y=0; y < height; y++) + { + tmpy1 = y * 640*3; + tmpy2 = y%4 << 2; + tmpyWid = (((y >> 2)<<4)*width); -// Custom data flusher function used for writing to memory buffers. -void pngu_flush_data_to_buffer (png_structp png_ptr) -{ - // Nothing to do here -} + for(x=0; x < width; x++) + { + offset = tmpyWid + ((x >> 2)<<6) + ((tmpy2+ x%4 ) << 1); + tmpxy = x * 3 + tmpy1; -// Function used in YCbYCr to RGB decoding -int pngu_clamp (int value, int min, int max) -{ - if (value < min) - value = min; - else if (value > max) - value = max; - - return value; + tmpbuffer[tmpxy ] = ptr[offset+1]; // R + tmpbuffer[tmpxy+1] = ptr[offset+32]; // G + tmpbuffer[tmpxy+2] = ptr[offset+33]; // B + } + } + + res = PNGU_EncodeFromRGB (ctx, width, height, tmpbuffer, stride); + free(tmpbuffer); + return res; } diff --git a/source/ngc/pngu.h b/source/ngc/pngu.h index 192506b..4819fbc 100644 --- a/source/ngc/pngu.h +++ b/source/ngc/pngu.h @@ -1,38 +1,15 @@ /******************************************************************************************** - -PNGU Version : 0.2a - -Coder : frontier - -More info : http://frontier-dev.net - -Modified by Tantric, 2009 - +* +* PNGU +* +* Original author: frontier (http://frontier-dev.net) +* Modified by Tantric, 2009-2010 +* ********************************************************************************************/ + #ifndef __PNGU__ #define __PNGU__ -// Return codes -#define PNGU_OK 0 -#define PNGU_ODD_WIDTH 1 -#define PNGU_ODD_STRIDE 2 -#define PNGU_INVALID_WIDTH_OR_HEIGHT 3 -#define PNGU_FILE_IS_NOT_PNG 4 -#define PNGU_UNSUPPORTED_COLOR_TYPE 5 -#define PNGU_NO_FILE_SELECTED 6 -#define PNGU_CANT_OPEN_FILE 7 -#define PNGU_CANT_READ_FILE 8 -#define PNGU_LIB_ERROR 9 - -// Color types -#define PNGU_COLOR_TYPE_GRAY 1 -#define PNGU_COLOR_TYPE_GRAY_ALPHA 2 -#define PNGU_COLOR_TYPE_PALETTE 3 -#define PNGU_COLOR_TYPE_RGB 4 -#define PNGU_COLOR_TYPE_RGB_ALPHA 5 -#define PNGU_COLOR_TYPE_UNKNOWN 6 - - #ifdef __cplusplus extern "C" { #endif @@ -67,7 +44,7 @@ struct _IMGCTX; typedef struct _IMGCTX *IMGCTX; /**************************************************************************** -* Image context handling * +* Image context handling * ****************************************************************************/ // Selects a PNG file, previosly loaded into a buffer, and creates an image context for subsequent procesing. @@ -79,22 +56,18 @@ IMGCTX PNGU_SelectImageFromDevice (const char *filename); // Frees resources associated with an image context. Always call this function when you no longer need the IMGCTX. void PNGU_ReleaseImageContext (IMGCTX ctx); - /**************************************************************************** -* Miscelaneous * +* Miscellaneous * ****************************************************************************/ // Retrieves info from selected PNG file, including image dimensions, color format, background and transparency colors. int PNGU_GetImageProperties (IMGCTX ctx, PNGUPROP *fileproperties); /**************************************************************************** -* Image conversion * +* Image conversion * ****************************************************************************/ -// Expands selected image into a 4x4 tiled RGBA8 buffer. You need to specify context, image dimensions, -// destination address and default alpha value, which is used if the source image doesn't have an alpha channel. -int PNGU_DecodeTo4x4RGBA8 (IMGCTX ctx, PNGU_u32 width, PNGU_u32 height, void *buffer, PNGU_u8 default_alpha); - +PNGU_u8 * DecodePNG(const PNGU_u8 *src, int *width, int *height); int PNGU_EncodeFromRGB (IMGCTX ctx, PNGU_u32 width, PNGU_u32 height, void *buffer, PNGU_u32 stride); int PNGU_EncodeFromGXTexture (IMGCTX ctx, PNGU_u32 width, PNGU_u32 height, void *buffer, PNGU_u32 stride); @@ -103,4 +76,3 @@ int PNGU_EncodeFromGXTexture (IMGCTX ctx, PNGU_u32 width, PNGU_u32 height, void #endif #endif -