domingo, 18 de noviembre de 2012

Creando un Paint en C++ Parte 5

Aquí llega una nueva entrega, del editor de imagenes. Una cosa básica que le faltaba a nuestro editor es lo que se denominan primitivas de dibujo. Concretamente son cuatro las que se añaden:
  • Crear una linea recta entre dos puntos.
  • La creación de un circulo.
  • La creación de un rectángulo.
  • La creación de un elipse.


Y para ello se debe de cambiar la imagen de panel de control, es decir, la imagen de los botones con la nueva.


Como se puede observar en la imagen se han añadido seis nuevos botones de los cuales utilizaremos solo cinco de ellos.

Empezamos con el código, desde el principio. Se incluyen las librerías que vamos a utilizar y declaramos las variables globales que se va a utilizar en el programa.
#include <allegro.h> 
#include <math.h>  // para sqrt()

// resolucion del editor - tamaño ventana 
#define ANCHO 640  
#define ALTO  480  
  
int soltado = 1;  
int accion  = 4;  
int colora  = 0x000000;
int colorR  = 255;
int colorG  = 255;
int colorB  = 255;
int inix, iniy;
int estado  = 0;
bool relleno = false;
int anterior = 0;
BITMAP *buffer;  
BITMAP *dibujo;  
BITMAP *botones; 
BITMAP *marcador;
BITMAP *rellenado;
PALETTE pal;

En la función Sobre_boton(), se debe cambiar un numero que representa el ancho de la imagen que estamos utilizando para el panel de botones, en este caso se debe de poner el numero 384, el resto se deja igual.
bool Sobre_boton(){  
     return ( mouse_x >0 && mouse_x < 384 &&  
              mouse_y >0 && mouse_y < 64 );  
};

