lunes, 10 de enero de 2022

Efectos de fusión de imágenes

En este ejemplo veremos dos formas de fusionar las imágenes, si estuviéramos usando Adobe Photoshop sería el modo de fusión Multiplicar, y el modo de fusión Trama.

En el modo multiplicar el color resultante siempre es un color más oscuro. Multiplicar cualquier color por negro produce negro, multiplicar cualquier color por blanco no cambia el color, y si multiplicas por otro color produce color mas oscuro.  De una forma rápida y sencilla esto quiere decir que cuando se fusionan dos imágenes mediante multiplicar lo que está en blanco es ignorado.

En el modo trama el color resultante siempre es un color más claro. Tramar con negro no cambia el color. Tramar con blanco genera blanco. En este caso quiere decir que se ignora lo que esta en negro.

En las imágenes de arriba se muestra el resultado de fusionar con multiplicar la imagen1 con la imagen2 y el resultado de fusionar con trama la imagen1 con la imagen2.


Para ponerlo mas interesante en vez de explicar solo los comandos necesarios, se hará el siguiente ejemplo tal y como se muestra en el siguiente video.



El Código

int main()
{
	al_init();
	al_install_keyboard();
	if (!al_init_image_addon())
	{
		return -1;
	}
    const int Pantallancho = 1152;
    const int Pantallalto = 572;	

	ALLEGRO_DISPLAY* pantalla = al_create_display(Pantallancho, Pantallalto);

	ALLEGRO_BITMAP* buffer = al_create_bitmap(Pantallancho, Pantallalto);
    al_set_window_title(pantalla, "Planeta Tierra: Dia y Noche");

	ALLEGRO_BITMAP* fondo = al_load_bitmap("Pespacio.png");
	ALLEGRO_BITMAP* tierraDia = al_load_bitmap("Pdia.png");
	ALLEGRO_BITMAP* tierraNoche = al_load_bitmap("Pnoche.png");
	ALLEGRO_BITMAP* mascaraDia = al_load_bitmap("PMDia.png");
	ALLEGRO_BITMAP* mascaraNoche = al_load_bitmap("PMNoche.png");
	ALLEGRO_BITMAP* nubes = al_load_bitmap("Pnube1.png");
	ALLEGRO_BITMAP* nubes2 = al_load_bitmap("Pnube2.png");
	ALLEGRO_BITMAP* volumen = al_load_bitmap("Pvolumen.png");

	ALLEGRO_BITMAP* temp = al_create_bitmap(Pantallancho, Pantallalto);

	ALLEGRO_KEYBOARD_STATE teclado;

	// defino lista de eventos
	ALLEGRO_EVENT_QUEUE* Mis_eventos;
	ALLEGRO_EVENT evento;

	bool salir;
	int velocidad = 2;

	// creo lista de eventos
	Mis_eventos = al_create_event_queue();

	salir = false;

	// asigno eventos a la lista de eventos
	al_register_event_source(Mis_eventos, al_get_keyboard_event_source());
	al_register_event_source(Mis_eventos, al_get_display_event_source(pantalla));

	float nubesX = 0;
	float nubes2X = 0;
	float tierraX = 0;

	while (!salir)
	{
		al_set_target_bitmap(buffer);
		al_set_blender(ALLEGRO_ADD, ALLEGRO_ALPHA, ALLEGRO_INVERSE_ALPHA);
		al_draw_bitmap(tierraDia, 0+tierraX, 0, 0);
		if (tierraX < -Pantallancho / 4)
		{
			al_draw_bitmap(tierraDia, 0 + tierraX + Pantallancho, 0, 0);
		}

		al_set_blender(ALLEGRO_ADD, ALLEGRO_ZERO, ALLEGRO_SRC_COLOR);
		al_draw_tinted_bitmap(volumen, al_map_rgba(200, 200, 200, 200), 0, 0, 0);

		al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_ONE);
		al_draw_tinted_bitmap(nubes2, al_map_rgba(128, 128, 128, 128), 0 + nubes2X, 0, 0);
		if (nubes2X < -Pantallancho / 4)
		{
			al_draw_tinted_bitmap(nubes2, al_map_rgba(128, 128, 128, 128), 0 + nubes2X + Pantallancho, 0, 0);
		}

		al_draw_bitmap(nubes, 0 + nubesX, 0, 0);
		if (nubesX < -Pantallancho / 4)
		{
			al_draw_bitmap(nubes, 0 + nubesX + Pantallancho, 0, 0);
		}

		al_set_target_bitmap(temp);
		al_set_blender(ALLEGRO_ADD, ALLEGRO_ALPHA, ALLEGRO_INVERSE_ALPHA);
		al_draw_bitmap(tierraNoche, 0 + tierraX, 0, 0);
		if (tierraX > Pantallancho / 4)
		{
			al_draw_bitmap(tierraNoche, 0 + tierraX - Pantallancho, 0, 0);
		}
		if (tierraX < -Pantallancho / 4)
		{
			al_draw_bitmap(tierraNoche, 0 + tierraX + Pantallancho, 0, 0);
		}

		al_set_blender(ALLEGRO_ADD, ALLEGRO_DEST_COLOR, ALLEGRO_SRC_COLOR);
		al_draw_bitmap(mascaraNoche, 0, 0, 0);
		al_convert_mask_to_alpha(temp, al_map_rgb(0, 0, 0));

		al_set_target_bitmap(buffer);

	    al_set_blender(ALLEGRO_ADD, ALLEGRO_ZERO, ALLEGRO_SRC_COLOR);
	
		al_draw_tinted_bitmap(mascaraDia, al_map_rgba(248, 248, 248, 248), 0, 0, 0);

		al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_ONE);
		al_draw_tinted_bitmap(volumen, al_map_rgba(64, 64, 64, 64), 0, 0, 0);
		al_draw_bitmap(temp, 0, 0, 0);

		al_draw_tinted_bitmap(nubes2, al_map_rgba(64, 64, 64, 64), 0 + nubes2X, 0, 0);
		if (nubes2X < -Pantallancho / 4)
		{
			al_draw_tinted_bitmap(nubes2, al_map_rgba(64, 64, 64, 64), 0 + nubes2X + Pantallancho, 0, 0);
		}

		al_set_blender(ALLEGRO_ADD, ALLEGRO_ALPHA, ALLEGRO_INVERSE_ALPHA);
		al_draw_bitmap(fondo, 0, 0, 0);

		al_set_target_backbuffer(pantalla);
		al_draw_bitmap(buffer, 0, 0, 0);

		al_flip_display();
		
		al_wait_for_event_timed(Mis_eventos, &evento, 1.0 / FPS);

		// se ha pulsado una tecla
		if (evento.type == ALLEGRO_EVENT_KEY_DOWN)
		{
			if (evento.keyboard.keycode == ALLEGRO_KEY_ESCAPE) {
				salir = true;
			}
		}

		if (evento.type == ALLEGRO_EVENT_DISPLAY_CLOSE)
		{
			salir = true;
		}		

		nubes2X = nubes2X - 0.7f*velocidad;
		if (nubes2X < -Pantallancho) nubes2X = nubes2X + Pantallancho;
		nubesX = nubesX - 0.9f* velocidad;
		if (nubesX < -Pantallancho) nubesX = nubesX + Pantallancho;
		tierraX = tierraX - 0.3f* velocidad;
		if (tierraX < -Pantallancho) tierraX = tierraX + Pantallancho;
	}

	al_destroy_bitmap(buffer);
	al_destroy_bitmap(fondo);
	al_destroy_bitmap(tierraDia);
	al_destroy_bitmap(tierraNoche);
	al_destroy_bitmap(mascaraDia);
	al_destroy_bitmap(mascaraNoche);
	al_destroy_bitmap(nubes);
	al_destroy_display(pantalla);
	return 0;
}
 

