From 572b633c085b0a220742f2defb36694a149a0137 Mon Sep 17 00:00:00 2001
From: deuce <>
Date: Thu, 27 Jan 2005 03:54:28 +0000
Subject: [PATCH] Optimize the X stuff a LOT... 1) Only redraw the individual
 chars that changed, not any line with a char that changed 2) When and Expose
 event or GraphicsExpose event happens, only redraw the affected rectangle
 (Previously, it redrew the entire screen for every exposure)

Make the window slightly resizable... integer scaling only (ie: 1x or 2x)
Currently, will only go up to 2x... if anyone can dig up an open-source
function to do integer-only scaleing of XBitMap (XBM) files or images, I'll
be able to increase this easily enough... but 1280x800 should be enough for
anyone... *snicker*
---
 src/conio/console.c | 223 +++++++++++++++++++++++++++++++++++++-------
 1 file changed, 189 insertions(+), 34 deletions(-)

diff --git a/src/conio/console.c b/src/conio/console.c
index 31979cdce7..e4090cff36 100644
--- a/src/conio/console.c
+++ b/src/conio/console.c
@@ -118,8 +118,8 @@
 #include "mouse.h"
 #include "vgafont.h"
 
-#define CONSOLE_MAX_ROWS	256
-#define CONSOLE_MAX_COLS	256
+#define CONSOLE_MAX_ROWS	61
+#define CONSOLE_MAX_COLS	81
 
 /* Console definition variables */
 int console_new_mode=NO_NEW_MODE;
@@ -136,6 +136,8 @@ sem_t	x11_title;
 int InitCS;
 int InitCE;
 int FW, FH;
+int FS=1;
+#define MAX_SCALE	2
 WORD DpyCols;
 BYTE DpyRows;
 BYTE *palette;
@@ -148,7 +150,8 @@ BYTE CursCol=0;
 typedef struct TextLine {
     WORD	*data;
     u_char	max_length;	/* Not used, but here for future use */
-    u_char	changed:1;
+    u_char	changed;
+	u_char	*exposed;
 } TextLine;
 TextLine *lines = NULL;
 
@@ -372,6 +375,7 @@ struct {
 };
 
 #define	HWM	16
+void resize_window(void);
 
 void tty_pause()
 {
@@ -436,22 +440,17 @@ video_update_text()
 	setgc(attr);
 
 	for (r = 0; r < (DpyRows+1); ++r) {
-	    int cc = 0;
-
 	    if (!lines[r].changed) {
-			if ((r == or || r == CursRow) && (or != CursRow || oc !=CursCol))
-				lines[r].changed=1;
-			else {
-			    for (c = 0; c < DpyCols; ++c) {
-					if (lines[r].data[c] != vmem[r * DpyCols + c]) {
-					    lines[r].changed = 1;
-					    break;
-					}
-					if (lines[r].data[c] & 0x8000 && show != os) {
-					    lines[r].changed = 1;
-					    break;
-					}
-			    }
+			for (c = 0; c < DpyCols; ++c) {
+				if ((lines[r].data[c] != vmem[r * DpyCols + c]) 
+						|| (lines[r].data[c] & 0x8000 && show != os)
+						|| (lines[r].exposed[c])
+						|| (((r == or && c==oc) || (r == CursRow && c==CursCol)) && (or != CursRow || oc !=CursCol))) {
+					setgc(vmem[r * DpyCols + c]  & 0xff00);
+					x11.XCopyPlane(dpy,pfnt,win,gc,0,FH*(vmem[r * DpyCols + c]&0xff),FW,FH,c*FW+2,r*FH+2,1);
+					lines[r].changed = 2;
+					lines[r].exposed[c]=0;
+				}
 			}
 	    }
 
@@ -459,14 +458,18 @@ video_update_text()
 			continue;
 
 		reset_poll();
-		lines[r].changed = 0;
 		memcpy(lines[r].data,
 			&vmem[r * DpyCols], sizeof(WORD) * DpyCols);
 
-		for (c = 0; c < DpyCols; ++c) {
-			setgc(vmem[r * DpyCols + c]  & 0xff00);
-			x11.XCopyPlane(dpy,pfnt,win,gc,0,FH*(vmem[r * DpyCols + c]&0xff),FW,FH,c*FW+2,r*FH+2,1);
+		if(lines[r].changed==1) {
+			for (c = 0; c < DpyCols; ++c) {
+				setgc(vmem[r * DpyCols + c]  & 0xff00);
+				x11.XCopyPlane(dpy,pfnt,win,gc,0,FH*(vmem[r * DpyCols + c]&0xff),FW,FH,c*FW+2,r*FH+2,1);
+			}
 		}
+		lines[r].changed = 0;
+		memset(lines[r].exposed,0,CONSOLE_MAX_COLS * sizeof(u_char));
+		x11.XFlush(dpy);
 	}
 
 	if (CursStart <= CursEnd && CursEnd <= FH &&
@@ -484,8 +487,8 @@ video_update_text()
 	    x11.XChangeGC(dpy, cgc, GCForeground | GCFunction, &v);
 	    x11.XFillRectangle(dpy, win, cgc,
 			   2 +CursCol * FW,
-			   2 + CursRow * FH + CursStart,
-			   FW, CursEnd + 1 - CursStart);
+			   2 + CursRow * FH + CursStart * FS,
+			   FW, (CursEnd + 1)*FS - (CursStart*FS));
 	}
 
 	or =CursRow;
@@ -536,6 +539,12 @@ get_lines()
 				fprintf(stderr, "Could not allocate data structure for text lines\n");
 				exit(1);
 			}
+			lines[i].exposed = (u_char *)malloc(CONSOLE_MAX_COLS * sizeof(u_char));
+			if (lines[i].exposed == NULL) {
+				fprintf(stderr, "Could not allocate data structure for text lines\n");
+				exit(1);
+			}
+			memset(lines[i].exposed,0,CONSOLE_MAX_COLS * sizeof(u_char));
 			lines[i].changed = 1;
 		}
 	}
