cairo - schneller zeichnen



  • Hallo,

    ich schreibe gerade ein Schachprogramm, also müssen in jedem Durchgang der Zeichnen-Routine alle 32 Figuren gezeichnet werden.
    Leider benötigt dieser Code sehr lange, bis er ausgeführt ist. Wie könnte ich das anders machen? Ich könnte mir vorstellen, einen Thread zu starten, der andauernd ein Bild erstellt und darauf die Figuren zeichnet; die Haupt-Zeichenroutine zeichnet dann immer das zuletzt fertiggestellte Bild.
    Habe das nun so umgesetzt:

    static cairo_surface_t *boardsurfaceImg;
    static cairo_t *boardsurface;
    static void* drawBoardThread(void *arg);
    
    GtkWidget* init_board_gui(void) {
       boardsurfaceImg = cairo_image_surface_create(CAIRO_FORMAT_ARGB32,1600,1600);
       boardsurface = cairo_create(boardsurfaceImg);   
    
       height = 800;
       width = 800;
    
    	bauerW = cairo_image_surface_create_from_png("whitePawn.png");
    	springerW = cairo_image_surface_create_from_png("whiteKnight.png");
    	laeuferW = cairo_image_surface_create_from_png("whiteBishop.png");
    	turmW = cairo_image_surface_create_from_png("whiteRook.png");
    	dameW = cairo_image_surface_create_from_png("whiteQueen.png");
    	koenigW = cairo_image_surface_create_from_png("whiteKing.png");
    	bauerS = cairo_image_surface_create_from_png("blackPawn.png");
    	springerS = cairo_image_surface_create_from_png("blackKnight.png");
    	laeuferS = cairo_image_surface_create_from_png("blackBishop.png");
    	turmS = cairo_image_surface_create_from_png("blackRook.png");
    	dameS = cairo_image_surface_create_from_png("blackQueen.png");
    	koenigS = cairo_image_surface_create_from_png("blackKing.png");
    
       drawArea = gtk_drawing_area_new();
    	gtk_widget_set_size_request(drawArea,400,400);
    
       g_signal_connect (drawArea, "button-press-event",G_CALLBACK (button_press_event_cb), NULL);
       g_signal_connect (drawArea, "button-release-event",G_CALLBACK (button_release_event_cb), NULL);
       g_signal_connect (drawArea,"motion-notify-event" ,G_CALLBACK (motion_notify_event_cb), NULL); 
      	g_signal_connect(G_OBJECT(drawArea), "draw",G_CALLBACK(on_draw_event), NULL);
    
       pthread_t tid;
    	int rc = pthread_create(&tid,NULL,drawBoardThread,NULL);
    	if(rc != 0) {
    		fprintf(stderr,"drawBoardThread konnte nicht gestartet werden!");
    	}
    
       return drawArea;
    }
    
    static gboolean on_draw_event(GtkWidget *widget, cairo_t *cr, gpointer user_data) {
      do_drawing(cr);
    
      return FALSE;
    }
    
    void setBoardSize(int w, int h) {
       width = w;
       height = h;
    }
    
    static void* drawBoardThread(void *arg) {
       int squareSize = 200;
       while(1) {
          for(int i=0;i<32;i++) {
             if(pieces[i].bx > 7 || pieces[i].by > 7)
                continue;
    		   if(mouseHoldX != -1 && mouseHoldY != -1) {
    			   if(mouseHoldX == pieces[i].bx && mouseHoldY == pieces[i].by && flipped == 1) {
    				   continue;
    			   } else if(mouseHoldX == pieces[i].bx && mouseHoldY == 7-pieces[i].by && flipped == 0)
                   continue;
    		   }
             cairo_save(boardsurface);
    
    		   if(flipped == 1) 
            		cairo_translate(boardsurface,pieces[i].px,pieces[i].py);
    		   else
             	cairo_translate(boardsurface,pieces[i].px,7*squareSize-pieces[i].py);
    
             cairo_scale(boardsurface,1.0/IMAGE_SIZE*squareSize,1.0/IMAGE_SIZE*squareSize);
    
            if(pieces[i].abbr == 'P') {
                cairo_set_source_surface(boardsurface,bauerW,0,0);
                cairo_paint(boardsurface);
             } else if(pieces[i].abbr == 'N') {
                cairo_set_source_surface(boardsurface,springerW,0,0);
                cairo_paint(boardsurface);
             } else if(pieces[i].abbr == 'B') {
                cairo_set_source_surface(boardsurface,laeuferW,0,0);
                cairo_paint(boardsurface);
             } else if(pieces[i].abbr == 'R') {
                cairo_set_source_surface(boardsurface,turmW,0,0);
                cairo_paint(boardsurface);
             } else if(pieces[i].abbr == 'Q') {
                cairo_set_source_surface(boardsurface,dameW,0,0);
                cairo_paint(boardsurface);
             } else if(pieces[i].abbr == 'K') {
                cairo_set_source_surface(boardsurface,koenigW,0,0);
                cairo_paint(boardsurface);
             } else if(pieces[i].abbr == 'p') {
                cairo_set_source_surface(boardsurface,bauerS,0,0);
                cairo_paint(boardsurface);
             } else if(pieces[i].abbr == 'n') {
                cairo_set_source_surface(boardsurface,springerS,0,0);
                cairo_paint(boardsurface);
             } else if(pieces[i].abbr == 'b') {
                cairo_set_source_surface(boardsurface,laeuferS,0,0);
                cairo_paint(boardsurface);
             } else if(pieces[i].abbr == 'r') {
                cairo_set_source_surface(boardsurface,turmS,0,0);
                cairo_paint(boardsurface);
             } else if(pieces[i].abbr == 'q') {
                cairo_set_source_surface(boardsurface,dameS,0,0);
                cairo_paint(boardsurface);
             } else if(pieces[i].abbr == 'k') {
                cairo_set_source_surface(boardsurface,koenigS,0,0);
                cairo_paint(boardsurface);
             }
             cairo_restore(boardsurface);
          }
       }
       return NULL;
    }
    
    static void do_drawing(cairo_t *cr) {
       if(inited == 0 || cr == NULL)
          return;
       int min = width;
       if(height < width)
          min = height;
       squareSize = min/8;
    	for(int j=0;j<8;j++) {
    		for(int i=0;i<8;i++) {
    			cairo_set_source_rgba(cr,0.55,0.45,0.35,1);			
    			if((i+j)%2 == 0) {
    				cairo_set_source_rgba(cr,.7,.6,.5,1);			
    			}
             if(game_status != 0) {
                cairo_set_source_rgba(cr,.4,.5,.6,1);
    			   if((i+j)%2 == 0) {
    				   cairo_set_source_rgba(cr,.7,.6,.5,1);			
    			   }
             }
             if(preMoveBool == 1) {
                if(i == preMoveNumberFromX && j == preMoveNumberFromY) { 
                   cairo_set_source_rgba(cr,0,1,1,0.5);
    //       	      cairo_rectangle(cr, squareSize*i, squareSize*j,squareSize,squareSize); 
    //               cairo_stroke(cr);
           			if(flipped == 1) 
    				      cairo_rectangle(cr, squareSize*i, squareSize*(j), squareSize, squareSize);
    			      else
    				      cairo_rectangle(cr, squareSize*i, squareSize*(7-j), squareSize, squareSize);
                } else if(i == preMoveNumberToX && j == preMoveNumberToY) { 
                   cairo_set_source_rgba(cr,1,1,0,0.5);
    //       	      cairo_rectangle(cr, squareSize*i, squareSize*j,squareSize,squareSize); 
    //               cairo_stroke(cr); 
           			if(flipped == 1) 
    				      cairo_rectangle(cr, squareSize*i, squareSize*(j), squareSize, squareSize);
    			      else
    				      cairo_rectangle(cr, squareSize*i, squareSize*(7-j), squareSize, squareSize);
                }
             }
    
             setDifference();
             if(preMoveBool == 0) {
                if(flipped == 1) {
                   if(i == figNumberFromX && j == figNumberFromY) 
                      cairo_set_source_rgba(cr,1,0,0,0.5);
                   if(i == figNumberToX && j == figNumberToY)
                      cairo_set_source_rgba(cr,0,1,0,0.5);
                } else {
                   if(i == figNumberFromX && j == figNumberFromY) 
                      cairo_set_source_rgba(cr,1,0,0,0.5);
                   if(i == figNumberToX && j == figNumberToY)
                      cairo_set_source_rgba(cr,0,1,0,0.5);
                }
             }
    			if(flipped == 1) 
    				cairo_rectangle(cr, squareSize*i, squareSize*(j), squareSize, squareSize);
    			else
    				cairo_rectangle(cr, squareSize*i, squareSize*(7-j), squareSize, squareSize);
    			cairo_set_line_width(cr, 14);
    			cairo_fill(cr);
    		}
    	}
    
       cairo_save(cr);
       cairo_scale(cr,squareSize*8,squareSize*8);
       cairo_set_source_surface(cr,boardsurfaceImg,0,0);
       cairo_paint(cr);
       cairo_restore(cr);
    
       if(mouseHoldX != -1 && figMousePx != -1 && figMousePy != -1) {
             cairo_save(cr);
         		cairo_translate(cr,figMousePx-0.5*squareSize,figMousePy-0.5*squareSize);
             cairo_scale(cr,1.0/IMAGE_SIZE*squareSize,1.0/IMAGE_SIZE*squareSize);
             if(figMouseSymbol == 'P') {
                cairo_set_source_surface(cr,bauerW,0,0);
                cairo_paint(cr);
             }
             if(figMouseSymbol == 'N') {
                cairo_set_source_surface(cr,springerW,0,0);
                cairo_paint(cr);
             }
             if(figMouseSymbol == 'B') {
                cairo_set_source_surface(cr,laeuferW,0,0);
                cairo_paint(cr);
             }
             if(figMouseSymbol == 'R') {
                cairo_set_source_surface(cr,turmW,0,0);
                cairo_paint(cr);
             }
             if(figMouseSymbol == 'Q') {
                cairo_set_source_surface(cr,dameW,0,0);
                cairo_paint(cr);
             }
             if(figMouseSymbol == 'K') {
                cairo_set_source_surface(cr,koenigW,0,0);
                cairo_paint(cr);
             }
    
             if(figMouseSymbol == 'p') {
                cairo_set_source_surface(cr,bauerS,0,0);
                cairo_paint(cr);
             }
             if(figMouseSymbol == 'n') {
                cairo_set_source_surface(cr,springerS,0,0);
                cairo_paint(cr);
             }
             if(figMouseSymbol == 'b') {
                cairo_set_source_surface(cr,laeuferS,0,0);
                cairo_paint(cr);
             }
             if(figMouseSymbol == 'r') {
                cairo_set_source_surface(cr,turmS,0,0);
                cairo_paint(cr);
             }
             if(figMouseSymbol == 'q') {
                cairo_set_source_surface(cr,dameS,0,0);
                cairo_paint(cr);
             }
             if(figMouseSymbol == 'k') {
                cairo_set_source_surface(cr,koenigS,0,0);
                cairo_paint(cr);
             }
             cairo_restore(cr);     
       }
    }
    

    Leider werden die Figuren jetzt nicht mehr gezeichnet :(. Was mache ich falsch?
    Vielen Dank 🙂



  • Zu viel Code, keine Lust drüberzuschauen 😉

    Grundsätzlich darf das nicht zu langsam sein. Sowas sollte bei weitem schnell genug für Schach sein, auf auf einem 15 Jahre alten Rechner, wahrscheinlich auch auf einem 20 oder 25 Jahre alten Rechner.

    Du willst wirklich C und nicht C++ programmieren?

    Das mit den Threads würde ich auf keinen Fall machen. Du hast eine init_board_gui Funktion, das hört sich ja schon nicht ganz schlecht an. Die Bilder lädst du hoffentlich nur einmal und nicht jedesmal beim Zeichnen?

    Zeig mal deinen ursprünglichen Code, und bitte formatiert.

    Und versuch das ganze zu kapseln, diese if (pieces[i].abbr == ) erzeugt viel zu viel Rauschen. Das schaut nach einer Struktur aus. Dann pack da gleich dieses cairo_surface_t * als Member rein, und setze das beim Zeichnen, brauchst beim Zeichnen doch nicht wissen, was das ist.

    p.s. z.B. Zeilen 190-240 sind komplett überflüssig. Sowas würde reichen:

    cairo_set_source_surface(currentPiece->surface);
    cairo_paint(cr);
    

    Dann hast schon mal 50 Zeilen weniger. In den Zeilen 75-110 genauso. Dann kann man deinen Code vielleicht auch mal lesen.



  • Und versuch das ganze zu kapseln, diese if (pieces[i].abbr == ) erzeugt viel zu viel Rauschen. Das schaut nach einer Struktur aus. Dann pack da gleich dieses cairo_surface_t * als Member rein, und setze das beim Zeichnen, brauchst beim Zeichnen doch nicht wissen, was das ist.

    Gute Idee :), werde ich gleich machen.



  • Die Bilder werden nur einmal geladen, ja. Der ursprüngliche Code ist ziemlich lang:

    #include "board.h"
    
    static GtkWidget* drawArea;
    static int inited = 0;
    
    static void process_draw(GtkWidget* widget);
    
    GtkWidget* init_board_gui(void) {
       preMoveBool = 0;
       privateChessboard = malloc(8*sizeof(char*));
       if(privateChessboard == NULL) {
          perror("malloc");
          exit(EXIT_FAILURE);
       }
       for(int i=0;i<8;i++) {
          errno = 0;
          privateChessboard[i] = malloc(8*sizeof(char));
          if(privateChessboard[i] == NULL) {
             perror("malloc");
             exit(EXIT_FAILURE);
          }
       }
    
       privateChessboard[0][0] = 'R';
       privateChessboard[1][0] = 'N';
       privateChessboard[2][0] = 'B';
       privateChessboard[3][0] = 'Q';
       privateChessboard[4][0] = 'K';
       privateChessboard[5][0] = 'B';
       privateChessboard[6][0] = 'N';
       privateChessboard[7][0] = 'R';
    
       privateChessboard[0][7] = 'r';
       privateChessboard[1][7] = 'n';
       privateChessboard[2][7] = 'b';
       privateChessboard[3][7] = 'q';
       privateChessboard[4][7] = 'k';
       privateChessboard[5][7] = 'b';
       privateChessboard[6][7] = 'n';
       privateChessboard[7][7] = 'r';
    
       for(int i=0;i<8;i++) {
          privateChessboard[i][1] = 'P';
          privateChessboard[i][6] = 'p';
       }
    
       for(int i=0;i<8;i++)
          for(int j=2;j<6;j++)
             privateChessboard[i][j] = '-';
    
       errno = 0;
       preMove = malloc(8);
       if(preMove == NULL) {
          perror("malloc");
          exit(EXIT_FAILURE);
       }
    
       errno = 0;
       pieces = malloc(sizeof(struct figure)*32);
       if(pieces == NULL) {
          perror("malloc");
          exit(EXIT_FAILURE);
       }
    
    	bauerW = cairo_image_surface_create_from_png("whitePawn.png");
    	springerW = cairo_image_surface_create_from_png("whiteKnight.png");
    	laeuferW = cairo_image_surface_create_from_png("whiteBishop.png");
    	turmW = cairo_image_surface_create_from_png("whiteRook.png");
    	dameW = cairo_image_surface_create_from_png("whiteQueen.png");
    	koenigW = cairo_image_surface_create_from_png("whiteKing.png");
    	bauerS = cairo_image_surface_create_from_png("blackPawn.png");
    	springerS = cairo_image_surface_create_from_png("blackKnight.png");
    	laeuferS = cairo_image_surface_create_from_png("blackBishop.png");
    	turmS = cairo_image_surface_create_from_png("blackRook.png");
    	dameS = cairo_image_surface_create_from_png("blackQueen.png");
    	koenigS = cairo_image_surface_create_from_png("blackKing.png");
    
       for(int i=0;i<8;i++) {
          pieces[i].abbr = 'P';
          pieces[i].bx = i;
          pieces[i].by = 1;
          pieces[i].surface = bauerW;
    
          pieces[i+8].abbr = 'p';
          pieces[i+8].bx = i;
          pieces[i+8].by = 6;
          pieces[i+8].surface = bauerS;
    
          pieces[i].px = i*squareSize;
          pieces[i].py = 1*squareSize;
    
          pieces[i+8].px = i*squareSize;
          pieces[i+8].py = 6*squareSize;
       }
       pieces[16].abbr = 'R';
       pieces[17].abbr = 'N';
       pieces[18].abbr = 'B';
       pieces[19].abbr = 'Q';
       pieces[20].abbr = 'K';
       pieces[21].abbr = 'B';
       pieces[22].abbr = 'N';
       pieces[23].abbr = 'R';
       pieces[24].abbr = 'r';
       pieces[25].abbr = 'n';
       pieces[26].abbr = 'b';
       pieces[27].abbr = 'q';
       pieces[28].abbr = 'k';
       pieces[29].abbr = 'b';
       pieces[30].abbr = 'n';
       pieces[31].abbr = 'r';
    
       setPiecePos(&pieces[16],0,0);
       setPiecePos(&pieces[17],1,0);
       setPiecePos(&pieces[18],2,0);
       setPiecePos(&pieces[19],3,0);
       setPiecePos(&pieces[20],4,0);
       setPiecePos(&pieces[21],5,0);
       setPiecePos(&pieces[22],6,0);
       setPiecePos(&pieces[23],7,0);
       setPiecePos(&pieces[24],0,7);
       setPiecePos(&pieces[25],1,7);
       setPiecePos(&pieces[26],2,7);
       setPiecePos(&pieces[27],3,7);
       setPiecePos(&pieces[28],4,7);
       setPiecePos(&pieces[29],5,7);
       setPiecePos(&pieces[30],6,7);
       setPiecePos(&pieces[31],7,7);
    
       height = 800;
       width = 800;
    
       pieces[16].surface = turmW;
       pieces[17].surface = springerW;
       pieces[18].surface = laeuferW;
       pieces[19].surface = dameW;
       pieces[20].surface = koenigW;
       pieces[21].surface = laeuferW;
       pieces[22].surface = springerW;
       pieces[23].surface = turmW;
       pieces[24].surface = turmS;
       pieces[25].surface = springerS;
       pieces[26].surface = laeuferS;
       pieces[27].surface = dameS;
       pieces[28].surface = koenigS;
       pieces[29].surface = laeuferS;
       pieces[30].surface = springerS;
       pieces[31].surface = turmS;
    
       drawArea = gtk_drawing_area_new();
    	gtk_widget_set_size_request(drawArea,400,400);
       gtk_widget_set_events (drawArea, gtk_widget_get_events (drawArea)
                         | GDK_BUTTON_PRESS_MASK
                         | GDK_BUTTON_RELEASE_MASK
    							| GDK_POINTER_MOTION_MASK);
    
       g_signal_connect (drawArea, "button-press-event",G_CALLBACK (button_press_event_cb), NULL);
       g_signal_connect (drawArea, "button-release-event",G_CALLBACK (button_release_event_cb), NULL);
       g_signal_connect (drawArea,"motion-notify-event" ,G_CALLBACK (motion_notify_event_cb), NULL); 
      	g_signal_connect(G_OBJECT(drawArea), "draw",G_CALLBACK(on_draw_event), NULL);
    
       inited = 1;
       return drawArea;
    }
    
    static void setPiecePos(struct figure* f, int i, int j) {
       f->bx = i;
       f->by = j;
       f->px = squareSize*i;
       f->py = squareSize*j;
    }
    
    static gboolean on_draw_event(GtkWidget *widget, cairo_t *cr, gpointer user_data) {
      do_drawing(cr);
    
      return FALSE;
    }
    
    void setBoardSize(int w, int h) {
       width = w;
       height = h;
    }
    
    static void do_drawing(cairo_t *cr) {
       if(inited == 0 || cr == NULL)
          return;
       int min = width;
       if(height < width)
          min = height;
       squareSize = min/8;
    	for(int j=0;j<8;j++) {
    		for(int i=0;i<8;i++) {
    			cairo_set_source_rgba(cr,0.55,0.45,0.35,1);			
    			if((i+j)%2 == 0) {
    				cairo_set_source_rgba(cr,.7,.6,.5,1);			
    			}
             if(game_status != 0) {
                cairo_set_source_rgba(cr,.4,.5,.6,1);
    			   if((i+j)%2 == 0) {
    				   cairo_set_source_rgba(cr,.7,.6,.5,1);			
    			   }
             }
             if(preMoveBool == 1) {
                if(i == preMoveNumberFromX && j == preMoveNumberFromY) { 
                   cairo_set_source_rgba(cr,0,1,1,0.5);
    //       	      cairo_rectangle(cr, squareSize*i, squareSize*j,squareSize,squareSize); 
    //               cairo_stroke(cr);
           			if(flipped == 1) 
    				      cairo_rectangle(cr, squareSize*i, squareSize*(j), squareSize, squareSize);
    			      else
    				      cairo_rectangle(cr, squareSize*i, squareSize*(7-j), squareSize, squareSize);
                } else if(i == preMoveNumberToX && j == preMoveNumberToY) { 
                   cairo_set_source_rgba(cr,1,1,0,0.5);
    //       	      cairo_rectangle(cr, squareSize*i, squareSize*j,squareSize,squareSize); 
    //               cairo_stroke(cr); 
           			if(flipped == 1) 
    				      cairo_rectangle(cr, squareSize*i, squareSize*(j), squareSize, squareSize);
    			      else
    				      cairo_rectangle(cr, squareSize*i, squareSize*(7-j), squareSize, squareSize);
                }
             }
    
             setDifference();
             if(preMoveBool == 0) {
                if(flipped == 1) {
                   if(i == figNumberFromX && j == figNumberFromY) 
                      cairo_set_source_rgba(cr,1,0,0,0.5);
                   if(i == figNumberToX && j == figNumberToY)
                      cairo_set_source_rgba(cr,0,1,0,0.5);
                } else {
                   if(i == figNumberFromX && j == figNumberFromY) 
                      cairo_set_source_rgba(cr,1,0,0,0.5);
                   if(i == figNumberToX && j == figNumberToY)
                      cairo_set_source_rgba(cr,0,1,0,0.5);
                }
             }
    			if(flipped == 1) 
    				cairo_rectangle(cr, squareSize*i, squareSize*(j), squareSize, squareSize);
    			else
    				cairo_rectangle(cr, squareSize*i, squareSize*(7-j), squareSize, squareSize);
    			cairo_set_line_width(cr, 14);
    			cairo_fill(cr);
    		}
    	}
       for(int i=0;i<32;i++) {
          if(pieces[i].bx > 7 || pieces[i].by > 7)
             continue;
    		if(mouseHoldX != -1 && mouseHoldY != -1) {
    			if(mouseHoldX == pieces[i].bx && mouseHoldY == pieces[i].by && flipped == 1) {
    				continue;
    			} else if(mouseHoldX == pieces[i].bx && mouseHoldY == 7-pieces[i].by && flipped == 0)
                continue;
    		}
          cairo_save(cr);
    
    		if(flipped == 1) 
         		cairo_translate(cr,pieces[i].px,pieces[i].py);
    		else
          	cairo_translate(cr,pieces[i].px,7*squareSize-pieces[i].py);
    
          cairo_scale(cr,1.0/IMAGE_SIZE*squareSize,1.0/IMAGE_SIZE*squareSize);
          cairo_set_source_surface(cr,pieces[i].surface,0,0);
          cairo_paint(cr);
    
          cairo_restore(cr);
    
       }
       if(mouseHoldX != -1 && figMousePx != -1 && figMousePy != -1) {
             cairo_save(cr);
         		cairo_translate(cr,figMousePx-0.5*squareSize,figMousePy-0.5*squareSize);
             cairo_scale(cr,1.0/IMAGE_SIZE*squareSize,1.0/IMAGE_SIZE*squareSize);
             if(figMouseSurface != NULL)
                cairo_set_source_surface(cr,figMouseSurface,0,0);
             cairo_paint(cr);
             cairo_restore(cr);     
       }
    }
    
    static gboolean button_press_event_cb (GtkWidget      *widget,
                   GdkEventButton *event,
                   gpointer        data) {
       mxV = event->x;
       myV = event->y;
    
       if(mxV >= squareSize * 8 || myV >= squareSize * 8)
          return FALSE;
    	mouseHoldX = event->x/squareSize;
    	mouseHoldY = event->y/squareSize;
    	figMousePx = event->x;
    	figMousePy = event->y;
    	if(flipped == 1) {
          if(getPieceOnSquare(mxV/squareSize,myV/squareSize) != NULL)
             figMouseSurface = getPieceOnSquare(mxV/squareSize,myV/squareSize)->surface;
          else
             figMouseSurface = NULL;
       } else
          if(getPieceOnSquare(mxV/squareSize,7-myV/squareSize) != NULL)
             figMouseSurface = getPieceOnSquare(mxV/squareSize,7-myV/squareSize)->surface;
          else
             figMouseSurface = NULL;
       gtk_widget_queue_draw(widget);
       return FALSE;
    }
    static gboolean motion_notify_event_cb (GtkWidget      *widget,
                   GdkEventButton *event,
                   gpointer        data) {
    	figMousePx = event->x;
    	figMousePy = event->y;
       gtk_widget_queue_draw(widget);
       return FALSE;
    }
    static gboolean button_release_event_cb (GtkWidget      *widget,
                   GdkEventButton *event,
                   gpointer        data) {
       mxN = event->x;
       myN = event->y;
       if(mxN >= squareSize * 8 || myN >= squareSize * 8)
          return FALSE;
       mouseHoldX = -1;
       mouseHoldY = -1;
    	figMousePx = -1;
    	figMousePy = -1;
    	if(flipped == 1) 
    	   handleMove(mxV/squareSize,myV/squareSize,mxN/squareSize,myN/squareSize);
    	else 
    	   handleMove(mxV/squareSize,7-myV/squareSize,mxN/squareSize,7-myN/squareSize);
    
       gtk_widget_queue_draw(widget);
       return FALSE;
    }
    
    static void handleMove(int x, int y, int x2, int y2) {
       figNumberFromX = x;
       figNumberFromY = y;
       figNumberToX = x2;
       figNumberToY = y2;
       errno = 0;
       char *zug = malloc(sizeof(char)*10);
       if(zug == NULL) {
          perror("malloc");
          exit(EXIT_FAILURE);
       }
       zug[0] = getLetterFromNumber(x);
       zug[1] = getNumberFromNumber(y);
    
       zug[2] = '-';
       zug[3] = getLetterFromNumber(x2);
       zug[4] = getNumberFromNumber(y2);
       zug[5] = '\0';
    
       if(client_move == -1) {
          strncpy(preMove,zug,6);
          preMoveBool = 1;
          preMoveNumberFromX = x;
          preMoveNumberFromY = y;
          preMoveNumberToX = x2;
          preMoveNumberToY = y2;
       }
       sendLine("board.c",zug);
    }
    
    static char getLetterFromNumber(int nr) {
        switch(nr) {
          case 0: return 'a';
          case 1: return 'b';
          case 2: return 'c';
          case 3: return 'd';
          case 4: return 'e';
          case 5: return 'f';
          case 6: return 'g';
          case 7: return 'h';
       }  
       return ' ';
    }
    
    static char getNumberFromNumber(int nr) {
       switch(nr) {
          case 0: return '1';
          case 1: return '2';
          case 2: return '3';
          case 3: return '4';
          case 4: return '5';
          case 5: return '6';
          case 6: return '7';
          case 7: return '8';
       }
       return ' ';
    }
    
    static void setDifference(void) {
       if(strncmp(movestr,"O-O",3) == 0 && strncmp(movestr,"O-O-O",5) != 0) {
          if(privateChessboard[4][7] != chessboard[4][7]) {
             struct figure* king = getPieceOnSquare(4,7);
             if(king != NULL)
                king->bx = 6;
             struct figure* rook = getPieceOnSquare(7,7);
             if(rook != NULL)
                rook->bx = 5;
          } else if(privateChessboard[4][0] != chessboard[4][0]) {
             struct figure* king = getPieceOnSquare(4,0);
             if(king != NULL)
                king->bx = 6;
             struct figure* rook = getPieceOnSquare(7,0);
             if(rook != NULL)
                rook->bx = 5;
          }
          for(int i=0;i<8;i++) {
             for(int j=0;j<8;j++) {
                privateChessboard[i][j] = chessboard[i][j];
             }
          }
       } else if(strncmp(movestr,"O-O-O",5) == 0) {
          if(privateChessboard[4][7] != chessboard[4][7]) {
             struct figure* king = getPieceOnSquare(4,7);
             if(king != NULL)
                king->bx = 2;
             struct figure* rook = getPieceOnSquare(0,7);
             if(rook != NULL)
                rook->bx = 3;
          } else if(privateChessboard[4][0] != chessboard[4][0]) {
             struct figure* king = getPieceOnSquare(4,0);
             if(king != NULL)
                king->bx = 2;
             struct figure* rook = getPieceOnSquare(0,0);
             if(rook != NULL)
                rook->bx = 3;
          }
          for(int i=0;i<8;i++) {
             for(int j=0;j<8;j++) {
                privateChessboard[i][j] = chessboard[i][j];
             }
          }
       }
       int diff = 0;
    	int cnt = 0;
       for(int i=0;i<8;i++) {
          for(int j=0;j<8;j++) {
             if(chessboard[i][j] != privateChessboard[i][j]) {
                diff = 1;
                if(chessboard[i][j] == '-') {
                   figNumberFromX = i;
                   figNumberFromY = j;
                } else {
                   figNumberToX = i;
                   figNumberToY = j;
                }
                privateChessboard[i][j] = chessboard[i][j];
    				cnt++;
             }
          }
       }
    	if(cnt > 2) { //set pieces so that it reflects the board position
    		for(int i=0;i<8;i++)
    			for(int j=0;j<8;j++)
    				privateChessboard[i][j] = chessboard[i][j];
    
    		int Pcnt = 0, pcnt = 0;
    		int Rcnt = 0, rcnt = 0;
    		int Bcnt = 0, bcnt = 0;
    		int Ncnt = 0, ncnt = 0;
    		for(int i=0;i<8;i++) {
    			for(int j=0;j<8;j++) {
    				if(privateChessboard[i][j] == 'R') {
    					setPiecePos(&pieces[16+7*Rcnt],i,j);
    					Rcnt++;
    				} else if(privateChessboard[i][j] == 'N') {
    					setPiecePos(&pieces[17+5*Ncnt],i,j);
    					Ncnt++;
    				} else if(privateChessboard[i][j] == 'B') {
    					setPiecePos(&pieces[18+3*Bcnt],i,j);
    					Bcnt++;
    				} else if(privateChessboard[i][j] == 'Q') {
    					setPiecePos(&pieces[19],i,j);
    				} else if(privateChessboard[i][j] == 'K') {
    					setPiecePos(&pieces[20],i,j);
    				} else if(privateChessboard[i][j] == 'P') {
    					setPiecePos(&pieces[Pcnt],i,j);
    					Pcnt++;
    				}
    
    				if(privateChessboard[i][j] == 'r') {
    					setPiecePos(&pieces[24+7*rcnt],i,j);
    					rcnt++;
    				} else if(privateChessboard[i][j] == 'n') {
    					setPiecePos(&pieces[25+5*ncnt],i,j);
    					ncnt++;
    				} else if(privateChessboard[i][j] == 'b') {
    					setPiecePos(&pieces[26+3*bcnt],i,j);
    					bcnt++;
    				} else if(privateChessboard[i][j] == 'q') {
    					setPiecePos(&pieces[27],i,j);
    				} else if(privateChessboard[i][j] == 'k') {
    					setPiecePos(&pieces[28],i,j);
    				} else if(privateChessboard[i][j] == 'p') {
    					setPiecePos(&pieces[pcnt+8],i,j);
    					pcnt++;
    				}
    			}
    		}
    	}
    
       if(diff == 1) {
          struct figure* before = getPieceOnSquare(figNumberToX, figNumberToY);
          if(before != NULL) { 
             before->bx = 10;
             before->by = 5;
          }
          struct figure* f = getPieceOnSquare(figNumberFromX, figNumberFromY);
          if(f != NULL) {
             f->bx = figNumberToX;
             f->by = figNumberToY;
          }
       }
       if(diff == 1) {
          pid_t pid = fork();
          if(pid == 0) {
             execlp("aplay", "aplay", "clack.wav", NULL);
             printf("EXIT aplay\n");
             exit(EXIT_FAILURE);
          }
       }
    }
    
    static struct figure* getPieceOnSquare(int i, int j) {
       for(int k=0;k<32;k++) {
          if(pieces[k].bx == i && pieces[k].by == j)
             return &pieces[k];
       }
       return NULL;
    }
    
    void deletePreMove(void) {
       preMoveBool = 0;
       updateBoardUI();
    }
    
    void* movingThread(void* arg) {
       double delta = squareSize/1.6;
       while(1) {
          for(int i=0;i<32;i++) {
             if(pieces == NULL)
                continue;
             if(pieces[i].px > squareSize*pieces[i].bx)
                pieces[i].px -= delta;
             if(pieces[i].px < squareSize*pieces[i].bx)
                pieces[i].px += delta;
             if(pieces[i].py > squareSize*pieces[i].by)
                pieces[i].py -= delta;
             if(pieces[i].py < squareSize*pieces[i].by)
                pieces[i].py += delta;
    
             if(abs(pieces[i].px - squareSize*pieces[i].bx) < delta)
                pieces[i].px = squareSize*pieces[i].bx;
             if(abs(pieces[i].py - squareSize*pieces[i].by) < delta)
                pieces[i].py = squareSize*pieces[i].by;
          }
          usleep(1000*25);
    		g_idle_add((GSourceFunc)process_draw,drawArea); 
       }
       return NULL;
    }
    
    void updateBoardUI(void) {
       for(int i=0;i<32;i++) {
    //      printf("pieces[%i].by=%i, pieces[%i].py=%i\n",i,(int)pieces[i].by,i,(int)pieces[i].py);
       }
       if(client_move == 1) {
          if(preMoveBool == 1) {
             sendLine("board.c",preMove);
             preMoveBool = 0;
          }
       }
    	g_idle_add((GSourceFunc)process_draw,drawArea);
    }
    
    static void process_draw(GtkWidget* widget) {
    	gtk_widget_queue_draw(widget);
    }
    

    Und die zugehörige Header-Datei:

    #ifndef BOARD_H
    #define BOARD_H
    
    #define _BSD_SOURCE
    
    #include <stdlib.h>
    #include <stdio.h>
    #include <sys/stat.h>
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <netdb.h>
    #include <errno.h>
    #include <netinet/in.h>
    #include <string.h>
    #include <unistd.h>
    #include <gtk/gtk.h>
    #include <cairo.h>
    
    #include "chess.h"
    
    struct figure {
       char abbr;
       double px;
       double py;
       int bx;
       int by;
       cairo_surface_t *surface;
    } *pieces;
    
    static char** privateChessboard;
    static char* preMove;
    static int preMoveBool;
    static int mxN, myN, mxV, myV;
    static int height, width;
    static int squareSize = 50;
    static int IMAGE_SIZE = 250;
    static int mouseHoldX, mouseHoldY;
    static int figMousePx, figMousePy;
    static char figMouseSymbol;
    static cairo_surface_t *figMouseSurface;
    static cairo_surface_t *bauerW, *springerW, *laeuferW, *turmW, *dameW, *koenigW;
    static cairo_surface_t *bauerS, *springerS, *laeuferS, *turmS, *dameS, *koenigS;
    static int figNumberFromX, figNumberFromY, figNumberToX, figNumberToY;
    static int preMoveNumberFromX, preMoveNumberFromY, preMoveNumberToX, preMoveNumberToY;
    
    GtkWidget* init_board_gui(void);
    void setBoardSize(int,int);
    void updateBoardUI(void);
    void deletePreMove(void);
    
    static void setPiecePos(struct figure* f, int i, int j);
    static struct figure* getPieceOnSquare( int i, int j);
    static void setDifference(void);
    static char getNumberFromNumber(int nr);
    static char getLetterFromNumber(int nr);
    static gboolean button_press_event_cb (GtkWidget      *widget,
                   GdkEventButton *event,gpointer        data);
    static gboolean motion_notify_event_cb (GtkWidget      *widget,
                   GdkEventButton *event,
                   gpointer        data);
    static gboolean button_release_event_cb (GtkWidget      *widget,
                   GdkEventButton *event,
                   gpointer        data);
    static gboolean on_draw_event(GtkWidget *widget, cairo_t *cr, gpointer user_data);
    static void do_drawing(cairo_t *cr);
    static void handleMove(int x, int y, int x2, int y2);
    void* movingThread(void* arg);
    
    #endif
    

    Wenn ich den Code so ausführe, dann wird die Figur, die mit der Maus gezogen wird nur stark verzögert auch auf dem Brett verschoben. Werden die 32 Figuren nicht gezeichnet, dann geht das ohne Verzögerung.



  • Die relevanten Stellen hätten gereicht 😉 Das wäre in deinem Fall das do_drawing und wohl das setDifferences.

    Was mir schon mal auffällt ist, dass du zu viele unnötige Operationen ausführst. Was soll z.B. diese Schleife am Anfang von do_drawing? Du rufst mindestens 64 mal cairo_set_source_rgba, warum? Das hat nur einmal Auswirkungen. Also entscheide dich einmal, welchen Wert zu setzen willst und ruf das dann nur ein mal auf. Versuch, die ganzen cairo Funktionen so selten wie möglich aufzurufen.

    Das setDifferences schaut auch sehr komplex aus, kann ich spontan nicht sagen, ob das Sinn macht.

    Kannst du das Problem eingrenzen? Wenn du keine Figur bewegst und einfach nur 32 Figuren zeichnest, ist es dann schnell genug?



  • Übrigens, du kannst auf jeden Fall das Spielbrett cachen. Du kannst das Brett und alle Figuren, die grad nicht bewegt werden in ein offscreen surface zeichnen. Dann zeichnest du das beim Zeichnen auf den Bildschrim und zeichnest nur die Figur nochmal drüber, die bewegt wird.



  • Wenn ich das "cairo_paint(cr);" aus Zeile 266 rauslasse, dann funktioniert es ohne Verzögerung.



  • In jedem Mal-Durchgang 32x ein transformiertes Surface über das gesamte Fenster zu malen ist auch keine gute Idee.
    Das Setzen von Pattern in Cairo ist ziemlich günstig, da Pattern nur ein paar Bytes sind, die beim Rendern das Füllen beschreiben. Echte Flaschenhälse sind cairo_fill* und cairo_stroke* Aufrufe (besonders mit vielen Kurven im Path) und das Transformieren von Surfaces.
    Der beste Tipp in diesem Fall wurde bereits von Mechanics genannt: Caching!
    Render nicht mehr wie nötig, verwende Gezeichnetes wieder. Male das Schachbrett einmal auf ein image surface und male dieses, so wie es ist, zuerst, danach die Figuren drüber, welche nur noch in ihrer Position transformiert werden sollten.



  • Ja, das stimmt, jedesmal die Bilder zu skalieren ist keine gute Idee ;).

    static void scaleImages(int size) {
       for(int i=0;i<32;i++) {
          cairo_t *cr = cairo_create(pieces[i].surface);
          cairo_save(cr);
          int IMAGE_HEIGHT = cairo_image_surface_get_height(pieces[i].surface);
          int IMAGE_WIDTH = cairo_image_surface_get_width(pieces[i].surface);
          cairo_scale(cr,1.0/IMAGE_HEIGHT*size,1.0/IMAGE_WIDTH*size);
          cairo_set_source_surface(cr,pieces[i].surface,0,0);
          cairo_paint(cr);
          cairo_restore(cr);
       }
    }
    

    Meine Intention ist, die Figuren auf dem gleichen Surface zu skalieren und wieder darauf zu zeichnen. Zunächst soll aber der Inhalt gelöscht werden. Nur wie mache ich das? Oder soll ich per Holzhammermethode einfach eine neue Surface anlegen und das Bild quasi jedesmal kopieren?

    EDIT: Hab den Fehler gefunden :). Ich muss cairo_fill verwenden und zusätzlich habe ich die Bildgröße falsch berechnet.

    EDIT 2: Das hat das Problem leider doch nicht gelöst. Jetzt sind Bilder aller möglichen Skalierungsfaktoren gezeichnet.

    EDIT 3 :):
    Nach http://cairographics.org/FAQ/#clear_a_surface sollte es so eigentlich gehen, tut es aber nicht. hm..

    static void scaleImages(int size) {
       for(int i=0;i<32;i++) {
          cairo_t *cr = cairo_create(pieces[i].surface);
          cairo_save(cr);
          cairo_set_operator(cr,CAIRO_OPERATOR_CLEAR);
          cairo_paint(cr);
          cairo_restore(cr);
          cairo_save(cr);
          int IMAGE_HEIGHT = cairo_image_surface_get_height(pieces[i].surface);
          int IMAGE_WIDTH = cairo_image_surface_get_width(pieces[i].surface);
          cairo_scale(cr,1.0/IMAGE_HEIGHT*size,1.0/IMAGE_WIDTH*size);
          cairo_set_source_surface(cr,pieces[i].surface,0,0);
          cairo_paint(cr);
          cairo_restore(cr);
       }
    }
    

    "Geht nicht" bedeutet hier übrigens, dass gar nichts angezeigt wird.



  • coder21 schrieb:

    Meine Intention ist, die Figuren auf dem gleichen Surface zu skalieren und wieder darauf zu zeichnen. Zunächst soll aber der Inhalt gelöscht werden. Nur wie mache ich das? Oder soll ich per Holzhammermethode einfach eine neue Surface anlegen und das Bild quasi jedesmal kopieren?

    Was heißt auf dem gleichen?
    Notfalls kannst du das surface löschen, indem du ein weißes Rechteck drüberzeichnest.



  • Notfalls kannst du das surface löschen, indem du ein weißes Rechteck drüberzeichnest.

    Das Surface soll aber transparent sein. Und genau das versuche ich ja zu machen mit:

    cairo_set_operator(cr,CAIRO_OPERATOR_CLEAR);
    


  • Btw.: Entferne die static-Variablen aus deinem Header und packe sie in den Source-Code. Wenn du doch globale Variablen benötigst, dann verwende "extern" im Header und lege diese Variablen in genau einer SourceCode-Datei ab (aber dann ohne 'static').



  • tw.: Entferne die static-Variablen aus deinem Header und packe sie in den Source-Code. Wenn du doch globale Variablen benötigst, dann verwende "extern" im Header und lege diese Variablen in genau einer SourceCode-Datei ab (aber dann ohne 'static').

    Kann ich machen. Ich wusste nicht, wie es üblich ist, die Variablen zu definieren. Ich dachte nur, dass es so übersichtlicher wäre.


Log in to reply