En la función cambiaccion(), se añade el siguiente código, que es el que se encarga de comprobar si el cursor esta sobre alguno de los nuevo botones, en ese caso le da un valor a la variable acción.
     
     if (mouse_x > 288 && mouse_x < 320 &&  
        mouse_y > 1   && mouse_y < 32 ){ 
          rect( buffer, 289,1,318,30, 0x666666 );
          accion = 6;      
     }   
     if (mouse_x > 288 && mouse_x < 320 &&  
        mouse_y > 32 && mouse_y < 64){ 
          rect( buffer, 289,33,318,62, 0x666666 ); 
          accion = 7;     
     }   
     if (mouse_x > 320 && mouse_x < 352 &&  
        mouse_y > 1   && mouse_y < 32 ){ 
          rect( buffer, 321,1,350,30, 0x666666 ); 
          accion = 8;     
     }   
     if (mouse_x > 320 && mouse_x < 352 &&  
        mouse_y > 32 && mouse_y < 64){ 
          rect( buffer, 321,33,350,62, 0x666666 ); 
          accion = 9;     
     }
     if (mouse_x > 352 && mouse_x < 384 &&  
        mouse_y > 1   && mouse_y < 32 ){ 
          rect( buffer, 353,1,382,30, 0x666666 ); 
          if ( estado == 0 ){
             anterior = accion;
             estado = 1;          
             accion = 10;   
          }

Después de esta función, se añadirá una nueva función llamada sueltaboton(), que se encarga de controlar las nuevas funciones, ya que se requiere al menos dos puntos para crear la figura correspondiente. Aquí se controla el segundo punto, y se encarga de dibujarlo sobre la imagen dibujo.

void sueltaboton(){
     int r;
     switch(accion){    
     case 6: 
           // linea
           if ( estado == 1 ){
              estado = 0;
                line( dibujo, inix, iniy, mouse_x, mouse_y, colora);
           }          
            break; 
     case 7:
           // circulo
           if ( estado == 1 ) {
                estado = 0;
                int r = int (sqrt( ((inix-mouse_x)*(inix-mouse_x)) + ((iniy-mouse_y)*(iniy-mouse_y)) ));
                if ( relleno ){
                    circlefill(dibujo, inix, iniy, r, colora);
                }else{ 
                    circle(dibujo, inix, iniy, r, colora);
                }
           }          
            break; 
     case 8:
           // rectangulo
           if ( estado == 1 ) {
                estado = 0;
                if ( relleno ){
                     rectfill( dibujo, inix, iniy, mouse_x, mouse_y, colora);
                }else{
                     rect ( dibujo, inix, iniy, mouse_x, mouse_y, colora);
                }
           }          
            break; 
     case 9:
           // elipse
           if ( estado == 1 ) {
                estado = 0;
                if ( relleno ){
                    ellipsefill(dibujo, inix, iniy, abs(inix-mouse_x), abs(iniy-mouse_y), colora);
                }else{
                    ellipse(dibujo, inix, iniy, abs(inix-mouse_x), abs(iniy-mouse_y), colora);  
                }
           }          
            break; 
     case 10:
          if (estado == 1){
             accion = anterior;
             estado = 0;
             relleno = !relleno;
          };
          break;
                
     };                            
}

En la función realizaccion(), se añaden las nuevas acciones que van del 6 al 9.
     case 6: 
           // linea
           if ( estado == 0 ){
              inix = mouse_x;
              iniy = mouse_y;
              estado = 1;
           }
           if ( estado == 1 ) {
                line( buffer, inix, iniy, mouse_x, mouse_y, colora);
           }          
            break; 
     case 7:
           // circulo
           if ( estado == 0 ){
              inix = mouse_x;
              iniy = mouse_y;
              estado = 1;
           }
           if ( estado == 1 ) {
                r = int (sqrt( ((inix-mouse_x)*(inix-mouse_x)) + ((iniy-mouse_y)*(iniy-mouse_y)) ));
                if ( relleno ){
                   circlefill(buffer, inix, iniy, r, colora);
                }else{
                   circle(buffer, inix, iniy, r, colora);
                }
           }          
            break; 
     case 8:
           // rectangulo
           if ( estado == 0 ){
              inix = mouse_x;
              iniy = mouse_y;
              estado = 1;
           }
           if ( estado == 1 ) {
                if ( relleno ){
                     rectfill ( buffer, inix, iniy, mouse_x, mouse_y, colora);
                   }else{
                     rect ( buffer, inix, iniy, mouse_x, mouse_y, colora);
                }
           }          
            break; 
     case 9:
           // elipse
           if ( estado == 0 ){
              inix = mouse_x;
              iniy = mouse_y;
              estado = 1;
           }
           if ( estado == 1 ) {
               if ( relleno ){
                ellipsefill(buffer, inix, iniy, abs(inix-mouse_x), abs(iniy-mouse_y), colora);    
                  }else{                         
                ellipse(buffer, inix, iniy, abs(inix-mouse_x), abs(iniy-mouse_y), colora);
                }
           }          
            break;

Si se han fijado en el código, este y el anterior son muy parecidos la única diferencia entre ellos es que en el de realizaccion() las figuras se realizan sobre la imagen del buffer, y en cambio en la de sueltaboton() las figuras se pintan sobre la imagen dibujo.

 En la función Pinta_botones() también hay que hacer un pequeño cambio a la hora de mostrar la imagen, ya que ahora el ancho de la imagen es 384. Y se añade una condición para cambiar el aspecto del botón rellenar, superponiendo la imagen rellenado sobre la de los botones.
     masked_blit( botones, buffer, 0,0, 0,0,384, 64);
     if ( relleno ) blit(rellenado, buffer, 0,0, 352,0,32,32);


La imagen anterior es la imagen llamada relleno.bmp, que se utiliza para mostrar en el botón para indicar cuando esta activo el relleno.
En el main, para cargar la nueva imagen, en mi caso la he llamado bton-5.bmp, por ello debo de cambiar la linea en la que carga el BITMAP con el nuevo nombre. Además de eso se realizan algunos cambios en el bucle principal.
 botones = load_bmp("bton-5.bmp",NULL);  
 marcador = load_bmp("cselect.bmp",NULL); 
 rellenado = load_bmp("relleno.bmp",NULL); 
   
 clear_to_color(buffer, 0xFFFFFF);   
 clear_to_color(dibujo, 0xFFFFFF);   
  
 while( !key[KEY_ESC] ){  
       blit( dibujo, buffer, 0,0,0,0,ANCHO, ALTO);       
       Pinta_botones();
       
       if ( soltado == 1 ) sueltaboton();
           
       //pulsa boton izquierdo  
       if(mouse_b&1){             
           soltado = 0;             
           Boton_izquierdo();        
       }else{  
           soltado =1;   
       }  
             
       Pinta_cursor();              
       blit(buffer, screen, 0, 0, 0, 0, ANCHO, ALTO);  
 }

Y ya se tiene todo listo para hacerlo funcionar. Solo me falta comentar para que sirve el quinto botón. Este botón se utilizará para escoger si se rellena la figura o no. De esta manera se puede pintar un circulo vacío o relleno, un rectángulo vacío o relleno, y un elipse vacío o relleno. Teniendo en cuenta que cuando se rellena se pinta todo con el color primario en este caso lo que contiene la variable colora.



Recuerda que este tutorial es la continuación del curso Creando un paint :
Parte 1Parte 2Parte 3Parte 4

3 comentarios:

  1. Amigo gracias por el aporte. De donde sale y cual es la función de la imagen "rellenado.bmp"? No entiendo que hace.

    ResponderEliminar
    Respuestas
    1. Dificilmente podrias averiguarlo pues faltaba donde se utilizaba. Ya lo he añadido, y se trata de una imagen que se utiliza para cambiar el boton de rellenado. Lo cual me recuerda que debo añadir esta imagen. Gracias por el aviso ^_^

      Eliminar
  2. Disculpa el código me marca que hay varias funciones no definidas
    tendrás un archivo de como queda la estructura al final?

    ResponderEliminar

Related Posts Plugin for WordPress, Blogger...