viernes, 25 de abril de 2008

LIBPNG 1.2.26 + PNGU v0.1c para Wii

Desde que hace unos meses se descubrió un bug que permite ejecutar código casero en Wii mucha gente se ha metido de cabeza a estudiar los entresijos de la consola de Nintendo.

Hay varias librerías que pueden usarse para hacer aplicaciones caseras en Wii, pero la más utilizada sin duda es libogc, que está incluida en devkitpro. Aunque es una librería muy completa suelen necesitarse librerías complementarias que cubran aquellos aspectos para los que libogc no ha sido diseñada. Uno de estos aspectos es la carga de imágenes, sonido, etc...

Para rellenar una parte de ese hueco he compilado la librería libpng para Wii. Creo que puede ser una alternativa a libjpeg, que también ha sido portada recientemente. El formato PNG presume de muchas prestaciones: Almacena un color de fondo, un color de transparencia, permite tener un canal alpha con varias modalidades de profundidad, comprime sin deteriorar la calidad, es un formato abierto, etc... Además libpng es la librería más completa para manejarlo.

Para rematar la faena he creado un conjunto de funciones (PNGU_*) que permiten cargar una imagen en un búfer de memoria muy fácilmente. De esta forma se puede empezar a experimentar con la librería de inmediato. La versión actual de PNGU es la 0.1c y tiene las siguientes características:

Permite cargar ficheros desde un búfer de memoria o desde una tarjeta SD.

Puede descomprimir imágenes PNG y convertirlas a formato YCbYCr, RGBA8, 4x4 RGB565, 4x4 RGB5A3 y 4x4 RGBA8.

De momento sólo está probada con archivos PNG en formato RGB8, aunque es muy posible que funcione con otros tipos de PNG, como RGBA8.

Os dejo la librería ya compilada, las funciones PNGU_*, varios proyectos de ejemplo, un archivo .bat para el que quiera compilar la librería él mismo y algunas indicaciones adicionales aquí.

Y por supuesto, no dudeis en dejar un comentario si encontrais algún bug o teneis dudas sobre como usarla.

21 comentarios:

Anónimo dijo...

Hola,

Primero felicidades por la librería. Ahora estaba intentando cargar archivos desde el SD frontal y montarlos los monta bien, pero al hacer un f_stat la aplicación se cuelga y crashea. He mirado tu código y sigo sin saber qué falla (también uso tinyFAT-FS). A ver si lo miro con más calma o le puedes echar un vistazo porque me tiene que estar fallando algo.

Por cierto, ¿tienes pensamiento de escribir la página de PNGU en wiibrew? (es por hacerlo yo, porque me parece interesante). Quizás podrías incluir tu librería en GRRLIB y unificar... no sé
¡adelante!

Frontier dijo...

Hola _conejo,

En principio no deberías necesitar ninguna llamada a f_stat. En su lugar tienes que llamar a PNGU_GetImageProperties.

Si te hace falta f_stat porque en tu programa cargas otros tipos de archivo además de .png, tienes que desactivar el acceso de PNGU a la SD para no crear conflictos por montar dos veces el sistema de archivos. Eso se hace comentando la línea "#define PNGU_USE_WII_SD" en el archivo "pngu.h".

Si comentas esa línea debes cargar por tu cuenta los archivos .png enteros en un búfer de memoria y usar PNGU_SelectFileFromBuffer en lugar de PNGU_SelectFileFromWiiSD. Si te sigue fallando escríbeme a frontier@frontier-dev.net y trataré de averiguar que está pasando...

La página de wiibrew no tenía intención de escribirla, más que nada por falta de tiempo. Si te encargas tu te estaría muy agradecido :)

Saludos!

Anónimo dijo...

Bueno, la página ya está, no es gran cosa pero tengo que practicar el inglés de alguna forma xD

Y si, lo que quiero cargar no son png's, pero algo estoy implementando mal en la tinyFat FS porque se me cuelga la aplicación y no sé el motivo

Frontier dijo...

Muchas gracias por la página. La he visto y te ha quedado muy bien :D

Si quieres pásame el código fuente por email y le doy un vistazo a ver si puedo averiguar que es lo que falla.

