|
Kiran Satish wrote: 513x513 and the grid's horizontal and vertical offset is 20 and box width (each box in the grid) is 15 and box gap is 2.
How do you get 513? 12 cells at 15 pixels each is 180 pixels. 11 2-pixel gaps is 22 pixels. Total == 202 pixels (assuming no border).
Kiran Satish wrote: LONG Stride = ((DIBSecWidth * BitsPerPixel + 31L) & (~31L)) / 8L; /**I didnt understand this step, how can I calculate this in my case*/
Bytes per row in a DIB have to be aligned on a DWORD (4-byte) boundary. That's what this calculation does.
The calculation is always the same - it's always based on DIBSecWidth.
Kiran Satish wrote: HBITMAP hbm = ::CreateDIBSection(NULL, &bmi, DIB_RGB_COLORS, (void**)&pDIBSectionBits, NULL, 0);/**I have to replace first argument NULL with my ResCDC */
You don't need to worry about a DC here since the DIBSection is 24-bits-per-pixel.
You shouldn't be worrying about a DC anywhere here - this is al stuff that can be calculated once,
not every time you redraw - that's part of what will save you alot of CPU cycles
Kiran Satish wrote: From then I couldnt understand how I can find pixel address for each pixel in my application while considering box sizes and gap.
It depends on how you want to loop. If it's always by cell, the upper left corner pixel
coordinates (x,y) for a given cell (CellX,CellY) would be
x = CellX * CellWidthInPixels + CellX * GapWidthInPixels;
y = CellY * CellHeightInPixels + CellY * GapHeightInPixels;
With (x,y) you can use the calculation in my examples to get the byte offset in the pixel data.
Make youreslf a handy utility function to calculate these if you're using them alot.
Mark
Mark Salsbery
Microsoft MVP - Visual C++
|
|
|
|
|
Mark Salsbery wrote: How do you get 513? 12 cells at 15 pixels each is 180 pixels. 11 2-pixel gaps is 22 pixels. Total == 202 pixels (assuming no border).
Sorry its 265x250, they are creating this window with these dimensions and while drawing boxes, they add offset of 20 from top and bottom
Here is a snapshot of it. The four corner boxes are always black.
Hope this helps in understanding a lil better.
PKNT
|
|
|
|
|
Kiran Satish wrote: Hope this helps in understanding a lil better.
Yes! Thank you!
In that case the DIBSection can be 202x202.
The calculations I've explained previously will work.
The entire grid bitmap can then be blted to the window at whatever offset you want.
Mark
Mark Salsbery
Microsoft MVP - Visual C++
|
|
|
|
|
Before I start changing the code to use DIBSection, I started referin at BitBlt on msdn and came accross PatBlt and thought of quickly trying it with the following arguments-
within the loop
CBrush *pcolor,tcolor;<br />
for(i=0; i < GRID; i++)
{<br />
for(j=0; j < GRID; j++)<br />
{<br />
if( (j == 0 || j == (GRID-1)) && (i == 0 || i == (GRID-1)) )<br />
;
else<br />
{<br />
resval = (parent->calcfile)->FetchResData(i,j);<br />
ResRect.left = X_OFFSET + (i*(RES_BOX_SIZE+BOX_GAP));<br />
ResRect.right = ResRect.left + RES_BOX_SIZE;<br />
ResRect.top = Y_OFFSET + (j*(RES_BOX_SIZE+BOX_GAP));<br />
ResRect.bottom = ResRect.top + RES_BOX_SIZE;<br />
color = check_ColorLimits(resval); <br />
tcolor = new CBrush(GetRVal(color),GetGVal(color),GetBVal(color));<br />
pcolor = ResCDC->SelectObject(&tcolor);<br />
PatBlt(ResCDC->m_hDC, ResRECT.left, ResRECT.top, (ResRECT.right-ResRECT.left), (ResRECT.bottom-ResRECT.top), PATCOPY);<br />
}<br />
}<br />
}<br />
ResDisp->ReleaseDC(ResCDC);
The above loop is working fine for one grid location and draws one box filled with color, for the second time when it reaches selectobject statement, it is crashing with an error in wingdi.cpp. It seems like I am reselecting a new object without actually releasing the first color or soething like tht. How can I get rid of this error??
thanks,
PKNT
|
|
|
|
|
Any time you select an object into a DC, you should save the
previously selected object. When you're done with the DC, select the original
object back into the DC.
Mark
Mark Salsbery
Microsoft MVP - Visual C++
|
|
|
|
|
Yep.... just done that and here you are with your reply, Damn you beat me again . Slowly getting used to these. Now just using PatBlt instead of SetPixel for GRID window increased my application's closed loop freq from 2.84Hz to 8Hz whoa... Now I have to change the way of drawing other two windows with DIBSection as I cant use PatBlt, since each pixel will have different intensity.
PKNT
|
|
|
|
|
8Hz....your computations must be pretty intense (or your hardware is OLD)!
Mark Salsbery
Microsoft MVP - Visual C++
|
|
|
|
|
At first attempt of using DIBSection for another dialog window which has a drawing area of only 64x64. Here is how I did..
In the constructor of the dialog-
DIBSecWidth = 64;<br />
DIBSecHeight = 64;<br />
BitsPerPixel = 24;<br />
Stride = ((DIBSecWidth * BitsPerPixel + 31L) & (~31L)) / 8L;<br />
BITMAPINFO bmi;<br />
memset(&bmi, 0, sizeof(BITMAPINFO));<br />
bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);<br />
bmi.bmiHeader.biWidth = DIBSecWidth;<br />
bmi.bmiHeader.biHeight = DIBSecHeight;<br />
bmi.bmiHeader.biPlanes = 1;<br />
bmi.bmiHeader.biBitCount = (WORD)BitsPerPixel;<br />
bmi.bmiHeader.biCompression = BI_RGB;<br />
bmi.bmiHeader.biSizeImage = Stride * abs(DIBSecHeight);<br />
hbm = ::CreateDIBSection(NULL, &bmi, DIB_RGB_COLORS, (void**)&pDIBSectionBits, NULL, 0);
In the OnPaint() function of this dialog box-
CWnd *Disp;<br />
CPaintDC dc(this);
Disp = GetDlgItem(ID_PSF);<br />
Disp->InvalidateRect (NULL, TRUE);<br />
Disp->UpdateWindow();<br />
DrawPSF(Disp);
In the DrawPSF(SVDisp) function-
int i,j;<br />
RECT rect;<br />
BYTE color;<br />
unsigned long align_top,align_left;<br />
CDC *SVCDC = SVDisp->GetDC();<br />
SVDisp->GetClientRect(&rect);<br />
align_top = (unsigned long) (rect.bottom - rect.top - row) / 2;<br />
align_left = (unsigned long) (rect.right - rect.left - col) / 2;<br />
RGBTRIPLE *pCurRowPixel = (RGBTRIPLE *)(pDIBSectionBits);<br />
for (int y = 0; y < col; ++y)<br />
{<br />
for (int x = 0; x < row; ++x)<br />
{<br />
color = (BYTE) data[x * col + (row - 1 - y)];<br />
pCurRowPixel[x].rgbtBlue = color;<br />
pCurRowPixel[x].rgbtGreen = color;<br />
pCurRowPixel[x].rgbtRed = color;<br />
}<br />
pCurRowPixel = (RGBTRIPLE *)((BYTE*)pCurRowPixel + Stride);<br />
}<br />
BitBlt((HDC)SVDisp, align_left, align_top, bmi.bmWidth, bmi.bmHeight, (HDC)hbm, 0, 0, SRCCOPY);<br />
SVDisp->ReleaseDC(SVCDC);
I am sure the code is pretty bad, how can get rid of calling DC every time I call the paint function?? Does this way work at all?? dont bother about data, its just the actual data used to generate the intensity at that location as well as row and col.
When I ran the applicaiton with this code, the application hangs at commant BitBlt and never comes back
thanks
PKNT
|
|
|
|
|
Having to cast things to HDC is a bad sign.
You need real device contexts.
The destination DC for BitBlt() should be the PaintDC or a DC you've obtained
for the window you want to draw on.
The source DC for BitBlt() needs to be a memory DC that you've selected the
DIBSection into
hbm = ::CreateDIBSection(NULL, &bmi, DIB_RGB_COLORS, (void**)&pDIBSectionBits, NULL, 0);<br />
DIBSectionDC.CreateCompatibleDC(0);
DIBSectionDC is a CDC member object<br />
hbmOldDIBSecBM = ::SelectObject( DIBSectionDC, hbm
);<br />
DIBSectionDC should be the source dc when you call BitBlt().
You'll need to pass a valid destination DC to your DrawPSF()
function to use as the destination DC.
Mark Salsbery
Microsoft MVP - Visual C++
|
|
|
|
|
Thanks for the reply, it seems the steps are shown in the example of CDC::CreateCompatibleDC in MSDN. But there they are using direct bitmaps (CBitmap class).
Here is how I modified my code based upon your suggesitons above and the exmpale in MSDN
SVDisp->GetClientRect(&rect);<br />
align_top = (unsigned long) (rect.bottom - rect.top - row) / 2;<br />
align_left = (unsigned long) (rect.right - rect.left - col) / 2;<br />
<br />
RGBTRIPLE *pCurRowPixel = (RGBTRIPLE *)(pDIBSectionBits);<br />
for (int y = 0; y < col; ++y)<br />
{<br />
for (int x = 0; x < row; ++x)<br />
{<br />
color = (BYTE) data[x * col + (row - 1 - y)];<br />
pCurRowPixel[x].rgbtBlue = color;<br />
pCurRowPixel[x].rgbtGreen = color;<br />
pCurRowPixel[x].rgbtRed = color;<br />
}<br />
pCurRowPixel = (RGBTRIPLE *)((BYTE*)pCurRowPixel + Stride);<br />
}<br />
<br />
CDC *SVCDC = SVDisp->GetDC();<br />
CDC DIBSectionDC;<br />
DIBSectionDC.CreateCompatibleDC(SVCDC);<br />
HGDIOBJ hbmOldDIBSecBM = ::SelectObject(DIBSectionDC, hbm);<br />
SVCDC->BitBlt(align_left, align_top, bmi.bmiHeader.biWidth, bmi.bmiHeader.biHeight, &DIBSectionDC, 0, 0, SRCCOPY);<br />
<br />
DIBSectionDC.SelectObject(hbmOldDIBSecBM);<br />
SVDisp->ReleaseDC(SVCDC);
it doesnt give any errors, but it shows up nothin on the window, I have seen different values being stored into pDIBSectionBits between (0-255).
The dialog box is filled with a textbox and I am using its handle for getting DC and all. The SVDisp in the above code is a window pointer to that text box.
PKNT
modified on Thursday, September 17, 2009 1:47 PM
|
|
|
|
|
Any suggestions ?? If I can get this to work, then I can use the same way for 3 other dialog boxes.
PKNT
|
|
|
|
|
Kiran Satish wrote: Any suggestions ??
Yes. Get it working just drawing right on the dialog.
I don't know that this control is (Disp = GetDlgItem(ID_PSF); )
that you're drawing to but it's adding unnecessary complexity.
The DIBSectionDC only needs to be created when you create the dibsection,
not every time you draw - we're trying to SAVE time here
Destroy it when you destroy the DIBSection - they go hand-in-hand.
But again, I recommend getting it working drawing right on the dialog.
That means your destination DC is the paintdc, that's fine as long as there's
no controls in the way. That way, you can see what's going on.
Also, go through the code line by line and make sure you understand it.
The same principles apply as you were doing before with setpixel.
the only difference is now you draw to an offscreen DC and then blt the final drawing
to the screen. You have a pointer to the offscreen bits so you can write pixel
values directly to memory and/or use gdi functions to draw offscreen (by
drawing to the DIBSectionDC)....that's the power.
Mark
Mark Salsbery
Microsoft MVP - Visual C++
|
|
|
|
|
At last got it running , removed the text box from the window and bilted it directly onto the dialog box as follows.
void CPSFDlg::OnPaint() <br />
{<br />
CPaintDC dc(this);
HGDIOBJ holdbm;<br />
RECT rect;<br />
BYTE color;<br />
int align_top,align_left;<br />
this->GetClientRect(&rect);<br />
align_top = (rect.bottom - rect.top - row) / 2;<br />
align_left = (rect.right - rect.left - col) / 2;<br />
this->InvalidateRect(NULL,TRUE);<br />
RGBTRIPLE *pCurRowPixel = (RGBTRIPLE *)(pDIBSectionBits);<br />
for (int y = 0; y < col; ++y)<br />
{<br />
for (int x = 0; x < row; ++x)<br />
{<br />
color = (BYTE) data[x * col + (row - 1 - y)];<br />
pCurRowPixel[x].rgbtBlue = color;<br />
pCurRowPixel[x].rgbtGreen = color;<br />
pCurRowPixel[x].rgbtRed = color;<br />
}<br />
pCurRowPixel = (RGBTRIPLE *)((BYTE*)pCurRowPixel + Stride);<br />
} <br />
holdbm = memDC.SelectObject(hbm);<br />
dc.BitBlt(align_left, align_top, bmi.bmiHeader.biWidth, bmi.bmiHeader.biHeight,&memDC,0,0,SRCCOPY);<br />
memDC.SelectObject(holdbm);<br />
}
the problem is, the window keeps on refreshing all the time even though there is nothing happening on tht window and you can see the image flickering in it. How to get rid of it??
thanks,
PKNT
|
|
|
|
|
Never call InvalidateRect or InvalidateRgn from your WM_PAINT handler.
This causes endless WM_PAINT messages! Bad!
Mark Salsbery
Microsoft MVP - Visual C++
|
|
|
|
|
Ooops.... I am just getting on track now... Actually I didnt have InvalidateRect in there at first, at that time, the window doesnt refresh at all. I started off with data filled with 255 and when I ran the program it showed me a nice whire box, but when I do some calculations and when the box is supposed to be changed it doesnt reflect the new data, it still stays white until I move another window over it or something like tht. This is why I added that in OnPaint function.
Anyway I got it now... replaced it into the calling function and tht did the trick. Now I can't wait to do the same for all other windows and see how the performance increases.
thanks,
PKNT
|
|
|
|
|
Whenever your data is updated, use InvalidateRect()/UpdateWindow() (or RedrawWindow()).
This will force an immediate WM_PAINT message to be sent to the window's window procedure.
Just don't do it from inside the WM_PAINT handler
Mark
Mark Salsbery
Microsoft MVP - Visual C++
|
|
|
|
|
Did exactly the same.... now everything is fine... time to go home.. will modify other windows the same way tomm.
thanks for all your help and patience...
PKNT
|
|
|
|
|
Gr8, changing all the drawing to bitmaps improved the speed to ~11Hz. The main bottleneck as you thought before is from a very big matrix multiplication which is done in a for loop element by element. To sum up that multiplication, it includes 66x100x100 matrix (static) multiplied by a 1x66 matrix (variable). I changed this using matrix library from OptiVec and now the speed boosted to ~16Hz. I have to change another loop of the same kind but involves complex matricies of 66x64x64 and 1x66 sizes. That should improve speed close to ~20Hz. But for now ~16Hz is pretty impressive for our application.
Now I will start on developing a new application to display a TIFF image (greyscale images), zoom in and out able to select some points (mark them in red) on the image using mouse, delete any selected point or move any selected point in any mode (normal, zoom in/out) using mouse. Some basic IP functions like histogram equalization, brightness/contrast adjustment. I think single document interface is good enough for this. But whats the best way to draw image (our images may be very big anywhere from 512x512 to 2000x3000) ??
PKNT
|
|
|
|
|
Kiran Satish wrote: But whats the best way to draw image (our images may be very big anywhere from 512x512 to 2000x3000) ??
StretchBlt() takes a source rect and a destination rect so you can specify exactly
what you want drawn, where, and at what scale.
Mark
Mark Salsbery
Microsoft MVP - Visual C++
|
|
|
|
|
So you have a 12x12 grid of cells and you're filling each cell with pixels right?
If so, I would...
Create a memory DC - this only needs to be done for the lifetime of the drawing,
not every time a redraw is done
Make one DIBSection, 24-bit RGB. the size of the 12 cells plus any
gaps/dividers/borders. This only needs to be (re)created if the dimensions
change.
Select the DIBSection into the memory DC.
Now you can use GDI APIs to draw any borders/dividers/etc. You may only have to
do this once as well if you're not overwriting them with data pixels.
Use the pointer to the DIBSection's pixel bits to directly write pixel values in your loops.
The "stride" (# of bytes per row) only needs to be calculated once, or whenever the
size of the DIBSection changes.
To calculate starting offset (rowpointer) in pixel data, use y*stride+x*3
Cast this pointer to an RGBTRIPLE*
For each row
Loop inserting row's pixel data (use rowpointer[x] to index)
Add stride to rowpointer
You'll find this MUCH faster than SetPixel()
After all the cells have been drawn offscreen, a single BitBlt (or StretchBlt)
call can copy the entire grid to the window.
Mark
Mark Salsbery
Microsoft MVP - Visual C++
|
|
|
|
|
Kiran Satish wrote: Hope this helps in understanding a lil better.
Yes! Thank you!
In that case the DIBSection can be 202x202.
The calculations I've explained previously will work.
The entire grid bitmap can then be blted to the window at whatever offset you want.
** I replied to your last message but the reply came back to me.<br />
I think we exceeded the maximum message hierarchy depth in Code Project
Mark
Mark Salsbery
Microsoft MVP - Visual C++
|
|
|
|
|
I had problems with my previous project too. If it doesn't matter you, I think it will be better if you use a View/Doc app insteads of DialogBox app. The view has more functionality than a dialog box. When I changed it, it worked 2,3 times faster with my programm.
If you centralize all datas in the document, and use different views for showing whatever you need, I think it will be faster.
Greetings.
--------
M.D.V.
If something has a solution... Why do we have to worry about?. If it has no solution... For what reason do we have to worry about?
Help me to understand what I'm saying, and I'll explain it better to you
|
|
|
|
|
I thought of implementing in Doc/View architecture, but I have soo many displays embedded into my main display, I am not sure how I can implement soo many views. Not to say the least, I am not that familiar with Doc/View implementation, any good resources on it which are simple and straight away rather than jumping from one part to another part??
thanks
|
|
|
|
|
About how to jump between the views, look for messages related that I wrote. I have asked about how to create different views with different menus more than once. The last, a few days ago.
But if you think is going to be difficult for you to go clear with the Doc/View... then u should try it as you think is better for you.
Greetings.
--------
M.D.V.
If something has a solution... Why do we have to worry about?. If it has no solution... For what reason do we have to worry about?
Help me to understand what I'm saying, and I'll explain it better to you
|
|
|
|
|
Any time you select an object into a DC, you should save the
previously selected object. When you're done with the DC, select the original
object back into the DC.
Mark
Mark Salsbery
Microsoft MVP - Visual C++
|
|
|
|
|