Subversion Repositories filter_foundry

Rev

Rev 146 | Rev 159 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

  1. /*
  2.     This file is part of "Filter Foundry", a filter plugin for Adobe Photoshop
  3.     Copyright (C) 2003-9 Toby Thain, toby@telegraphics.com.au
  4.  
  5.     This program is free software; you can redistribute it and/or modify
  6.     it under the terms of the GNU General Public License as published by
  7.     the Free Software Foundation; either version 2 of the License, or
  8.     (at your option) any later version.
  9.  
  10.     This program is distributed in the hope that it will be useful,
  11.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.     GNU General Public License for more details.
  14.  
  15.     You should have received a copy of the GNU General Public License
  16.     along with this program; if not, write to the Free Software
  17.     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  18. */
  19.  
  20. //#include <stdio.h>
  21. //#include <sound.h>
  22.  
  23. #include "ff.h"
  24.  
  25. #include "node.h"
  26. #include "y.tab.h"
  27. #include "scripting.h"
  28.  
  29. struct node *tree[4];
  30. char *err[4];
  31. int errpos[4],errstart[4],nplanes,cnvused,chunksize,toprow;
  32. value_type slider[8],cell[NUM_CELLS],map[4][0x100];
  33. char *expr[4];
  34. // long maxSpace;
  35. globals_t *gdata;
  36. FilterRecordPtr gpb;
  37.  
  38. #ifdef MAC_ENV
  39.         #define hDllInstance NULL /* fake this Windows-only global */
  40. #endif
  41.  
  42. extern struct sym_rec predefs[];
  43. extern int nplanes,varused[];
  44.  
  45. int checkandinitparams(Handle params);
  46.  
  47. // MPW MrC requires prototype
  48. DLLEXPORT MACPASCAL
  49. void ENTRYPOINT(short selector,FilterRecordPtr pb,intptr_t *data,short *result);
  50.  
  51. DLLEXPORT MACPASCAL
  52. void ENTRYPOINT(short selector, FilterRecordPtr pb, intptr_t *data, short *result){
  53.         static Boolean wantdialog = false;
  54.         OSErr e = noErr;
  55.         char *reason;
  56.  
  57. #ifdef WIN_ENV
  58.         // For Windows, we use an activation context to enforce that our Manifest resource will
  59.         // be used. This allows us to use Visual Styles, even if the host application does not
  60.         // support it.
  61.         HANDLE hActCtx;
  62.         ACTCTX actCtx;
  63.         ULONG_PTR cookie;
  64.         BOOL activationContextUsed = FALSE;
  65.  
  66.         ZeroMemory(&actCtx, sizeof(actCtx));
  67.         actCtx.cbSize = sizeof(actCtx);
  68.         actCtx.hModule = hDllInstance;
  69.         actCtx.lpResourceName = MAKEINTRESOURCE(1); // ID of manifest resource
  70.         actCtx.dwFlags = ACTCTX_FLAG_HMODULE_VALID | ACTCTX_FLAG_RESOURCE_NAME_VALID;
  71.  
  72.         hActCtx = CreateActCtx(&actCtx);
  73.         if (hActCtx != INVALID_HANDLE_VALUE) {
  74.                 ActivateActCtx(hActCtx, &cookie);
  75.                 activationContextUsed = TRUE;
  76.         }
  77. #endif
  78.  
  79.         if(selector != filterSelectorAbout && !*data){
  80.                 BufferID tempId;
  81.                 if( (*result = PS_BUFFER_ALLOC(sizeof(globals_t), &tempId)) )
  82.                         return;
  83.                 *data = (intptr_t)PS_BUFFER_LOCK(tempId, true);
  84.                 gdata = (globals_t*)*data;
  85.                 gdata->standalone = gdata->parmloaded = false;
  86.         }else
  87.                 gdata = (globals_t*)*data;
  88.  
  89.         EnterCodeResource();
  90.  
  91.         gpb = pb;
  92.  
  93.         nplanes = MIN(pb->planes,4);
  94.  
  95.         switch (selector){
  96.         case filterSelectorAbout:
  97.                 if(gdata && !gdata->parmloaded)
  98.                         gdata->standalone = gdata->parmloaded = readPARMresource(hDllInstance,&reason,1);
  99.                 DoAbout((AboutRecordPtr)pb);
  100.                 break;
  101.         case filterSelectorParameters:
  102.                 wantdialog = true;
  103.                 break;
  104.         case filterSelectorPrepare:
  105.                 DoPrepare(pb);
  106.                 init_symtab(predefs); // ready for parser calls
  107.                 init_trigtab();
  108.                 break;
  109.         case filterSelectorStart:
  110.                 /* initialise the parameter handle that Photoshop keeps for us */
  111.                 if(!pb->parameters)
  112.                         pb->parameters = PINEWHANDLE(0);
  113.  
  114.                 wantdialog |= checkandinitparams(pb->parameters);
  115.  
  116.                 /* wantdialog = false means that we never got a Parameters call, so we're not supposed to ask user */
  117.                 if( wantdialog && (!gdata->standalone || gdata->parm.popDialog) ){
  118.                         if( maindialog(pb) ){
  119.                                 /* update stored parameters from new user settings */
  120.                                 saveparams(pb->parameters);
  121.                         }else
  122.                                 e = userCanceledErr;
  123.                 }
  124.                 wantdialog = false;
  125.  
  126.                 if(!e){
  127.                         if(setup(pb)){
  128.                                 DoStart(pb);
  129.                         }else{
  130.                                 SYSBEEP(1);
  131.                                 e = filterBadParameters;
  132.                         }
  133.                 }
  134.                 break;
  135.         case filterSelectorContinue:
  136.                 e = DoContinue(pb);
  137.                 break;
  138.         case filterSelectorFinish:
  139.                 DoFinish(pb);
  140.                 break;
  141.         default:
  142.                 e = filterBadParameters;
  143.         }
  144.  
  145.         *result = e;
  146.  
  147.         ExitCodeResource();
  148.  
  149. #ifdef WIN_ENV
  150.         if (activationContextUsed) {
  151.                 DeactivateActCtx(0, cookie);
  152.                 ReleaseActCtx(hActCtx);
  153.         }
  154. #endif
  155. }
  156.  
  157. int checkandinitparams(Handle params){
  158.         char *reasonstr,*reason;
  159.         int i,f,showdialog;
  160.  
  161.         if( (f = !(params && readparams(params,false,&reasonstr))) ){
  162.                 /* either the parameter handle was uninitialised,
  163.                    or the parameter data couldn't be read; set default values */
  164.  
  165.                 // see if saved parameters exist
  166.                 gdata->standalone = gdata->parmloaded = readPARMresource(hDllInstance,&reason,1);
  167.  
  168.                 if(!gdata->standalone){
  169.                         // no saved settings (not standalone)
  170.                         for(i = 0; i < 8; ++i)
  171.                                 slider[i] = i*10+100;
  172.                         for(i = 0; i < 4; ++i)
  173.                                 if(expr[i])
  174.                                         free(expr[i]);
  175.                         if(gpb->imageMode == plugInModeRGBColor){
  176.                                 expr[0] = my_strdup("r");
  177.                                 expr[1] = my_strdup("g");
  178.                                 expr[2] = my_strdup("b");
  179.                                 expr[3] = my_strdup("a");
  180.                         }else{
  181.                                 expr[0] = my_strdup("c");
  182.                                 expr[1] = my_strdup("c");
  183.                                 expr[2] = my_strdup("c");
  184.                                 expr[3] = my_strdup("c");
  185.                         }
  186.                 }
  187.         }
  188.  
  189.         // let scripting system change parameters, if we're scripted;
  190.         // user may want to force display of dialog during scripting playback
  191.         showdialog = ReadScriptParamsOnRead();
  192.  
  193.         saveparams(params);
  194.         return f || showdialog;
  195. }
  196.  
  197. void DoPrepare(FilterRecordPtr pb){
  198.         int i;
  199.  
  200.         for(i = 4; i--;){
  201.                 if(expr[i]||tree[i]) DBG("expr[] or tree[] non-NULL in Prepare!");
  202.                 expr[i] = NULL;
  203.                 tree[i] = NULL;
  204.         }
  205.  
  206.         // Commented out by DM, 18 Dec 2018:
  207.         // This code did not work on systems with 8 GB RAM:
  208.         /*
  209.         long space = (pb->maxSpace*9)/10; // don't ask for more than 90% of available memory
  210.  
  211.         maxSpace = 512L<<10; // this is a wild guess, actually
  212.         if(maxSpace > space)
  213.                 maxSpace = space;
  214.         pb->maxSpace = maxSpace;
  215.         */
  216.  
  217.         // New variant:
  218.         // TODO: Programmatically test if host supports pb->maxSpace64, and if it does so, use this value instead.
  219.         pb->maxSpace = ((double)pb->maxSpace/10)*9; // don't ask for more than 90% of available memory
  220. }
  221.  
  222. void RequestNext(FilterRecordPtr pb,long toprow){
  223.         /* Request next block of the image */
  224.  
  225.         pb->inLoPlane = pb->outLoPlane = 0;
  226.         pb->inHiPlane = pb->outHiPlane = nplanes-1;
  227.  
  228.         // if any of the formulae involve random access to image pixels,
  229.         // ask for the entire image
  230.         if(needall){
  231.                 SETRECT(pb->inRect,0,0,pb->imageSize.h,pb->imageSize.v);
  232.         }else{
  233.                 // otherwise, process the filtered area, by chunksize parts
  234.                 pb->inRect.left = pb->filterRect.left;
  235.                 pb->inRect.right = pb->filterRect.right;
  236.                 pb->inRect.top = toprow;
  237.                 pb->inRect.bottom = MIN(toprow + chunksize,pb->filterRect.bottom);
  238.  
  239.                 if(cnvused){
  240.                         // cnv() needs one extra pixel in each direction
  241.                         if(pb->inRect.left > 0)
  242.                                 --pb->inRect.left;
  243.                         if(pb->inRect.right < pb->imageSize.h)
  244.                                 ++pb->inRect.right;
  245.                         if(pb->inRect.top > 0)
  246.                                 --pb->inRect.top;
  247.                         if(pb->inRect.bottom < pb->imageSize.v)
  248.                                 ++pb->inRect.bottom;
  249.                 }
  250.         }
  251.         pb->outRect = pb->filterRect;
  252. /*
  253. {char s[0x100];sprintf(s,"RequestNext needall=%d inRect=(%d,%d,%d,%d) filterRect=(%d,%d,%d,%d)",
  254.         needall,
  255.         pb->inRect.left,pb->inRect.top,pb->inRect.right,pb->inRect.bottom,
  256.         pb->filterRect.left,pb->filterRect.top,pb->filterRect.right,pb->filterRect.bottom);dbg(s);}
  257. */
  258. }
  259.  
  260. void DoStart(FilterRecordPtr pb){
  261. //dbg("DoStart");
  262.         /* if src() or rad() functions are used, random access to the image data is required,
  263.            so we must request the entire image in a single chunk. */
  264.         chunksize = needall ? (pb->filterRect.bottom - pb->filterRect.top) : CHUNK_ROWS;
  265.         toprow = pb->filterRect.top;
  266.         RequestNext(pb,toprow);
  267. }
  268.  
  269. OSErr DoContinue(FilterRecordPtr pb){
  270.         OSErr e = noErr;
  271.         Rect fr;
  272.         long outoffset;
  273.  
  274.         if(needall)
  275.                 fr = pb->filterRect;  // filter whole selection at once
  276.         else if(cnvused){
  277.                 // we've requested one pixel extra all around
  278.                 // (see RequestNext()), just for access purposes. But filter
  279.                 // original selection only.
  280.                 fr.left = pb->filterRect.left;
  281.                 fr.right = pb->filterRect.right;
  282.                 fr.top = toprow;
  283.                 fr.bottom = MIN(toprow + chunksize,pb->filterRect.bottom);
  284.         }else  // filter whatever portion we've been given
  285.                 fr = pb->inRect;
  286.  
  287.         outoffset = (long)pb->outRowBytes*(fr.top - pb->outRect.top)
  288.                                 + (long)nplanes*(fr.left - pb->outRect.left);
  289.  
  290.         if(!(e = process_scaled(pb, true, &fr, &fr,
  291.                                 (Ptr)pb->outData+outoffset, pb->outRowBytes, 1.)))
  292.         {
  293.                 toprow += chunksize;
  294.                 if(toprow < pb->filterRect.bottom)
  295.                         RequestNext(pb,toprow);
  296.                 else{
  297.                         SETRECT(pb->inRect,0,0,0,0);
  298.                         pb->outRect = pb->maskRect = pb->inRect;
  299.                 }
  300.         }
  301.         return e;
  302. }
  303.  
  304. void DoFinish(FilterRecordPtr pb){
  305.         int i;
  306.  
  307.         WriteScriptParamsOnRead();
  308.  
  309.         for(i = 4; i--;){
  310.                 freetree(tree[i]);
  311.                 if(expr[i]) free(expr[i]);
  312.         }
  313. }
  314.