Foros - Stratos

Programadores => Programación gráfica => Mensaje iniciado por: Altair en 22 de Julio de 2006, 05:51:20 PM

Título: SDL: hacer un set_pixel a medida
Publicado por: Altair en 22 de Julio de 2006, 05:51:20 PM
Hola gente,

estoy liadete con un error bastante curioso, intento hacer que, dada una surface, unas coordenadas X e Y de esa surface y un color ya creado con SDL_Color, un pixel se ponga de un determinado color.

En concreto la funcion es esta:

void SetPixel ( SDL_Surface* pSurface , int x , int y , SDL_Color color )
{
 //convert color
 Uint32 col = SDL_MapRGB ( pSurface->format , color.r , color.g , color.b ) ;

 //determine position
 char* pPosition = ( char* ) pSurface->pixels ;

 //offset by y
 pPosition += ( pSurface->pitch * y ) ;

 //offset by x
 pPosition += ( pSurface->format->BytesPerPixel * x ) ;

 //copy pixel data
 memcpy ( pPosition , &col , pSurface->format->BytesPerPixel ) ;
}

Sacada de http://www.gamedev.net/reference/programming/features/sdl2/page5.asp

Funcionar funciona, porque me sale la pantalla llena de pixeles coloreados. Pero siempre termina dandome Segmentation Fault (SDL Parachute Deployed).

Tal y como indican en la web, uso SDL_LockSurface y SDL_UnlockSurface  antes de comenzar nada.

¿Alguna idea de que puede ser?
Título: SDL: hacer un set_pixel a medida
Publicado por: ALRAZ en 23 de Julio de 2006, 12:15:49 AM
En la ayuda de SDL viene una función put pixel mucho más guapa que esa:


void putpixel(SDL_Surface *surface, int x, int y, Uint32 pixel)
{
   int bpp = surface->format->BytesPerPixel;
   /* Here p is the address to the pixel we want to set */
   Uint8 *p = (Uint8 *)surface->pixels + y * surface->pitch + x * bpp;

   switch(bpp) {
   case 1:
       *p = pixel;
       break;

   case 2:
       *(Uint16 *)p = pixel;
       break;

   case 3:
       if(SDL_BYTEORDER == SDL_BIG_ENDIAN) {
           p[0] = (pixel >> 16) & 0xff;
           p[1] = (pixel >> 8) & 0xff;
           p[2] = pixel & 0xff;
       } else {
           p[0] = pixel & 0xff;
           p[1] = (pixel >> 8) & 0xff;
           p[2] = (pixel >> 16) & 0xff;
       }
       break;

   case 4:
       *(Uint32 *)p = pixel;
       break;
   }
}


Espero te sirva.

Un saludo
Título: SDL: hacer un set_pixel a medida
Publicado por: Altair en 23 de Julio de 2006, 07:47:58 AM
Si, conozco esa funcion y es muy practica, pero me plantea un pequeño problema.

Yo lo que quiero es controlar los valores RGB y RGBA de un pixel de una surface dada, para lo cual uso SDL_Color.

En esa funcion tenemos "Uint32 pixel", lo cual me lleva a que cada componente de color RGBA esta incluida en un solo numero, logicamente. Lo que no consigo acordarme de como era exactamente para cambiar los valores RGB de SDL_Color para meterlos en el Uint32 de pixel.

Anoche en el canal estuve hablando del tema, y sacamos lo siguiente:

<{_SaLeM_}> supon la combinacion 1, 1, 1, 0
<{_SaLeM_}> eso seria
<{_SaLeM_}> 2^24 + 2^16 + 2^8
<{_SaLeM_}> 16843008
<{_SaLeM_}> que pasado a bin es
<{_SaLeM_}> 00000001000000010000000100000000
<{_SaLeM_}> 1, 1, 1, 0

<{_SaLeM_}> pues 1 * 2^24 + 1 * 2^16 + 1 * 2^8 + 0

Creo que la solucion va por ahi, pero intento pintar la pantalla de rojo (255,0,0) y me sale casi negro, algo me falla en la formula.
Título: SDL: hacer un set_pixel a medida
Publicado por: ALRAZ en 23 de Julio de 2006, 10:30:20 AM
Revisando con un poco más de atención tu código, me doy cuenta de que en realidad estás usando SDL_MapRGB, pero estás mapeando hacia la surface equivocada. Intenta cambiar "pSurface" por la dirección de la Surface principal (Ver SDL_GetVideoSurface)... Al menos eso es lo que recuerdo que se hacía.

De cualquier manera, lo que podrías hacer sería simplemente llamar SDL_MapRGB al inicio de la función para convertir el SDL_Color a un Uint32 usando la misma función de SDL y problema resuelto  :lol:


