MultiWin and imglib

Discussions related to graphics (2D and 3D), animation and games programming
KenDown
Posts: 327
Joined: Wed 04 Apr 2018, 06:36

MultiWin and imglib

Post by KenDown »

Hmmmm. Am I doing something wrong or is there a very good reason why I am not using imglib in my program?

Code: Select all

      INSTALL@lib$+"IMGLIB_W"
      PROC_imgInit
      INSTALL@lib$+"WINLIB5A"
      INSTALL@lib$+"MULTIWINMOD"
      PROC_multiwin(2)
      hw1%=FN_createwin(1,"Presenter window",0,0,1280,840,0,&96C00000,0)
      pic$="F:\Sermons\JohnTheBaptist\Hippolytus.jpg"

      x%=1280
      GCOL0,9
      VDU23,23,8;0;0;0;
      LINE0,0,x%,900
      t%=FN_imgLoad(pic$)
      PROC_imgPlot(t%,x%,840,0.5,0.5,0)
      PROC_selectwin(1)
      VDU26
      GCOL0,9
      VDU23,23,8;0;0;0;
      LINE0,0,x%,900
      PROC_imgPlot(t%,x%,840,0.5,0.5,0)
      END
This creates two windows and draws a red line diagonally across them both, to show that the windows are set up correctly and do receive graphics input. However the image plot routine in imglib will not display the picture in the second window! (You'll have to substitute a picture path and name of your own.)

Of course, I am hampered by the lack of documentation for imglib (that I've been able to find, anyway) and perhaps there is some call that will send the output to the right window. Suggestions appreciated.
KenDown
Posts: 327
Joined: Wed 04 Apr 2018, 06:36

Re: MultiWin and imglib

Post by KenDown »

I won't claim to be experienced with gdiplib, but I have used its facilities to provide translucent backgrounds in my program and also to draw thick lines with arrows and other symbols. I couldn't work out why that kept failing until someone here kindly suggested an undocumented call to FN_gdipsetdc(@memhdc%) and now those features will work on multi windows. It therefore occurred to me that as imglib does a lot of calls to gdip functions perhaps I needed to set the DC before using it.

Result? No better.

Code: Select all

      INSTALL@lib$+"GDIPLIB"
      PROC_gdipinit
      INSTALL@lib$+"IMGLIB_W"
      PROC_imgInit
      INSTALL@lib$+"WINLIB5A"
      INSTALL@lib$+"MULTIWINMOD"
      PROC_multiwin(2)
      hw1%=FN_createwin(1,"Presenter window",0,0,1280,840,0,&96C00000,0)
      pic$="F:\Sermons\JohnTheBaptist\Hippolytus.jpg"

      x%=1280
      t%=FN_imgLoad(pic$)

      PROC_selectwin(0)
      VDU26
      GCOL0,9
      VDU23,23,8;0;0;0;
      LINE0,0,x%,900
      PROC_imgPlot(t%,x%,840,0.5,0.5,0)

      PROC_selectwin(1)
      VDU26
      GCOL0,9
      VDU23,23,8;0;0;0;
      LINE0,0,x%,900
      tmp%=FN_gdipsetdc(@memhdc%)
      PROC_imgPlot(t%,x%,840,0.5,0.5,0)
      END
Drat!
KenDown
Posts: 327
Joined: Wed 04 Apr 2018, 06:36

Re: MultiWin and imglib

Post by KenDown »

Ha! Problem solved (at least in part). The problem lies in IMGLIB itself.

In the initialisation procedure at the very start a variable G@imglib% is created which is tied to the @memhdc% at the start - which, of course, is the main window. Then, when PROC_imgPlot is called, GdipDrawImageFX is invoked with G@imglib%, so naturally drawing will only take place on the main window. (And, if you have selected another window, drawing just doesn't happen at all!)

The solution appears to be to incorporate those two lines in PROC_imgPlot The revised procedure is below.

Code: Select all

      DEFPROC_imgPlot(I%,x,y,s,t,a)
      LOCALM%,R%:DIMR%LOCAL15
      x+=@vdu.o.x%:y+=@vdu.o.y%
      SYS`GdipCreateMatrix2`,&3F800000,FALSE,FALSE,&3F800000,FN_f4(x/2),FN_f4(@vdu%!212-y/2),^M%
      SYS`GdipRotateMatrix`,M%,FN_f4(a),0
      SYS`GdipScaleMatrix`,M%,FN_f4(s),FN_f4(t),0
      SYS`GdipTranslateMatrix`,M%,FN_f4(-I%!4/2),FN_f4(-I%!8/2),0
      SYS`SetBoundsRect`,@memhdc%,0,5

      SYS`GdipCreateFromHDC`,@memhdc%,^G@imglib%
      SYS`GdipSetInterpolationMode`,G@imglib%,3 : REM bilinear

      SYS`GdipDrawImageFX`,G@imglib%,!I%,0,M%,0,I%!12,2
      SYS`GetBoundsRect`,@memhdc%,R%,0
      SYS`OffsetRect`,R%,-@ox%,-@oy%
      SYS`InvalidateRect`,@hwnd%,R%,0
      SYS`GdipDeleteMatrix`,M%
      ENDPROC
You will notice that if you make this change in IMGLIB and save it in the libraries directory (please rename the original IMGLIB so that you don't overwrite it, in case of disasters) the sample program I provided in my first post to this thread now works and displays the picture in both windows and different rotation angles can be specified for each picture.

I would welcome comment from Richard. For example, do I need both lines? Would it be better if G@imglib% was made LOCAL? Would he like to include this alteration in subsequent versions (or even the current download) of IMGLIB?
DDRM

Re: MultiWin and imglib

Post by DDRM »

Richard, who is currently absenting himself from the forum, asks me to point out that Kendall's suggested modification to imglib would cause a major resource leak, that is likely to crash the process, possibly very rapidly in some programs. This is because it creates a new device context every time PROC_ImgPlot is called, and never releases them.

Best wishes,

D
KenDown
Posts: 327
Joined: Wed 04 Apr 2018, 06:36

Re: MultiWin and imglib

Post by KenDown »

Yes, I have just seen his post to the Discussion Group. Unfortunately he does not propose a solution and indeed simply says, "The IMGLIB library does not provide any support for plotting images to multiple windows in the same program, and that capability would not be easy to add. It would involve having an array of GDI+ graphics contexts, one per window, and somehow selecting the appropriate context for the particular window. Should such a capability be wanted it would probably be better to create a new library specifically for the purpose."

Well, I *do* want that capability; in my program I have a minimum of three windows that require pictures posted to them and on occasion as many as six! I am grateful to Richard for pointing out the resource leak (which I am not clever enough to have recognised). It seems to me, however, that the "leak" could be solved by releasing each contact as soon as it is used. Is that too simplistic?

Watch this space!
KenDown
Posts: 327
Joined: Wed 04 Apr 2018, 06:36

Re: MultiWin and imglib

Post by KenDown »

Over on the Discussion Group Richard has been somewhat scathing about my attempt to alter IMGLIB (and I suppose I can't blame him) but I post the following short program without further comment. Please note that it uses Richard's original IMGLIB, not my modified version. Those who wish to test the program will have to substitute their own picture names; all the pictures are a standard size of 1280x840.

Code: Select all

      INSTALL@lib$+"IMGLIB_W"
      PROC_imgInit
      FORi%=0TO10
        READpic$
        t%=FN_imgLoad(pic$)
        PROC_imgPlot(t%,1280,840,0.5,0.5,0)
        g%=GET
      NEXT
      PROC_imgExit
      END

      DATAF:\Sermons\JohnTheBaptist\Hippolytus.jpg
      DATAF:Sermons\AgeofEarth\aali.jpg
      DATAF:Sermons\AgeofEarth\ancientword.jpg
      DATAF:Sermons\AgeofEarth\dilmun01.jpg
      DATAF:Sermons\AgeofEarth\gilgamesh00.jpg
      DATAF:Sermons\AgeofEarth\gilgamesh01.jpg
      DATAF:Sermons\AgeofEarth\gilgamesh02.jpg
      DATAF:Sermons\AgeofEarth\diglamesh03.jpg
      DATAF:Sermons\AgeofEarth\judgedates01.jpg
      DATAF:Sermons\AgeofEarth\judges.jpg
      DATAF:Sermons\AgeofEarth\kinglist.jpg
It is possible that I have left out some very important step, but again, it is the lack of documentation that is to blame.
KenDown
Posts: 327
Joined: Wed 04 Apr 2018, 06:36

Re: MultiWin and imglib

Post by KenDown »

You can do what you like with this - save it as a library or incorporate directly it in your program, it's not all that big. I have tested it with five windows and 110 successive pictures displayed in all five. It seems to work all right. Notice the extra parameter in PROC_imgInit, PROC_imgExit and PROC_imgPlot; this specifies in the case of the first two the number of windows involved and should be the same number as you feed to PROC_multiwin which sets up the multiple windows. For my five windows this number was 4. In the case of the third procedure, it specifies which window is to receive the image plot. 0 (zero) is the window that appears when you start up BB4W and, if you want to use these routines without multiple windows it is the number you will use as the parameter in all three PROCs.

Apart from that extra parameter, the routines are the same as found in Richard's excellent IMGLIB and all credit must go to him.

Code: Select all

      REM Initialise library:
      DEFPROC_imgInit(dchandles%)
      LOCALT%:DIMT%LOCAL15

      SYS"GetModuleHandle","GDI32.DLL"TOL@imglib%
      SYS"GetProcAddress",L@imglib%,"SetBoundsRect"TO`SetBoundsRect`
      SYS"GetProcAddress",L@imglib%,"GetBoundsRect"TO`GetBoundsRect`
      SYS"GetModuleHandle","USER32.DLL"TOL@imglib%
      SYS"GetProcAddress",L@imglib%,"OffsetRect"TO`OffsetRect`
      SYS"GetProcAddress",L@imglib%,"InvalidateRect"TO`InvalidateRect`
      SYS"LoadLibrary","GDIPLUS.DLL"TOL@imglib%
      IFL@imglib%=0 ERROR100,"Couldn't load GDIPLUS.DLL"
      SYS"GetProcAddress",L@imglib%,"GdiplusStartup"TO`GdiplusStartup`
      SYS"GetProcAddress",L@imglib%,"GdipLoadImageFromFile"TO`GdipLoadImageFromFile`
      SYS"GetProcAddress",L@imglib%,"GdipDrawImageFX"TO`GdipDrawImageFX`
      SYS"GetProcAddress",L@imglib%,"GdipCreateMatrix2"TO`GdipCreateMatrix2`
      SYS"GetProcAddress",L@imglib%,"GdipRotateMatrix"TO`GdipRotateMatrix`
      SYS"GetProcAddress",L@imglib%,"GdipTranslateMatrix"TO`GdipTranslateMatrix`
      SYS"GetProcAddress",L@imglib%,"GdipScaleMatrix"TO`GdipScaleMatrix`
      SYS"GetProcAddress",L@imglib%,"GdipDeleteMatrix"TO`GdipDeleteMatrix`
      SYS"GetProcAddress",L@imglib%,"GdipGetImageHeight"TO`GdipGetImageHeight`
      SYS"GetProcAddress",L@imglib%,"GdipGetImageWidth"TO`GdipGetImageWidth`
      SYS"GetProcAddress",L@imglib%,"GdipCreateFromHDC"TO`GdipCreateFromHDC`
      SYS"GetProcAddress",L@imglib%,"GdipSetInterpolationMode"TO`GdipSetInterpolationMode`
      SYS"GetProcAddress",L@imglib%,"GdipDeleteGraphics"TO`GdipDeleteGraphics`
      SYS"GetProcAddress",L@imglib%,"GdipDisposeImage"TO`GdipDisposeImage`
      SYS"GetProcAddress",L@imglib%,"GdiplusShutdown"TO`GdiplusShutdown`
      SYS"GetProcAddress",L@imglib%,"GdipCreateImageAttributes"TO`GdipCreateImageAttributes`
      SYS"GetProcAddress",L@imglib%,"GdipDisposeImageAttributes"TO`GdipDisposeImageAttributes`
      SYS"GetProcAddress",L@imglib%,"GdipSetImageAttributesColorMatrix"TO`GdipSetImageAttributesColorMatrix`

      !T%=1
      SYS`GdiplusStartup`,^T@imglib%,T%, 0

      DIMhandle%(dchandles%)
      FORhi%=0TOdchandles%
        PROC_selectwin(hi%)
        SYS`GdipCreateFromHDC`,@memhdc%,^handle%(hi%)
        SYS`GdipSetInterpolationMode`,handle%(hi%),3:REM bilinear
      NEXT
      PROC_selectwin(0)
      ENDPROC

      REM Uninitialise library (destroy images)
      DEFPROC_imgExit(dchandles%)
      LOCALP%
      P%=FN_imgPrivate(0)
      WHILEP%
        SYS`GdipDisposeImage`,!P%
        IFP%!12SYS`GdipDisposeImageAttributes`,P%!12
        P%=P%!16
      ENDWHILE
      FORi%=0TOdchandles%
        SYS`GdipDeleteGraphics`,handle%(i%)
      NEXT
      SYS`GdiplusShutdown`,T@imglib%
      SYS"FreeLibrary",L@imglib%
      ENDPROC

      REM Load an image from a file (.bmp, .jpg, .gif, .png and others):
      REM N.B. .gif and .png files may have an alpha (transparency) mask
      DEFFN_imgLoad(img$)
      LOCALI%,T%:DIMI%22,T%LOCAL513:I%=(I%+3)AND-4
      SYS"MultiByteToWideChar",0,0,img$,-1,T%,256
      SYS`GdipLoadImageFromFile`,T%,I%
      IF!I%=0THEN:=0
      SYS`GdipGetImageWidth`,!I%,I%+4
      SYS`GdipGetImageHeight`,!I%,I%+8
      I%!16=FN_imgPrivate(I%)
      =I%

      REM Multiply the image's R, G, B, A values by the specified factors:
      DEFPROC_imgMult(I%,r,g,b,a)
      LOCALC%:DIMC%LOCAL99
      IFI%!12=0SYS`GdipCreateImageAttributes`,I%+12
      C%!0=FN_f4(r):C%!24=FN_f4(g):C%!48=FN_f4(b):C%!72=FN_f4(a)
      SYS`GdipSetImageAttributesColorMatrix`,I%!12,1,1,C%,0,0
      ENDPROC

      REM Plot an image:
      REM I% = pointer to image object
      REM x  = horizontal coordinate of centre of object (BBC BASIC units)
      REM y  = vertical coordinate of centre of object (BBC BASIC units)
      REM s  = horizontal scale (1.0 = original width), negative to flip
      REM t  = vertical scale (1.0 = original height), negative to flip
      REM a  = angle of rotation (degrees, clockwise)

      REM First step is to add the ORIGIN to the x/y coordinates
      REM GdipCreateMatrix2 sets up a matrix for affine transformations
      REM GdipRotateMatrix applies any rotation (angle a) to the matrix
      REM GdipScaleMatrix applies the scale factors s/t
      REM GdipTranslateMatrix moves the image to a stated position
      REM SetBoundsRect turns on boundary accumulation and clears the rectangle
      REM GdipDrawImageFX draws the image after the various changes are applied
      REM GetBoundsRect obtains the current boundary rectangle
      REM OffsetRect moves the rectangle up and to the left to match output bitmap and window contents
      REM InvalidateRect marks the rectangle for redrawing
      REM GdipDeleteMatrix Deletes the matrix M%

      DEFPROC_imgPlot(I%,x,y,s,t,a,hand%)
      LOCALM%,R%:DIMR%LOCAL15
      x+=@vdu.o.x%:y+=@vdu.o.y%
      SYS`GdipCreateMatrix2`,&3F800000,FALSE,FALSE,&3F800000,FN_f4(x/2),FN_f4(@vdu%!212-y/2),^M%
      SYS`GdipRotateMatrix`,M%,FN_f4(a),0
      SYS`GdipScaleMatrix`,M%,FN_f4(s),FN_f4(t),0
      SYS`GdipTranslateMatrix`,M%,FN_f4(-I%!4/2),FN_f4(-I%!8/2),0
      SYS`SetBoundsRect`,@memhdc%,0,5
      SYS`GdipDrawImageFX`,handle%(hand%),!I%,0,M%,0,I%!12,2
      SYS`GetBoundsRect`,@memhdc%,R%,0
      SYS`OffsetRect`,R%,-@ox%,-@oy%
      SYS`InvalidateRect`,@hwnd%,R%,0
      SYS`GdipDeleteMatrix`,M%
      ENDPROC

      DEFFN_imgPrivate(L%)
      PRIVATEP%
      SWAPL%,P%
      =L%

      REM Convert to 4-byte float:
      DEFFN_f4(a#)LOCALp%%:p%%=^a#:IFABSa#<1E-38THEN=FALSE
      =p%%!4ANDNOT&7FFFFFFFOR(p%%!4-&38000000<<3OR!p%%>>29AND7)+(!p%%>>28AND1)
KenDown
Posts: 327
Joined: Wed 04 Apr 2018, 06:36

Re: MultiWin and imglib

Post by KenDown »

Actually using the amended library turned up several issues. In particular, it required that all the windows you need should be created right at the start of the program, which did not suit me at all. I have, therefore, made a couple of small changes. I have also written a sort of "User Guide", which follows the library and which I hope will be useful to anyone wanting to use the library. (Most of the comments also apply to Richard's original IMGLIB.

Code: Select all

      REM Initialise library
      DEFPROC_imgInit(dchandles%)
      LOCALT%:DIMT%LOCAL15
      SYS"GetModuleHandle","GDI32.DLL"TOL@imglib%
      SYS"GetProcAddress",L@imglib%,"SetBoundsRect"TO`SetBoundsRect`
      SYS"GetProcAddress",L@imglib%,"GetBoundsRect"TO`GetBoundsRect`
      SYS"GetModuleHandle","USER32.DLL"TOL@imglib%
      SYS"GetProcAddress",L@imglib%,"OffsetRect"TO`OffsetRect`
      SYS"GetProcAddress",L@imglib%,"InvalidateRect"TO`InvalidateRect`
      SYS"LoadLibrary","GDIPLUS.DLL"TOL@imglib%
      IFL@imglib%=0 ERROR100,"Couldn't load GDIPLUS.DLL"
      SYS"GetProcAddress",L@imglib%,"GdiplusStartup"TO`GdiplusStartup`
      SYS"GetProcAddress",L@imglib%,"GdipLoadImageFromFile"TO`GdipLoadImageFromFile`
      SYS"GetProcAddress",L@imglib%,"GdipDrawImageFX"TO`GdipDrawImageFX`
      SYS"GetProcAddress",L@imglib%,"GdipCreateMatrix2"TO`GdipCreateMatrix2`
      SYS"GetProcAddress",L@imglib%,"GdipRotateMatrix"TO`GdipRotateMatrix`
      SYS"GetProcAddress",L@imglib%,"GdipTranslateMatrix"TO`GdipTranslateMatrix`
      SYS"GetProcAddress",L@imglib%,"GdipScaleMatrix"TO`GdipScaleMatrix`
      SYS"GetProcAddress",L@imglib%,"GdipDeleteMatrix"TO`GdipDeleteMatrix`
      SYS"GetProcAddress",L@imglib%,"GdipGetImageHeight"TO`GdipGetImageHeight`
      SYS"GetProcAddress",L@imglib%,"GdipGetImageWidth"TO`GdipGetImageWidth`
      SYS"GetProcAddress",L@imglib%,"GdipCreateFromHDC"TO`GdipCreateFromHDC`
      SYS"GetProcAddress",L@imglib%,"GdipSetInterpolationMode"TO`GdipSetInterpolationMode`
      SYS"GetProcAddress",L@imglib%,"GdipDeleteGraphics"TO`GdipDeleteGraphics`
      SYS"GetProcAddress",L@imglib%,"GdipDisposeImage"TO`GdipDisposeImage`
      SYS"GetProcAddress",L@imglib%,"GdiplusShutdown"TO`GdiplusShutdown`
      SYS"GetProcAddress",L@imglib%,"GdipCreateImageAttributes"TO`GdipCreateImageAttributes`
      SYS"GetProcAddress",L@imglib%,"GdipDisposeImageAttributes"TO`GdipDisposeImageAttributes`
      SYS"GetProcAddress",L@imglib%,"GdipSetImageAttributesColorMatrix"TO`GdipSetImageAttributesColorMatrix`
      !T%=1
      SYS`GdiplusStartup`,^T@imglib%,T%, 0
      DIMdchandle%(dchandles%)
      PROCsetdc(0)
      ENDPROC
      :
      DEFPROCsetdc(handle%)
      SYS`GdipCreateFromHDC`,@memhdc%,^dchandle%(handle%)
      IFdchandle%(handle%)=0ERROR 101,"Couldn't initialise window for GDIP"
      SYS`GdipSetInterpolationMode`,dchandle%(handle%),3:REM bilinear
      ENDPROC
      :
      REM Returns 0 if picture failed to load
      DEFFN_imgLoad(img$)
      LOCALI%,T%:DIMI%22,T%LOCAL513:I%=(I%+3)AND-4
      SYS"MultiByteToWideChar",0,0,img$,-1,T%,256
      SYS`GdipLoadImageFromFile`,T%,I%
      IF!I%=0THEN:=0
      SYS`GdipGetImageWidth`,!I%,I%+4
      SYS`GdipGetImageHeight`,!I%,I%+8
      I%!16=FN_imgPrivate(I%)
      =I%
      :
      REM Multiply the image's R, G, B, A values by the specified factors:
      DEFPROC_imgMult(I%,r,g,b,a)
      LOCALC%:DIMC%LOCAL99
      IFI%!12=0SYS`GdipCreateImageAttributes`,I%+12
      C%!0=FN_f4(r):C%!24=FN_f4(g):C%!48=FN_f4(b):C%!72=FN_f4(a)
      SYS`GdipSetImageAttributesColorMatrix`,I%!12,1,1,C%,0,0
      ENDPROC
      :
      DEFPROC_imgPlot(I%,x,y,s,t,a,hand%)
      LOCALM%,R%:DIMR%LOCAL15
      x+=@vdu.o.x%:y+=@vdu.o.y%
      SYS`GdipCreateMatrix2`,&3F800000,FALSE,FALSE,&3F800000,FN_f4(x/2),FN_f4(@vdu%!212-y/2),^M%
      SYS`GdipRotateMatrix`,M%,FN_f4(a),0
      SYS`GdipScaleMatrix`,M%,FN_f4(s),FN_f4(t),0
      REM Use the line below to use the centre point of the picture
      REMSYS`GdipTranslateMatrix`,M%,FN_f4(-I%!4/2),FN_f4(-I%!8/2),0
      REM Use the line below to use the top-left corner of the picture
      SYS`GdipTranslateMatrix`,M%,0,0,0
      SYS`SetBoundsRect`,@memhdc%,0,5
      SYS`GdipDrawImageFX`,dchandle%(hand%),!I%,0,M%,0,I%!12,2
      SYS`GetBoundsRect`,@memhdc%,R%,0
      SYS`OffsetRect`,R%,-@ox%,-@oy%
      SYS`InvalidateRect`,@hwnd%,R%,0
      SYS`GdipDeleteMatrix`,M%
      ENDPROC
      :
      DEFFN_imgPrivate(L%)
      PRIVATEP%
      SWAPL%,P%
      =L%
      :
      REM Convert to 4-byte float:
      DEFFN_f4(a#)LOCALp%%:p%%=^a#:IFABSa#<1E-38THEN=FALSE
      =p%%!4ANDNOT&7FFFFFFFOR(p%%!4-&38000000<<3OR!p%%>>29AND7)+(!p%%>>28AND1)
      :
      DEFPROC_imgExit(dchandles%)
      LOCALP%
      P%=FN_imgPrivate(0)
      WHILEP%
        SYS`GdipDisposeImage`,!P%
        IFP%!12SYS`GdipDisposeImageAttributes`,P%!12
        P%=P%!16
      ENDWHILE
      FORi%=0TOdchandles%
        PROCdeleteimghandle(i%)
      NEXT
      SYS`GdiplusShutdown`,T@imglib%
      SYS"FreeLibrary",L@imglib%
      ENDPROC
      :
      DEFPROCdeleteimghandle(i%)
      IFdchandle%(i%)>0SYS`GdipDeleteGraphics`,dchandle%(i%):dchandle%(i%)=0
      ENDPROC
)

This is the documentation for the IMGLIB library written by Richard Russell and modified by Kendall Down so that it will work with multiple windows. The modified library will also work with a single window. The documentation is the work of Kendall Down and any errors are his responsibility.

PROC_imgInit(dchandles%)

This should be called once at the start of your program but *after* MULTIWIN has been installed and initialised. Here we have ten windows being initialised:

INSTALL @lib$+"MULTIWINMOD"
multiwin%=10
PROC_multiwin(multiwin%)
PROC_imgInit(multiwin%)

Notice, however, that with this initial call to PROC_imgInit an array, dchandles%() is set up with ten elements, but only one window is assigned a DChandle - @hwnd%. As each window must be created *before* it can be assigned a DChandle, it is not always convenient to create all your windows at the start of the program. The routine to assign DChandles is therefore separated from the initialisation and must be called separately for each window as it is created.

Here the first window - window 1 - is created, selected and then a DChandle is assigned.

hw1%=FN_createwin(1,"Presenter window",0,0,cordx%(1)-8,cordy%(1)-60,0,&96C00000,0)
PROC_selectwin(1)
PROCsetdc(1)

================

The corollary is that when you close each window you must delete its associated DChandle.

PROC_selectwin(0)
PROC_closewin(7)
PROCdeleteimghandle(7)

Note that it is always a good idea to select window 0 before you close other windows, for if you try to close a window that is your selected window the results are likely to be unfortunate.

When you close your program, however, you should call PROC_imgExit() once, but with the number of windows as your parameter.

PROC_imgExit(multiwin%)

If any DChandles have not been deleted at this stage, they will be closed and deleted, along with various other bits of housekeeping associated with the library.

================

We now come to the heart of the library, loading and displaying an image as well as subjecting it to various manipulations.

FN_imgLoad(img$)

The parameter is the full file name of the picture you wish to load - for example, "F:\Pictures\Petra\Khazneh01.jpg"

The routine returns a value which *must* be checked. If that value is zero it means that the file name was incorrect or for some other reason the picture could not be loaded. Please note that if you attempt to plot an image with a zero handle BB4W will crash disastrously.

The value is an integer with the convenient attribute that you can find the width and height of the image with two simple operations.

pic%=FN_imgLoad(img$)
width%=pic%!4
height%=pic%!8

You can, of course, use your own variable names. I have merely chosen ones that are meaningful.

To actually display a picture you call PROC_imgPlot(I%,x,y,s,t,a,hand%) with the various parameters

I% is the handle returned by FN_imgLoad
x is the horizontal position of the picture (see below)
y is the vertical position of the picture (see below)
s is the horizontal scale to enlarge or reduce the x-axis
t is the vertical scale to enlarge or reduce the y-axis
a is the rotation in degrees. A positive number rotates clockwise, a negative anti-clockwise
hand% is the multiwin number of the window in which the picture is to be displayed

Richard's original library specified the centre point of the picture and displayed it centred on that point. The jpeg routine given in the Help for BB4W uses the top-left point of the picture and displays it across and down from that point. As my program was already set up in that way I found it more convenient to continue to specify the top-left point. I therefore altered the routine to this:

SYS`GdipTranslateMatrix`,M%,0,0,0

If you prefer to use the centre point - which does have advantages when rotating images - use Richard's original line *instead* of my line.

SYS`GdipTranslateMatrix`,M%,FN_f4(-I%!4/2),FN_f4(-I%!8/2),0

DO NOT attempt to have both lines! I'm not sure what the results would be and I am in no hurry to find out. Note that both lines are in the library and you do not need to retype them - just remove the REM from one and put a REM in front of the other.

The horizontal and vertical scale parameters can be positive or negative. A negative number has the effect of flipping the picture on that axis, so -s will flip on the horizontal axis and -t will flip on the vertical axis. Be aware, however, that if you are using my preference for positioning the picture according to the top-left corner, flipping it in any way will affect the position, whereas using the centre of the picture, its position should remain the same.

If you have - say - three windows and you wish to display your picture in each of those windows, you only load the picture once, but then you would call imgPlot three times like this:

PROC_imgPlot(t%,2*x%+lfx%,-2*y%-sl%+lfy%,s,s,angle,1)
PROC_imgPlot(t%,2*x%+lfx%,-2*y%-sl%+lfy%,s,s,angle,2)
PROC_imgPlot(t%,2*x%+lfx%,-2*y%-sl%+lfy%,s,s,angle,3)

To display the picture in the original window (or if you only have one window) it would be:

PROC_imgPlot(t%,2*x%+lfx%,-2*y%-sl%+lfy%,s,s,angle,0)

Note that the plotting routine is extremely fast and with suitable programming you can grab a corner of a picture and rotate it in real time (though obviously a bigger picture will be slower than a small one!)

================

For most purposes the above is all you need to know. However Richard has written a rather clever routine for manipulating your picture in various ways *before* displaying it.

PROC_imgMult(I%,r,g,b,a)

I% is the image handle returned by FN_imgLoad
r is the red values in the picture
g is the green values in the picture
b is the blue values in the picture
a, somewhat confusingly, is not the angle of the picture but its alpha value

The default values for r, g and b are 1. If you set them all to zero you will get a completely black picture. As you go beyond 1 the colours are increasingly washed out, though, annoyingly, any particularly dark colours will remain visible, even though the colours are horribly distorted. You cannot fade from pure black to pure white just by altering the rgb values.

You can write a simple program which loads an image and then starts off with r g b set to 0 and increase them to some value, then decrease them back to 0 again and the picture will change accordingly, from black to full colour and back to black again.

The default value for a is 1. If you set it to zero you will get a completely white picture, which moves through gray and various washed-out colours to full brightness as a approaches 1. Increasing beyond 1 does not seem to affect the picture in any way.

Annoyingly, starting at 1 and decreasing the value of a does not appear to affect the picture, which continues to be displayed as though a was 1. Alpha controls the transparency (or the opacity) of a colour - in this case, of all the colours simultaneously - so once it is set to fully opaque, plotting a fully or partially transparent picture on top makes no discernable difference! If you clear the screen or otherwise get rid of the picture before re-plotting it, the picture will gradually return to white (or clear or transparent).
DDRM

Re: MultiWin and imglib

Post by DDRM »

Can I note that Richard comments that there are "serious flaws" in this description of both Richard's original library, and Kendall's modification of it, though he does not specify them. Please bear that in mind if you use it as guidance.

Best wishes,

D
KenDown
Posts: 327
Joined: Wed 04 Apr 2018, 06:36

Re: MultiWin and imglib

Post by KenDown »

Thanks for pointing that out, David. It would be helpful if Richard would give some clue to these alleged errors, for I am sure that he is right. I can only comment that I am using the modified procedures and so far - touch wood - have not encountered any problems.

As for the flaws in the documentation, the whole issue could have been avoided if Richard had supplied documentation similar to that available in the BB4W Help for the other libraries. Lacking that, I have had to do my poor best and I trust others will find it useful.

There is, however, one other point that Richard makes over on the Discussion Group; imglib consists of two libraries, one for BB4W and one for SDL. They use different methods, but the procedures and functions they contain are identical and provide the same facilities. It must be emphasised that my modifications are for the BB4W library *only*. I do not use SDL and will not be attempting to alter the SDL imglib. I suspect that the method by which I have altered the library to make it suitable for multiple windows can be applied to the SDL imglib, but I leave that as an exercise for others.

Of course the ideal would be for Richard to release his own modified, multi-win compatible, libraries, with documentation. My poor efforts can then be consigned to the dustbin of history!