home *** CD-ROM | disk | FTP | other *** search
- Programming information for .EFX files (written 29/3/96 for Photogenics 2)
- ==========================================================================
-
- Copyright © Almathera Systems Ltd 1994-6. All Rights Reserved.
-
- All programming examples and documentation is proprietary
- and may only be used to create .EFX files for use
- with the Photogenics program.
-
- Any other use of this documentation and source is strictly
- prohibited. It may not be reproduced or copied without
- written authorisation from Almathera.
-
- Permission is hereby given to allow free or commercial
- distribution of .EFX files for Photogenics written using
- this code. Almathera encourages the free distribution
- of .EFX files for use with Photogenics.
-
- (ie. If you write an EFX, you can do whatever you want with
- it!)
-
- .EFX files may not be distributed for use with any other
- Amiga software.
-
- (ie. You can't reverse engineer our system and build your
- own image-processor around our files)
-
- ---------------------------------------------------
- If you have any problems developing add-on files for
- Photogenics, then please contact:
-
- Jolyon Ralph on (UK) 0181 687 0040 during office hours, or email to:
-
- jralph@cix.compulink.co.uk
-
- We'll be happy to help out where we can.
-
- If you've come up with an excellent idea for a loader but
- can't program it yourself, then let us know and we might
- have a go ourselves, or call our BBS, someone may
- have already written one!
-
- -----------------------------------------------------
-
- What is an .EFX file? - Jolyon Ralph (29/3/96)
- ==============================================
-
- EFX files are add-in files for Photogenics 2 that allow various image processing type
- functions to be applied to the image.
-
- An .EFX file, just like the .GIO files, is a standard system disk-based library file. You can
- create .EFX files with any programming language that can create a library (assembler, C, C++, Modula II, etc.).
- The examples provided were written using SAS V6.51 and Hisoft Devpac, but any C compiler
- and Assembler should be capable of compiling them with little or no alteration to the sourcecode.
-
- Using libraries carries little overhead and has the major advantage
- that the Amiga operating system automatically handles ram cacheing
- of libraries and flushing libraries when ram is low without us having
- to worry about that.
-
- Each library follows a standard function layout (as shown
- in the efx.fd file:)
-
- * "efx.library"
- ##base __EfxBase
- ##bias 30
- ##public
- EfxInfo()()
- EfxPreRender(giodata)(a0)
- EfxRender(giodata)(a0)
- EfxPrefs(giodata)(a0)
- EfxAbout(giodata)(a0)
- ##end
-
- First a description of the functions:
-
-
- EfxInfo
- =======
-
- flags = EfxInfo(void)
- d0.L
-
- This is required by all .efx files. It returns flags depending on
- the capabilities of the effect. The flags are (defined in efx.h)
-
- EFX_24BIT -
- The effect will operate on 24-bit images (currently the only
- type supported in Photogenics 2.0)
-
- EFX_8GREY -
- The effect will operate on 8-bit greyscale images
- (which currently means paintlayer - but will also include standard 8-bit buffers
- in future versions)
-
- EFX_1BIT
- The effect will operate on 1-bit monochrome images
- (not implemented)
-
- EFX_INDEXED
- The effect will operate on 256 (or less) palette based
- index colour images (not implemented)
-
- EFX_NOOPTIONS -
- No options page is available for this effect.
-
- EFX_USESSECOND -
- Another image needs to be selected as the secondary to use
- this effect.
-
- EFX_NEEDSUNDO -
- The effect needs an undo buffer in order to operate
- correctly. This is essential to avoid 'feedback' situations. You will need
- to use this if it is not possible to process a pixel at a time (for example if your
- effect overwrites other pixels while processing).
-
- If your effect works on a pixel at a time, then you don't need this flag, and the effect can
- be executed even if the undo buffer is not present.
-
- EFX_PAINTLAYER -
- The effect operates by altering the image paintlayer rather
- than affecting the
-
- EFX_FULLSCREENONLY -
- The effect cannot operate on a window. In this case, the effect processes every
- pixel of the image.
-
- Normally, the window to be processed would be passed in
-
- giodata->WindX
- giodata->WindY
- giodata->WindWidth
- giodata->WindHeight
-
- and only those pixels should be altered. If EFX_FULLSCREENONLY is set, the
- program knows that the whole picture, from 0,0 to giodata->Width-1, giodata->Height-1
- is processed, regardless of the window position.
-
- Obviously you should only use EFX_FULLSCREENONLY when it is not practical or sensible to
- allow an effect within a region.
-
-
- EfxPreRender
- ============
- This currently does nothing.
- Please return zero for future compatibility.
-
- EfxRender
- =========
- This is the actual effect routine. It's pretty straight forward, and very similar to
- programming for the GIO modules
-
- Here is some example code from Negative.efx
-
- __asm ULONG EfxRender(register __a0 struct GIOData *giodata)
- {
- UBYTE r,g,b;
- int x,y;
-
- SetProgress("Inverting image...",0);
-
- switch(giodata->Depth)
- {
-
- case 24:
-
- for(y=giodata->WindY;y<giodata->WindY+giodata->WindHeight;y++)
- {
- if(!(y%64))
- {
-
- /* SetProgress returns 1 if it wasn't cancelled! */
-
- if(SetProgress(0,(y-giodata->WindY)*100/giodata->WindHeight)!=1)
- {
- giodata->Error = GIO_ABORTED;
- goto err;
- }
- }
- for(x=giodata->WindX;x<giodata->WindX+giodata->WindWidth;x++)
- {
- GetSrcPixel(giodata,x,y,&r,&g,&b);
- PutDestPixel(giodata,x,y,255-r,255-g,255-b);
- }
- }
- break;
-
- case 8:
- for(y=giodata->WindY;y<giodata->WindY+giodata->WindHeight;y++)
- {
- if(!(y%64))
- {
- if(SetProgress(0,(y-giodata->WindY)*100/giodata->WindHeight)!=1)
- {
- giodata->Error = GIO_ABORTED;
- goto err;
- }
- }
- for(x=giodata->WindX;x<giodata->WindX+giodata->WindWidth;x++)
- {
- r=GetSrcPixel8(giodata,x,y);
- PutDestPixel8(giodata,x,y,255-r);
- }
- }
- break;
- }
- giodata->Error = GIO_OK;
- err:
- return(giodata->Error);
- }
-
- Note the important factors.
-
- 1. Only the pixels within the window region are altered.
-
- 2. Unlike GIO's, we read a pixel at a time with the GetSrcPixel() function.
-
- Normally this reads from the undo buffer, so however much you alter the destination GetSrcPixel
- will return the original pixel values. If Undo is disabled within Photogenics, or there is not
- enough ram to run an undo buffer, then the Src and Destination buffers are one and the same, meaning
- you can't read the original colour of pixel (x,y) if you've just written over it. If your
- effect can't work with that, make sure you set the EFX_NEEDSUNDO flag.
-
- 3. Once we have processed the values, we use PutDestPixel() to return the pixels to the
- destination image.
-
- 4. With the 8-bit data, we use GetSrcPixel8 and PutDestPixel8 to get and put a byte of data at a time.
-
-
- Other calls you'll need to know about:
-
- Reading each pixel with GetSrcPixel isn't the fastest way to access data.
- The Negative code above would be a lot faster if we used the following...
-
- UBYTE *peeker,*poker;
-
- case 24:
-
- for(y=giodata->WindY;y<giodata->WindY+giodata->WindHeight;y++)
- {
- if(!(y%64))
- {
-
- /* SetProgress returns 1 if it wasn't cancelled! */
-
- if(SetProgress(0,(y-giodata->WindY)*100/giodata->WindHeight)!=1)
- {
- giodata->Error = GIO_ABORTED;
- goto err;
- }
- }
-
- peeker = GetSrcLine(giodata,y | PGVM_READONLY);
- poker = GetDestLine(giodata,y | PGVM_WRITEONLY);
-
- if(peeker && poker)
- {
- peeker+=giodata->WindX*3;
- poker+=giodata->WindX*3;
- for(x=0;x<(giodata->WindWidth*3);x++)
- {
- *poker++= 255-(*peeker++);
- }
- }
- if(peeker) ReleaseSrcLine(giodata,y | PGVM_READONLY);
- if(poker) ReleaseDestLine(giodata,y | PGVM_WRITEONLY);
- }
- break;
-
- This, although a little less obvious, does the same. If you've looked at the GIO devdocs you'll
- recognise the GetLine/ReleaseLine stuff.
-
- GetSrcLine(giodata,y) returns the address of the line of 24-bit data y.
-
- The y value is ORed with a flag:
-
- PGVM_READONLY - I only want to read from the data you give me.
- PGVM_WRITEONLY - I only want to write to the data you give me.
-
- If you want to read and write to the data (can't see when you'd need that, unless you
- want to read from the destination to get feedback effects) then leave the flag off.
-
- The reason for the flags is to speed up virtual memory access when using Virtual Image. With
- READONLY the data isn't written back to disk when you've finished with it, with WRITEONLY
- the data isn't read, but a blank line supplied to you.
-
- If you ignore the flags your code should still work, but it will be slower when working with
- virtual image as it will do unnecessary reads and writes.
-
- Once you've finished accessing the data you MUST use ReleaseSrcLine or ReleaseDestLine to
- free the data (and write it back to disk in the case of virtual images).
-
- Note: all this is handled for you with GetSrcPixel() & PutDestPixel() and they even
- cache lines for you.
-
- You can GetxxxLine multiple lines at a time, although it's not a wise idea to GetxxxLine every line
- in the image at the same time!!!!!
-
- GetSrcPixelAA(giodata,x,y,&r,&g,&b):
-
- Another function, not shown in the examples, is the GetSrcPixelAA() function. This gets an
- anti-aliased pixel from a virtual image 16 times larger in each dimension than your picture.
-
- To use this, simply scale your x and y values by 16 (<<4) and call GetSrcPixelAA().
-
- If you're calculating something like a wave or 3d perspective effect which returns a pixel
- position, multiplying by 16 and then using the AA routine will provide a much better image
- than you'd normally get. The Wave and Perspective effects use this code, and the Warper tool
- has been updated in Photogenics to work on the same principal.
-
-
- Image Previews:
-
- Previous versions of Photogenics didn't allow you to do anything clever with requesters for
- previews. AS Photogenics can run in so many different screenmodes, and it is not legal for you
- to change the photogenics screen palette, this has proved dificult.
-
- We've now circumvented the problem by adding a function to allow preview images to be written
- directly into your rastport.
-
- This assumes
-
- a) your source data is in 24-bit RGB format.
-
- b) your rastport is in a window on the Photogenics screen :-)
-
- The balance.efx code provided shows an example of opening a gadtools window with sliders, and
- a realtime updated preview.
-
- preview = CreatePreviewImage(giodata,64,64,0);
- is called to create a preview image 64 pixels by 64 pixels in size.
-
- We then allocate a block of memory 64x64x3 bytes in size to store a copy of the data.
-
- In the preview_balance routine we take a pixel at a time from the preview image,
- apply the effect (in this case the colour balance) to it, and place it in the copy of preview.
-
- The DrawPreviewImage(giodata,rastport,data,x,y,width,height) routine then
- draws the preview into the rastport.
-
- You don't need to have created the data with CreatePreviewImage in order to use DrawPreviewImage, you
- can allocate your own memory and send it to DrawPreviewImage, as long as you send RGB data with
- three bytes per pixel.
-
- The routine will draw the image into your rastport using the best method available for the
- screenmode. CyberGraphics screens will have the data transfered as 24-bit directly, 256 colour modes
- will use an ordered dither to maximise quality from the 256 colour fixed palette, Ham8 will use our
- 18-bit colour mode, etc. If new display modes are added to photogenics, the DrawPreviewImage
- routine will be updated to take these into account.
-
- Remember to free the preview with FreePreviewImage(giodata) when you've finished.
-
-
- EfxPrefs
- ========
- This is for preferences that you don't want requested every time. In general we don't use this
- much, but if you have options that aren't likely to be changed very often, then put the requester
- for them in here.
-
- EfxAbout
- ========
- This routine will bring up the about requester when information is selected for your GIO. Put
- your credits, instructions or whatever in here..
-
-
- Arexx...
- --------
- If your effect takes parameters you'll need to support arexx. See the balance.efx code for
- an example of how to do this.
-
- A string is passed to you in giodata->ArexxString. You need to parse the parameters from this
- string, so if you have two values you'll get a string like..
-
- "150 190"
-
- I'll leave how to split this up as an exercise for the reader, but if you're really lazy
- you can use our ParseRexx function (make sure you've got the pgsrexx_pragmas included and
- you've included the
-
- #define PgsrexxBase giodata->PgsrexxBase
-
- definition or you won't get at any of our library calls.
- (we use macros to reference most of the library bases off the giodata structure, this
- removes the need to re-open libraries, and cuts down the code size).
-
- Here's the code:
-
- LONG pointers[] = {0,0,0};
-
- ...
-
- if((giodata->ArexxString) && (PgsrexxBase)) /* do we have a string? Do we have arexx? */
- {
- LONG array[] = {3, (LONG) pointers,
- PARSETYPE_INT,-255,255,
- PARSETYPE_INT,-255,255,
- PARSETYPE_INT,-255,255};
-
- if(giodata->ArexxError = ParseTemplate(giodata->ArexxString,array))
- {
- giodata->Error = GIO_AREXXERROR;
- return(giodata->Error);
- }
-
- rval=pointers[0];
- gval=pointers[1];
- bval=pointers[2];
-
-
-
- ParseTemplate is pretty simple... There are four data types you can detect:
-
- PARSETYPE_INT,min,max, return a number between min and max.
-
- PARSETYPE_STRING, return a string
-
- PARSETYPE_ENUM,"OPTIONA","OPTIONB","OPTIONC","OPTIOND",0
-
- return a number for the string which matches the given options.
- eg if you passed OPTIONC it would return 2.
-
- PARSETYPE_REST, return the rest of the string.
-
-
- Note important:
-
- PARSETYPE_STRING copies the string into space you've already allocated and set the
- pointer to in the array you pass.
-
- PARSETYPE_REST doesn't, it just returns a pointer to rest of the string.
-
-
-
-
-