/*  SE  CAMBIA EL ÚLTIMO PARÁMETRO A SDL_Color  */
void putpixel(SDL_Surface *surface, int x, int y, SDL_Color color)
{

/*  SE  AGREGA ESTA LÍNEA!     */
Uint32 pixel = SDL_MapRGB (Screen->format, color.R, color.G, color.B);

/* Y EL RESTO DE LA FUNCIÓN LO DEJAS IGUAL */

  ...



En el caso anterior, "Screen" es la Surface de pantalla mencionada en el primer párrafo.


Y como nota adicional decir que es una buena costumbre en C++ que en lugar de pasar estructuras como parámetros, se pasen punteros a esas estructuras (Cosa que no hice aquí).

Espero sirva de algo.
Saludos
Título: SDL: hacer un set_pixel a medida
Publicado por: Altair en 23 de Julio de 2006, 12:11:19 PM
Vale, he cambiado todo para que la surface de la pantalla se llame "screen", y he comprobado que funciona porque la tengo delante.

Con la funcion putpixel puedo colocar pixeles en formato RGBA, pero SDL_Color tiene formato RGB.

Dado que los miembros de SDL_Color son Uint8, solo necesito una variable Uint8 alpha para completar de RGB a RGBA.

Tanto los miembros de SDL_Color como alpha admiten un valor entre 0 y 255, lo que lleva (si me estoy enterando bien con lo que leo por Google) a un dato hexadecimal (base 16)

Supongamos algo como esto:

SDL_Color *color1;
Uint8 *alpha;

color1->r=255;
color1->g=0;
color1->b=0;

alpha=150; (150, por poner un numero)

Si me entero bien, eso deberia dibujar un punto rojo con un cierto grado de transparencia, lo que no veo claro es como esos cuatro Uint8 los junto para formar un Uint32.
Título: SDL: hacer un set_pixel a medida
Publicado por: Sante en 23 de Julio de 2006, 01:46:54 PM
Cita de: AltairVale, he cambiado todo para que la surface de la pantalla se llame "screen", y he comprobado que funciona porque la tengo delante.

Con la funcion putpixel puedo colocar pixeles en formato RGBA, pero SDL_Color tiene formato RGB.

Dado que los miembros de SDL_Color son Uint8, solo necesito una variable Uint8 alpha para completar de RGB a RGBA.

Tanto los miembros de SDL_Color como alpha admiten un valor entre 0 y 255, lo que lleva (si me estoy enterando bien con lo que leo por Google) a un dato hexadecimal (base 16)

Supongamos algo como esto:

SDL_Color *color1;
Uint8 *alpha;

color1->r=255;
color1->g=0;
color1->b=0;

alpha=150; (150, por poner un numero)

Si me entero bien, eso deberia dibujar un punto rojo con un cierto grado de transparencia, lo que no veo claro es como esos cuatro Uint8 los junto para formar un Uint32.

Para eso esta la funcion SDL_MapRGBA (http://www.libsdl.org/cgi/docwiki.cgi/SDL_5fMapRGBA)

Te pongo un ejemplo de como mapear el color en un Uint32 de acuerdo al formato de una superficie:


SDL_Color *color1;
Uint8 *alpha;

color1->r=255;
color1->g=0;
color1->b=0;

alpha=150;

Uint32 final = SDL_MapRGBA (surface->format, color1->r, color1->g, color1->b, alpha);



Creo que era eso lo que preguntabas, no?
Título: SDL: hacer un set_pixel a medida
Publicado por: Altair en 23 de Julio de 2006, 04:57:39 PM
Si, si, eso es lo que inicialmente pense. De hecho primero me puse con SDL_MapRGB y deje para luego SDL_MapRGBA.

Lo raro del asunto es que a veces me suelta:

Fatal signal: Segmentation Fault (SDL Parachute Deployed)

despues de estar funcionando el programa unos segundos. Por poner un ejemplo: acabo de ejecutarlo tal cual, cinco veces, y me ha dado segmentation fault en tres.

En cambio, con la funcion putpixel de SDL nunca ha ocurrido ese error.
Título: SDL: hacer un set_pixel a medida
Publicado por: Sante en 23 de Julio de 2006, 05:44:11 PM
A ver, varias cosas:

- Un SDL Parachute te puede saltar por muchas razones. Puede que el problema esté en otra parte del código, especialmente si te salta "al azar" como parece.

- He probado a compilar el código ese de la web de Gamedev, y a ejecutarlo, y a mi no me da problemas. ¿Estás usando exactamente el mismo código?

- La función de setpixel de ese código no es muy buena (por ejemplo, no tiene en cuenta el endianess), usa el putpixel que te han puesto más arriba. La única diferencia es que en lugar de pasarle un SDL_Color y hacer el MapRGB dentro de la función, lo haces fuera, y le pasas a putpixel el color definitivo.


Como ya te digo, sin saber más de tu código, es muy dificil saber porqué te salta el parachute.
Título: SDL: hacer un set_pixel a medida
Publicado por: ALRAZ en 23 de Julio de 2006, 09:20:07 PM
Nadamás mencionar que la estructura SDL_Color tiene un miembro llamado "unused" de 8 bits que va justo después del miembro B:


typedef struct
{
  Uint8 R;
  Uint8 G;
  Uint8 B;
  Uint8 unused;
} SDL_Color


O algo así.
Hacer operaciones de memoria sin tomar en cuenta ese campo "unused" puede llevar a colgaderas del SDL.... Y del programa...