Anónimo dijo...

Eres piratilla pero te queremos igual xD.

Un abrazo tío ;).

wascator dijo...

Hola, no encontré tu email, te dejo el mio nodani@gmail.com dame 1 toque y te paso el source (aunque es un tocho). Creo que es una incompatibilidad con GRRLIB, así que no tengo ni idea de cómo solucionarla... =S

Anónimo dijo...

http://www.tehskeen.com/forums/showthread.php?t=4702

what's the difference ?
thank you

Frontier dijo...

Este es otro caso de falta de coordinación en la scene. Yo no sabía de la existencia del wrapper de softdev, y de haberlo sabido habría hecho el mío partiendo del suyo.

De todas formas creo que el mío es más completo ya que soporta lectura desde la SD frontal, puede pasar la imágen al esotérico formato que usan las texturas de Wii/GC y además sigo añadiendole nuevas funcionalidades.

Lo mejor es que mires la interfaz pública de ambos wrappers y te quedes con el que más convenga a tu propósito.


This is another case of descoordination in the scene. I didn't know about softdev's wrapper and if I would known I've done mine based in his code.

Anyway I think mine is more complete because it supports reading files from SD card, it can convert images to the esoteric texture format of Wii/GC and I'm still adding new funtionalities to it.

Yo better take a look of the public interfaces of both wrappers and pick the one that best fits your needs.

Anónimo dijo...

I see, yes, it seems to only support PNG (RGB888 format) to XFB (YCbYCr format) conversion

I think I will give a try to your implementation instead

do you have advices on how to render transparency effects in EFB, for example using superposed .png files previously computed in Macromedia Fireworks ?

Frontier dijo...

I'm sorry to say PNGU currently ignores alpha values of input png files and give all pixels an user defined alpha (the same for every pixel in the image) :(

However, reading input alpha is first thing in my TODO list and be available very soon in PNGU 0.1d release.

Anónimo dijo...

Hi, since i want to use your lib for making sprite, i want to store the information of each image in ycbycr format after the image is decoded.

This is the example (hardcoded values of x & y) that works drawing directly to the framebuffer:

if (PNGU_SelectFileFromBuffer logo_data) != PNGU_OK)
printf ("PNGU_SelectFileFromBuffer failed!\n");

PNGU_DECODE_TO_COORDS_YCbYCr (0, 0, 136, 80, 640, 480, xfb);

What I want to do is store the information in an array, for displaying it later using 2 for loops (i did it working with bitmaps). The code I tried to use is:

static u32 bufLogo[136*80];
PNGU_DecodeToYCbYCr (136, 80, bufLogo, 0);

This doesn't load the image in my array, and i don't know the why... some hint?

Thanks!

Frontier dijo...

The way you call PNGU_DecodeToYCbYCr is OK, but the way you obtain memory for the buffer is not.

Firs of all, you are requesting an u32 (4 bytes) for each pixel, and in YCbYCr a pixel only takes 2 bytes (u16). So, yo should request 136*80*2 bytes, or in your case "static u16 bufLogo[136*80];"

Also, I'd change my buffer request to "u8 *bufLogo = memalign (32, 136*80*2);" This way is preferable because you can select buffer size at runtime. The reason I call memalign instead of malloc is to make bufLogo 32 bytes aligned. This is irrelevant in your particular case, but if the GPU is going to access the buffer, for example if you use the image as a texture, it's absolutely necessary. Of course you must call "free (bufLogo);" when you are done with the buffer.

Finally, after performing any PNGU_DecodeTo* call, if the buffer is going to be accessed by the GPU, you have to call "DCFlushRange (bufLogo, 136*80*2);". Again this is not your case, but could be in the future, so you are warned...

I hope this helps you.

Anónimo dijo...

Ok I think I'm a bit confused than before :P
What i know is that the xfb manages a pair of ycb pixels and its size is u32.
I made few programs drawing to the fb, and I always declared "static u32 *xfb = NULL;", but you use void* and it confuses me much as i'm not very familiar with these things.

In my old stupid library I got bitmaps display correctly, storing the ycb values to a u32 array. I can send you how i did it.

