Stratos: Punto de Encuentro de Desarrolladores

¡Bienvenido a Stratos!

Acceder

Foros





SDL: hacer un set_pixel a medida

Iniciado por Altair, 22 de Julio de 2006, 05:51:20 PM

« anterior - próximo »

Altair

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?

ALRAZ

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

Altair

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.

ALRAZ

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

Altair

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.

Sante

Cita de: "Altair"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.

Para eso esta la funcion SDL_MapRGBA

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?

Altair

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.

Sante

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.

ALRAZ

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...






Stratos es un servicio gratuito, cuyos costes se cubren en parte con la publicidad.
Por favor, desactiva el bloqueador de anuncios en esta web para ayudar a que siga adelante.
Muchísimas gracias.