@@ -563,10 +572,72 @@ void tty_beep(void)
 	sem_post(&x11_beep);
 }
 
+void expose_chars(int x, int y, int width, int height)
+{
+	int sx,sy,ex,ey;
+	int r,c;
+
+	sx=x;
+	sx-=2;
+	if(sx<0)
+		sx=0;
+	sy=y;
+	sy-=2;
+	if(sy<0)
+		sy=0;
+	ex=sx+width+FW-1;
+	ey=sy+height+FH-1;
+	sx/=FW;
+	ex/=FW;
+	if(ex>=DpyCols)
+		ex=DpyCols-1;
+	sy/=FH;
+	ey/=FH;
+	if(ey>DpyRows)
+		ex=DpyRows;
+
+	for(r=sy;r<=ey;r++) {
+		for(c=sx;c<=ex;c++) {
+			lines[r].exposed[c]=1;
+		}
+	}
+}
+
 static int
 video_event(XEvent *ev)
 {
 	switch (ev->type) {
+		case ConfigureNotify: {
+				int newFSH=1;
+				int newFSW=1;
+				int	oldFS;
+				int r;
+
+				oldFS=FS;
+				if((ev->xconfigure.width == FW * DpyCols + 4)
+						&& (ev->xconfigure.height == FH * (DpyRows+1) + 4))
+					break;
+						
+				FW=FW/FS;
+				FH=FH/FS;
+				newFSH=(ev->xconfigure.width+(FW*DpyCols)/2)/(FW*DpyCols);
+				newFSW=(ev->xconfigure.height+(FH*(DpyRows+1))/2)/(FH*(DpyRows+1));
+				if(newFSW<1)
+					newFSW=1;
+				if(newFSW>MAX_SCALE)
+					newFSW=MAX_SCALE;
+				if(newFSH<1)
+					newFSH=1;
+				if(newFSH>MAX_SCALE)
+					newFSH=MAX_SCALE;
+				if(newFSH<newFSW)
+					FS=newFSH;
+				else
+					FS=newFSW;
+				load_font(NULL,FW,FH,FS);
+				resize_window();
+				break;
+		}
 		case SelectionClear: {
 				XSelectionClearEvent *req;
 
@@ -690,11 +761,13 @@ video_event(XEvent *ev)
 	    	}
         case NoExpose:
                 break;
-        case GraphicsExpose:
+        case GraphicsExpose: {
+			expose_chars(ev->xgraphicsexpose.x,ev->xgraphicsexpose.y
+					,ev->xgraphicsexpose.width,ev->xgraphicsexpose.height);
+			break;
+	    }
         case Expose: {
-			int r;
-			for (r = 0; r < (DpyRows+1); ++r)
-		    	lines[r].changed = 1;
+			expose_chars(ev->xexpose.x,ev->xexpose.y,ev->xexpose.width,ev->xexpose.height);
 			break;
 	    }
 	case KeyRelease: {
@@ -1088,6 +1161,7 @@ void
 resize_window()
 {
     XSizeHints *sh;
+	int r;
 
     sh = x11.XAllocSizeHints();
     if (sh == NULL) {
@@ -1098,8 +1172,10 @@ resize_window()
 	sh->base_width = FW * DpyCols + 4;
 	sh->base_height = FH * (DpyRows+1) + 4;
 
-    sh->min_width = sh->max_width = sh->base_width;
-    sh->min_height = sh->max_height = sh->base_height;
+    sh->min_width = (FW/FS) * DpyCols + 4;
+	sh->max_width = (FW/FS) * MAX_SCALE * DpyCols + 4;
+    sh->min_height = (FH/FS) * (DpyRows+1) +4;
+	sh->max_height = (FH/FS) * MAX_SCALE * (DpyRows+1) +4;
     sh->flags = USSize | PMinSize | PMaxSize | PSize;
 
     x11.XSetWMNormalHints(dpy, win, sh);
@@ -1112,12 +1188,83 @@ resize_window()
     return;
 }
 
+/* Scales a bitmap up to 2x it's current size */
+char *
+scale_bitmap(char *bitmap, int width, int height, int *multiplier)
+{
+	char 	*ret;
+	char	*outbyte;
+	int		pos;
+	int		bmpsize;
+
+	if(*multiplier>MAX_SCALE)
+		*multiplier=MAX_SCALE;
+	if(*multiplier < 1)
+		*multiplier=1;
+	bmpsize=width*height;
+	ret=(char *)malloc(bmpsize*(*multiplier)*(*multiplier));
+	if(ret==NULL)
+		return(NULL);
+	outbyte=ret;
+	for(pos=0;pos<bmpsize;pos++) {
+		switch(*multiplier) {
+			case 1:
+				*(outbyte++)=bitmap[pos];
+				break;
+			case 2:
+				*outbyte=
+						 ((bitmap[pos]&0x08)<<4)
+						|((bitmap[pos]&0x08)<<3)
+						|((bitmap[pos]&0x04)<<3)
+						|((bitmap[pos]&0x04)<<2)
+						|((bitmap[pos]&0x02)<<2)
+						|((bitmap[pos]&0x02)<<1)
+						|((bitmap[pos]&0x01)<<1)
+						|((bitmap[pos]&0x01));
+				outbyte++;
+				*outbyte=
+						 ((bitmap[pos]&0x80))
+						|((bitmap[pos]&0x80)>>1)
+						|((bitmap[pos]&0x40)>>1)
+						|((bitmap[pos]&0x40)>>2)
+						|((bitmap[pos]&0x20)>>2)
+						|((bitmap[pos]&0x20)>>3)
+						|((bitmap[pos]&0x10)>>3)
+						|((bitmap[pos]&0x10)>>4);
+				outbyte++;
+				*outbyte=
+						 ((bitmap[pos]&0x08)<<4)
+						|((bitmap[pos]&0x08)<<3)
+						|((bitmap[pos]&0x04)<<3)
+						|((bitmap[pos]&0x04)<<2)
+						|((bitmap[pos]&0x02)<<2)
+						|((bitmap[pos]&0x02)<<1)
+						|((bitmap[pos]&0x01)<<1)
+						|((bitmap[pos]&0x01));
+				outbyte++;
+				*outbyte=
+						 ((bitmap[pos]&0x80))
+						|((bitmap[pos]&0x80)>>1)
+						|((bitmap[pos]&0x40)>>1)
+						|((bitmap[pos]&0x40)>>2)
+						|((bitmap[pos]&0x20)>>2)
+						|((bitmap[pos]&0x20)>>3)
+						|((bitmap[pos]&0x10)>>3)
+						|((bitmap[pos]&0x10)>>4);
+				outbyte++;
+				break;
+		}
+	}
+	return(ret);
+}
+
 /* No longer uses X fonts - pass NULL to use VGA 8x16 font */
 int
-load_font(char *filename, int width, int height)
+load_font(char *filename, int width, int height, int scale)
 {
     XGCValues gcv;
 	char *font;
+	char *scaledfont;
 
 	/* I don't actually do this yet! */
 	if(filename != NULL) {
@@ -1148,7 +1295,15 @@ load_font(char *filename, int width, int height)
 
 	if(pfnt!=0)
 		x11.XFreePixmap(dpy,pfnt);
-	pfnt=x11.XCreateBitmapFromData(dpy, win, font, FW, FH*256);
+	scaledfont=scale_bitmap(font, FW, FH*256, &FS);
+	if(scaledfont==NULL)
+		pfnt=x11.XCreateBitmapFromData(dpy, win, font, FW, FH*256);
+	else {
+		FW*=scale;
+		FH*=scale;
+		pfnt=x11.XCreateBitmapFromData(dpy, win, scaledfont, FW, FH*256);
+		free(scaledfont);
+	}
 
     return(0);
 }
@@ -1211,7 +1366,7 @@ init_mode(int mode)
     update_pixels();
 
     /* Update font. */
-    if(load_font(NULL,vmode.charwidth,vmode.charheight)) {
+    if(load_font(NULL,vmode.charwidth,vmode.charheight,FS)) {
 		sem_post(&console_mode_changed);
 		return(-1);
 	}
@@ -1259,7 +1414,7 @@ init_window()
 
     x11.XSelectInput(dpy, win, KeyReleaseMask | KeyPressMask |
 		     ExposureMask | ButtonPressMask
-		     | ButtonReleaseMask | PointerMotionMask | StructureNotifyMask );
+		     | ButtonReleaseMask | PointerMotionMask | StructureNotifyMask);
 
 	SAFECOPY(window_title,"SyncConsole");
     x11.XStoreName(dpy, win, window_title);
-- 
GitLab