画一条线:鼠标光标在 C Vga 图形上的问题

Drawing a line: Problems with the mouse cursor on C Vga graphics

我正在尝试制作一个程序,您可以在其中通过单击鼠标画一条线,然后当您按下按钮移动时,该线会改变大小和方向,并在您释放它时留在屏幕上(就像在绘画或任何其他照片编辑器中一样)。我正在使用 256-VGA 处理 C。我遇到的问题是在鼠标光标所在的 space 上画一条线。我有这两个功能来显示和隐藏鼠标:

typedef struct MOUSE{
    byte on;
    byte button1;
    byte button2;
    byte button3;
    int num_buttons;
    sword x;
    sword y;
    byte under[MOUSE_SIZE];
    MOUSEBITMAP *bmp;


} MOUSE;
/**************************************************************************
 *  show_mouse                                                            *
 *    Displays the mouse.                                                 *
 **************************************************************************/
void show_mouse(MOUSE *mouse){
    int x,y;
    int mx = mouse->x - mouse->bmp->hot_x;
    int my= mouse->y - mouse->bmp->hot_y;
    long screen_offset = (my<<8)+(my<<6);
    word bitmap_offset = 0;
    byte data;
    //memcpy(double_buffer,VGA,SCREEN_SIZE);
    /* allocate memory for double buffer and background image */
    /*if ((double_buffer = (byte *) malloc(SCREEN_SIZE)) == NULL)
    {
        printf("Not enough memory for double buffer.\n");
        exit(1);
    }   */
    for(y=0;y<MOUSE_HEIGHT;y++){
        for(x=0;x<MOUSE_WIDTH;x++,bitmap_offset++){
            mouse->under[bitmap_offset] = VGA[(word) (screen_offset+mx+x)];
            if(mx+x < SCREEN_WIDTH && mx+x >=0 &&
                my+y < SCREEN_HEIGHT && my+y >=0) //Verificando que estemos dentro de pantalla
                {
                    /*Pintando en pantalla*/
                    data = mouse->bmp->data[bitmap_offset];
                    if(data) 
                    {
                        VGA[(word)(screen_offset+mx+x)] = data;
                    }                       
                }           
        }
        screen_offset+=SCREEN_WIDTH;
    }
    /*show_buffer(double_buffer);
    free(double_buffer);*/
}
 /**************************************************************************
 *  hide_mouse                                                            *
 *    hides the mouse.  This code is not optimized.                       *
 **************************************************************************/

void hide_mouse(MOUSE *mouse){

    int x,y;
    int mx = mouse->x - mouse->bmp->hot_x;
    int my = mouse->y - mouse->bmp->hot_y;
    long screen_offset = (my<<8)+(my<<6);
    word bitmap_offset = 0;
    /*memcpy(double_buffer,VGA,SCREEN_SIZE);
    /* allocate memory for double buffer and background image */
    /*if ((double_buffer = (byte *) malloc(SCREEN_SIZE)) == NULL)
    {
        printf("Not enough memory for double buffer.\n");
        exit(1);
    }   */
    for(y=0;y<MOUSE_HEIGHT;x++,y++){

        for(x=0;x<MOUSE_WIDTH;x++,bitmap_offset++){
            //Verificando que este dentro de pantalla
            if(mx+x < SCREEN_WIDTH &&mx+x >=0 &&
                my+y <SCREEN_HEIGHT && my+y >=0){

                    /*Pintando en pantalla*/

                    VGA[(word)(screen_offset+mx+x)] = mouse->under[bitmap_offset];
                }

        }
        screen_offset+=SCREEN_WIDTH;

    }
    /*show_buffer(double_buffer);
    free(double_buffer);*/
} 

我有 MOUSE 结构的 under 变量,它具有绘制前的屏幕背景。为了在按住按钮时使线随鼠标移动,我存储了鼠标的先前位置并绘制了一条白线(以清理它),然后绘制了另一条具有新位置的线。

问题是,然后我缩小了一条线的尺寸,并沿着这条线移动鼠标指针,鼠标的重新绘制再次绘制了之前的线。 我得到这样的东西:

缩线前:

缩线后:

这是与控制鼠标按钮的循环相关的其余代码void realizar_accion(){

void realizar_accion(){
    /*Caso1: Pintar pixel simple (lapiz)*/
    if(accion==1){

        plot_pixel(mouse_g.x,mouse_g.y,2);
        plot_pixel(mouse_g.x-1,mouse_g.y,2);
        plot_pixel(mouse_g.x,mouse_g.y-1,2);
        plot_pixel(mouse_g.x-1,mouse_g.y-1,2);

    }
    /*Caso2: Pintar Linea*/
    else if(accion==2){
        init_x = mouse_g.x;
        prevx = mouse_g.x;
        init_y = mouse_g.y;
        prevy = mouse_g.y;      
        //line(mouse_g.x,mouse_g.y,mouse_g.x-20,mouse_g.y-20,2);
    }
}
void realizar_accion_mantenido(){
    /*Caso1: Pintar pixel simple (lapiz)*/
    if(accion==1){

        plot_pixel(mouse_g.x,mouse_g.y,2);
        plot_pixel(mouse_g.x-1,mouse_g.y,2);
        plot_pixel(mouse_g.x,mouse_g.y-1,2);
        plot_pixel(mouse_g.x-1,mouse_g.y-1,2);


    }
    /*Caso2: Pintar Linea*/
    else if(accion==2){
        if(on_draw==-1){

            line(init_x,init_y,mouse_g.x,mouse_g.y,2);
            prevx=mouse_g.x;
            prevy=mouse_g.y;
            on_draw=0;

        }
        else{
            if(prevx!=mouse_g.x&&prevy!=mouse_g.y){
                line(init_x,init_y,prevx,prevy,0xFFFF); //borrando la linea anterior
                line(init_x,init_y,mouse_g.x,mouse_g.y,2);
                prevx=mouse_g.x;
                prevy=mouse_g.y;
            }

        }



    }


}

int sobre_barra(){
    if(new_x1>0 && new_x1<33 &&new_y1>0 &&new_y1<181){


        return 1;

    }
    else{

        return -1;
    }


}
void boton_soltado(){

    /*Caso1: Pintar pixel simple (lapiz)*/
    if(accion==1){



    }
    /*Caso2: Pintar Linea*/
    else if(accion==2){
        if(on_draw==0){
            line(init_x,init_y,prevx,prevy,0xFFFF); //borrando la linea anterior
             wait_for_retrace();
             hide_mouse(&mouse_g);
             if (mouse_new!=NULL) mouse_g.bmp=mouse_new;
             mouse_g.x = new_x1;
             mouse_g.y=new_y1;
             show_mouse(&mouse_g);
            line(init_x,init_y,mouse_g.x,mouse_g.y,2);
            prevx=mouse_g.x;
            prevy=mouse_g.y;
            on_draw=-1;         

        }

    }



}
void boton_mantenido(){

    /*Verificar que este dento del buffer de dibujo....*/
    if(sobre_barra()!=1){
        realizar_accion_mantenido();

    }
}
void boton_presionado(){

    if(sobre_barra()==1){
        cambiar_herramienta();

    }
    else{

        realizar_accion();

    }   

}
/**************************************************************************
 *  paint_screen                                                      *
 *    show  main screen paint                                           *
 **************************************************************************/
void paint_screen(BITMAP *fondo){
    int mantenido;
    BITMAP barra,barra_color,normal_ptr_image;
    int anterior_presionado;
    word last_time;
    word redraw,press,release;
    sword dx,dy=0;
    MOUSEBITMAP *mouse_new=NULL;    
    int i,done = 0;
    on_draw=-1;
    accion =2;
    current_color=2;
    /*Pintando fondo blanco*/
    clear_screen();
    /*Pintando barra de herramientas*/
    load_bmp("normal.bmp",&normal_ptr_image);
    load_bmp("mainbar.bmp",&barra);
    load_bmp("colores.bmp",&barra_color);
    set_pallete(fondo->pallete);
    draw_bitmap(&barra,0,0);
    draw_bitmap(&barra_color,0,180);
    load_mouse(&mouse_g);
    show_mouse(&mouse_g);
    wait(50);
    while(!done){
         if(redraw){
             wait_for_retrace();
             hide_mouse(&mouse_g);
             if (mouse_new!=NULL) mouse_g.bmp=mouse_new;
             mouse_g.x = new_x1;
             mouse_g.y=new_y1;
             show_mouse(&mouse_g);
             redraw=0;
             mouse_new=NULL;
         }

        do {                              // check mouse status 
            anterior_presionado = press;
            get_mouse_motion(&dx,&dy);
            press   = get_mouse_press(LEFT_BUTTON);
            release = get_mouse_release(LEFT_BUTTON);
            //Si el estado estaba presionado y no se ha soltado.. el boton esta mantenido
            if(anterior_presionado==1 &&release==0){
              mantenido =1;

            }
        } while (dx==0 && dy==0 && press==0 && release==0&&*my_clock==last_time);    
        if (release){
            mouse_g.button1=0;
            mantenido=0;
            boton_soltado();


        }       

        if (press){

            mouse_g.button1=1;
            boton_presionado();


        } 
        //El boton se mantiene presionado
        else if(mantenido){
            boton_mantenido();
        }
        else{
            release=1;
        }


        if (dx || dy)                     // calculate movement 
        {
          new_x1 = mouse_g.x+dx;
          new_y1 = mouse_g.y+dy; //Actualizamos posicion mouse
          if (new_x1<0)   new_x1=0;
          if (new_y1<0)   new_y1=0;
          if (new_x1>319) new_x1=319;
          if (new_y1>199) new_y1=199;
          redraw=1;
        }

        if(new_x1>=287 && new_x1 <320
            && new_y1>=180 && new_y1 < 200 &&press){

        set_mode(TEXT_MODE); 
        printf("Adios!!");
        wait(25);
        done=0;
        return;


    }   
    }
}

谁能帮我解决这个问题?

我不建议在旧线上画一条白线。相反,您应该使用帧缓冲区,这是一个屏幕外的内存区域,您每次都在其中重新 assemble 它。画背景,然后画线。一旦你放置了这条线,就把它画到背景上……但在那之前它是在之后画的。然后整个事情就是 flipped/copied 到每个循环的屏幕上。有道理吗?