Anyway i modified example fb display example of pngu in this way: http://rafb.net/p/6mlqJ499.html

There are small differences with the example, the image is displayed but in a "wrong" way. (It works on emulator though).

Thanks for help in advance.

Frontier dijo...

You are right, the xfb always manages two pixels at a time. But I'm also right, if the size of two pixels is an u32, the size of one pixel is an u16, so you only need 136*80*2 bytes to store your image.

However, your drawing routine works with pixel pairs instead of single pixels, so you have to declare your buffer as u32 and specify the number of pixels pairs, not the number of single pixels. In your case this should look like "static u32 bufLogo[136*80/2];".

The last thing you have to modify is the line "u32 z = ((136>>1) * 80);". I don´t understand what you are triying to do here, but if you want things to work then you have to replace it by "u32 z = 0;".

I've tested the program with these modifications an works fine. It's very important that you understand YCbYCr format if you are going to work with it. Maybe I'll post an article about Wii/GC pixel formats soon... Maybe, if I have time...

Anónimo dijo...

Thanks! It worked!
Making a simple wrapper for loading png instead of bmp (just for the backgrounds for now) reduced the size of my game from 7.8MB to 1.7MB!!!
Any chance to have support for transparency? I don't need the alpha blending, just full transparency instead of using magenta, but it's ok even this way!
Thank you for pngu!

Anónimo dijo...

Also, since you read my post and my drawing function, how can I deal with a pair of pixels where one is of a color and the other is "transparent" (magenta)?

For displaying I use this in my for loop (simplified):

z=0;

for(i...
for(j...
if (sprite.ycbImg[z] != COLOR_MAGENTA)
xfb[j + fboffset] = sprite.ycbImg[z];
z++;
}
fboffset += 320; //move to the next line
}

This works well when the pair is COLOR+COLOR (it is drawn), and MAGENTA+MAGENTA (whose code is stored in the COLOR_MAGENTA macro).
The problem is when a pair is COLOR+MAGENTA or MAGENTA + COLOR, where the result is displayed with some magenta variation.
It would really easy if i could separate the 2 pixels...
Any hint?
Thanks as usual, your lib will be quoted in my game.

Frontier dijo...

Mmmmm... There are three possible solutions:

1 - The easiest: Just tell your artist about the problem so he/she can make sprites in wich every pair of pixels is always COLOR-COLOR or MAGENTA-MAGENTA.

2 - The not so easy: Before writing any pair of pixels to xfb you have to test if it is COLOR-MAGENTA or MAGENTA-COLOR. In this case you have to read the pixel's pair stored in xfb and make a new one combining your pair and xfb's pair. This is an slow solution but it should work.

3 - The hard way: Just forget about writting your sprite directly to xfb. Instead, you can load your sprite to a texture and apply it to a square. Then you can draw the square at the appropiate screen position using GX commands. This solution is way faster than any other, but you have to learn GX, the 3D drawing interface of Wii/GC.

Unless you have a good reason, probably you should try the first solution...

Anónimo dijo...

Ehehe I thought at first solution, since for the second i don't know the way to understand how a pair is COLOR-MAGENTA or viceversa.
Thanks anyway :)

Unknown dijo...

Buenas frontier soy oyzzo :) ahora que ha salido devkitppc r15 con la libogc nueva y libfat me pregunto si te has planteado portar PNGU a libfat. Para el motor Revolution Engine que estamos desarrollando usamos libfat, así que nos interesaria bastante ;)

Frontier dijo...

Buenas oyzzo, ¡bienvenido a mi humilde cibermorada!

No sólo me lo he planteado sino que es justamente lo que estaba haciendo cuando he visto tu mensaje :D

Ya de paso quiero meterle algunas mejoras extras: Guardado de capturas de pantalla en formato png, lectura del canal alpha y posibilidad de usar la librería en entornos multihilo. Tardaré un poco, pero creo que merecerá la pena.

Un saludo!

Anónimo dijo...

I want to inform you I released my game that use pngu for loading images.
http://scognito.wordpress.com/2008/06/08/scogger-02-for-wii-and-gamecube-is-out/

Thanks for the lib!

Noticias anteriores