Se inicializan las librerías Allegro, teclado e imágenes.  Se define el tamaño de la ventana a mostrar que será de 1152x576, se ha escogido esta resolución ya que todas las imágenes utilizadas tienen este mismo tamaño. Se cargan las 8 imágenes que necesitamos para nuestro ejemplo.

Se definen y se inicializan las variables que se utilizan, en el ejemplo. En el bucle se pinta las imágenes según un orden para obtener el efecto deseado. Con el comando al_set_target_bitmap(buffer); se indica que todos los comandos de pintar tendrán efecto sobre la imagen buffer.

Primero se pinta el fondo, que en este caso es la imagen llamada tierraDia, como esta imagen se va a desplazar según la variable tierraX, llegará un momento en que la imagen salga del campo de visión, es por ello que a continuación hay una condición para que pinte una segunda imagen para darle continuidad a la escena.

Después se pinta el volumen y se aplica un método de fusión, en este caso el multiplicar, que se consigue escribiendo el siguiente código:

al_set_blender(ALLEGRO_ADD, ALLEGRO_ZERO, ALLEGRO_SRC_COLOR);

al_draw_tinted_bitmap(volumen, al_map_rgba(200, 200, 200, 200), 0, 0, 0);

En este caso se utiliza al_draw_tinted_bitmap para dibujar la imagen un poco transparente.

Luego se pintan las nubes, en este caso hay dos capas de nubes que utilizan trama para fusionarse, de este modo solo se pinta lo que está en blanco, es decir, las nubes. Cada capa de nubes tiene un desplazamiento diferente que viene marcado por las variables nubesX y nubes2X.  Al igual que el fondo para que tenga continuidad se pinta una segunda imagen.

Para utilizar el modo de fusión trama se debe escribir lo siguiente:

al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_ONE);

De este modo se ignora lo negro y se pinta lo blanco. Todo el resultado se está guardando en la variable buffer.

Luego en una imagen temporal se crea otra imagen fusionando mediante multiplicar la imagen de noche y la mascara noche. Eso es indicado mediante el comando al_set_target_bitmap(temp)  en el cual indicamos que ahora pintaremos sobre la imagen temp.

A lo que hay almacenado en buffer se multiplica con la mascara día.
Luego se fusionan van fusionando mediante trama sobre la imagen de buffer, la imagen de volumen y la imagen temp.
Y al resultado que se encuentra en buffer se le aplica otra fusión trama para poner nubes.
Finalmente sobre la imagen buffer se pone otra imagen llamada fondo.
De esta forma todo queda almacenado en buffer, que luego es mostrado por pantalla.
Después de todo esto se controlan los eventos para comprobar si se pulsa la tecla ESC o se pulsa en botón X de la ventana para indicar que se debe salir.

Y antes de finalizar el bucle, tenemos las variables utilizadas para mover las imágenes y algunas condiciones para que no se salgan del rango de visión.

Al finalizar antes de acabar, se libera la memoria utilizada por todas las imágenes, con el comando al_destroy_bitmap.

Si deseas descargar el código completo y las imágenes haz clic aquí.

No hay comentarios:

Publicar un comentario

Antes de publicar un comentario

Todos los comentarios que se realicen en el blog son moderados.

Debido a esto es muy probable que tu comentario no aparezca de inmediato ya que previamente debe ser revisado para evitar un mal uso (SPAM).

Podrán realizar comentario cualquiera que tenga una cuenta de Google.

Related Posts Plugin for WordPress, Blogger...