From: jagrant@emr1.emr.ca (John Grant)
Subject: results of tests to draw grid files as images
Organization: Energy, Mines, and Resources, Ottawa
Date: Sat, 2 Jan 1993 23:41:33 GMT

I posted a question recently, got a few ideas, but I wasn't
overwhelmed with responses.  So, I rolled up my sleeves and
wrote some code to explore.  I thought I'd share the results
with the group...

	Results of Tests with Drawing Grid Files
	----------------------------------------

Requirement
-----------
  I have a floating point grid file (336 columns X 807 rows).
I want to draw it as an image file, converting the float values
to colours on the fly: converting it to an image file first is 
not an option for this application.  I also want to be able to 
show it on a 16-colour VGA by taking advantage of Windows 3.1 
dithered colours - i.e. as much device independence as I can manage.

1. First I tried Rectangle(), but it was slow.  There are a zillion
   brush create/select/de-select/delete operations.  In addition,
   Rectangle has to deal with both a brush and a pen (even if you
   select NULL_PEN, I guess).

2. Next I tried PatBlt which was I faster, but still slow.  Well
   maybe it is the brush select/de-select operations? So...

3. Tried FillRect which doesn't require that the brush be selected
   first.  However, there must be some sort of implicit brush
   selection internally.

4. Ok, despite what I have read about "...limited GDI resources..."
   (which was why I started with the first 3 methods), I'll try 
   pre-creating a table of 256 brushes to eliminate the overhead 
   of creating and deleting them.  Wow!  Now we're cookin!

5.  Last combination to complete the set.  Back to PatBlt
    but this time with a brush table.  Well, well, well.
    Guess which method I'm going to use!

Summary
=======
	|           | No. of brush     | No. of brush
Time(s) | Method    | Create & Delete  | Select & de-Select
--------+-----------+------------------+---------------------
454     | Rectangle |   336 X 807 X 2  |   336 X 807 X 2
430     | PatBlt    |   336 X 807 X 2  |   336 X 807 X 2
438     | FillRect  |   336 X 807 X 2  |   0 *
133     | FillRect  |   256            |   0 *
107     | PatBlt    |   256            |   336 X 807
--------+-----------+------------------+---------------------
			* no explicit SelectObject(), but
			  FillRect probably does it internally?

System Information:
	25 MHz 80386 + 80387 
	ATI VGA Wonder 512k (in VGA mode)
	200 Mb disk 96% full
	8 Mb memory
	Windows 3.1
	DOS 5.0
	Borland C++ 3.1

Right now, most of you are saying "Idiot, I could have told you
that most of the overhead was in creating & deleting the brushes!".
Well, I asked for ideas and got a few, but nobody told me much.
So, now we all know.

Hope some of you find this of interest.  If you have any ideas on
speeding it up even more, I sure would be interested in hearing
them!

Happy New Year!  May all your bits be 32 in 1993!

John A. Grant						jagrant@emr1.emr.ca
Airborne Geophysics
Geological Survey of Canada, Ottawa

============================my test code=================================
#define NCOLOUR 256
#define SCALE(v) min(max(       \
		(v-minvalue)*(NCOLOUR-1)/(maxvalue-minvalue) \
		,0),NCOLOUR-1)
#define COLOUR RGB(xxx,0,0)

void DrawGrid(HWND hwnd,char *pathname,int ncol,int nrow,float undefined,
		float minvalue,float maxvalue)
{
FILE *f;
float *value;
int col,row;
int xxx;
HDC hdc;
RECT rect;
HBRUSH hbrush,brushtable[NCOLOUR];

	value=(float *)malloc(nrow*sizeof(float));
	f=fopen(pathname,"rb");

	hdc=GetDC(hwnd);

//method 1: Rectangle, many brush create/delete, many brush select/de-select
	SelectObject(hdc,GetStockObject(NULL_PEN));
	fseek(f,0,SEEK_SET);
	for(col=0;col<ncol;col++){
	  fread(value,sizeof(float),nrow,f);
	  for(row=0;row<nrow;row++){
	    if(value[row]!=undefined){
	       xxx=SCALE(value[row]);
	       hbrush=SelectObject(hdc,CreateSolidBrush(COLOUR));
	       Rectangle(hdc,col,row,col+2,row+2);
	       DeleteObject(SelectObject(hdc,hbrush));
	    }
	  }
	}
	MessageBeep(-1);

//method 2: PatBlt, many brush create/delete, many brush select/de-select
	fseek(f,0,SEEK_SET);
	for(col=0;col<ncol;col++){
	  fread(value,sizeof(float),nrow,f);
	  for(row=0;row<nrow;row++){
	    if(value[row]!=undefined){
	       xxx=SCALE(value[row]);
	       hbrush=SelectObject(hdc,CreateSolidBrush(COLOUR));
	       PatBlt(hdc,col,row,1,1,PATCOPY);
	       DeleteObject(SelectObject(hdc,hbrush));
	    }
	  }
	}
	MessageBeep(-1);

//method 3: FillRect, many brush create/delete, no brush select/de-select
	fseek(f,0,SEEK_SET);
	for(col=0;col<ncol;col++){
	  fread(value,sizeof(float),nrow,f);
	  for(row=0;row<nrow;row++){
	    if(value[row]!=undefined){
	       xxx=SCALE(value[row]);
	       rect.left=  col;
	       rect.right= col+1;
	       rect.top=   row;
	       rect.bottom=row+1;
	       hbrush=CreateSolidBrush(COLOUR);
	       FillRect(hdc,&rect,hbrush);
	       DeleteObject(hbrush);
	    }
	  }
	}
	MessageBeep(-1);

//method 4: FillRect & brush table, no brush select/de-select
	fseek(f,0,SEEK_SET);
	for(xxx=0;xxx<NCOLOUR;xxx++){
	  brushtable[xxx]=CreateSolidBrush(COLOUR);
	}       
	for(col=0;col<ncol;col++){
	  fread(value,sizeof(float),nrow,f);
	  for(row=0;row<nrow;row++){
	    if(value[row]!=undefined){
	       xxx=SCALE(value[row]);
	       rect.left=  col;
	       rect.right= col+1;
	       rect.top=   row;
	       rect.bottom=row+1;
	       FillRect(hdc,&rect,brushtable[xxx]);
	    }
	  }
	}
	for(xxx=0;xxx<NCOLOUR;xxx++){
	  DeleteObject(brushtable[xxx]);
	}       
	MessageBeep(-1);

//method 5: PatBlt & brush table, many brush select, no brush de-select
	fseek(f,0,SEEK_SET);
	for(xxx=0;xxx<NCOLOUR;xxx++){
	  brushtable[xxx]=CreateSolidBrush(COLOUR);
	}
	for(col=0;col<ncol;col++){
	  fread(value,sizeof(float),nrow,f);
	  for(row=0;row<nrow;row++){
	    if(value[row]!=undefined){
	       xxx=SCALE(value[row]);
	       SelectObject(hdc,brushtable[xxx]);
	       PatBlt(hdc,col,row,1,1,PATCOPY);
	    }
	  }
	}
	SelectObject(hdc,GetStockObject(NULL_BRUSH));
	for(xxx=0;xxx<NCOLOUR;xxx++){
	  DeleteObject(brushtable[xxx]);
	}       
	MessageBeep(-1);

	ReleaseDC(hwnd,hdc);

	fclose(f);
	free(value);

	return;
}
-- 
John A. Grant						jagrant@emr1.emr.ca
Airborne Geophysics
Geological Survey of Canada, Ottawa