text: /***********************************************************************
  **
  **  REBOL [R3] Language Interpreter and Run-time Environment
  **
  **  Copyright 2012 REBOL Technologies
  **  REBOL is a trademark of REBOL Technologies
  **
  **  Licensed under the Apache License, Version 2.0 (the "License");
  **  you may not use this file except in compliance with the License.
  **  You may obtain a copy of the License at
  **
  **  http://www.apache.org/licenses/LICENSE-2.0
  **
  **  Unless required by applicable law or agreed to in writing, software
  **  distributed under the License is distributed on an "AS IS" BASIS,
  **  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  **  See the License for the specific language governing permissions and
  **  limitations under the License.
  **
  ************************************************************************
  **
  **  Title: Effect Dialect Backend
  **  Author: Cyphre, Carl
  **  Purpose: Evaluates EFFECT commands; calls graphics functions.
  **
  ************************************************************************
  **
  **  NOTE to PROGRAMMERS:
  **
  **    1. Keep code clear and simple.
  **    2. Document unusual code, reasoning, or gotchas.
  **    3. Use same style for code, vars, indent(4), comments, etc.
  **    4. Keep in mind Linux, OS X, BSD, big/little endian CPUs.
  **    5. Test everything, then test it again.
  **
  ***********************************************************************/
  
  #include <stdlib.h>
  
  #include "reb-host.h"
  ///#include "reb-series.h"
  ///#include "reb-gob.h"
  #include "host-lib.h"
  #include "reb-types.h"
  #include "reb-value.h"
  #include "reb-dialect.h"
  #include "words-effect.h"	// Auto-generated by gen-effect-words.reb
  #include "rebol-lib.h"
  
  #include "agg-effects.h"
  
  //#define AGGC ((agg_graphics*)context)
  
  #define ARG_LOGIC(n)	VAL_LOGIC(arg+n)
  #define ARG_INTEGER(n)	VAL_INT32(arg+n)
  #define ARG_STRING(n)	VAL_STRING(arg+n)
  #define ARG_PAIR(n)		VAL_PAIR(arg+n)
  #define ARG_DECIMAL(n)	VAL_DECIMAL(arg+n)
  #define ARG_TUPLE(n)	VAL_TUPLE(arg+n)
  #define ARG_WORD(n)		VAL_WORD(arg+n)
  
  #define ARG_OBJECT(n)	VAL_SERIES(arg+n)  // temp
  #define ARG_IMAGE(n)	VAL_SERIES(arg+n)  // temp
  #define ARG_BLOCK(n)	VAL_SERIES(arg+n)
  
  #define ARG_OPT_IMAGE(n) (IS_IMAGE(arg+n)? ARG_IMAGE(n) : NULL)
  
  #define ARG_WORDS(n,s,e) ((ARG_WORD(n)>=s && ARG_WORD(n)<=e) ? ARG_WORD(n)-s : 0)
  
  
  
  /***********************************************************************
  **
  */	REBINT Effect_Gob(void *effects, REBSER *block)
  /*
  **		Handles all commands for the EFFECT dialect as specified
  **		in the system/dialects/effect object.
  **
  **		This function calls the REBOL_Dialect interpreter to
  **		parse the dialect and build and return the command number
  **		(the index offset in the draw object above) and a block
  **		of arguments. (For now, just a REBOL block, but this could
  **		be changed to isolate it from changes in REBOL's internals).
  **
  **		Each arg will be of the specified datatype (given in the
  **		dialect) or NONE when no argument of that type was given
  **		and this code must determine the proper default value.
  **
  **		If the cmd result is zero, then it is either the end of
  **		the block, or an error has occurred. If the error value
  **		is non-zero, then it was an error.
  **
  ***********************************************************************/
  {
  //	REBSER *block;
  	REBCNT index = 0;
  	REBINT cmd;
  	REBSER *args = 0;
  	REBVAL *arg;
  	REBCNT nargs;
  
  	//default values
  	REBYTE def_color1[4] = {0,0,0,0};
  	REBYTE def_color2[4] = {255,255,255,0};
  	REBPAR def_pair = {1,0};
  
  	do {
  		cmd = Reb_Dialect(DIALECTS_EFFECT, block, &index, &args);
  
  		if (cmd == 0) return 0;
  		if (cmd < 0) {
  //			Reb_Print("ERROR: %d, Index %d", -cmd, index);
  			return -((REBINT)index+1);
  		}
  //		else
  //			Reb_Print("EFFECT: Cmd %d, Index %d, Args %m", cmd, index, args);
  
  		arg = BLK_HEAD(args);
  		nargs = SERIES_TAIL(args);
  //		Reb_Print("Number of args: %d", nargs);
  
  		switch (cmd) {
  
  		case EW_ADD:
  			FX_Add(effects, ARG_OPT_IMAGE(0), ARG_OPT_IMAGE(1));
  			break;
  		case EW_ALPHAMUL:
  			if (IS_IMAGE(arg))
  				FX_Alphamul(effects, ARG_IMAGE(0), IS_NONE(arg+1) ? 127 : ARG_INTEGER(1));
  			break;
  		case EW_ASPECT:
  			{
  				REBINT type = 1, mode = 2;
  
  				if (ARG_WORD(0) == EW_RESAMPLE){
  						type = 2;
  						mode = 1;
  				}
  
  				FX_Fit(effects,ARG_OPT_IMAGE(0), ARG_WORDS(type,EW_NEAREST,EW_GAUSSIAN), ARG_WORD(mode) == EW_RESAMPLE, IS_NONE(arg+3) ? 1.0 : ARG_DECIMAL(3), TRUE);
  			}
  			break;
  		case EW_BLUR:
  //			FX_Blur(effects, ARG_OPT_IMAGE(0));
  			{
  				REBDEC filter[9] = {0, 1, 0, 1, 1, 1, 0, 1, 0};
  				FX_Convolve(effects, ARG_OPT_IMAGE(0),filter , 5.0, 0, FALSE);
  			}
  			break;
  		case EW_COLORIFY:
  			FX_Colorify(effects, IS_NONE(arg+1) ? def_color2 : ARG_TUPLE(1) , IS_NONE(arg+2) ? 255 : max(0, min(255,ARG_INTEGER(2))), ARG_OPT_IMAGE(0));
  			break;
  		case EW_COLORIZE:
  			FX_Colorize(effects, IS_NONE(arg+1) ? def_color2 : ARG_TUPLE(1) , ARG_OPT_IMAGE(0));
  			break;
  		case EW_CONTRAST:
  			FX_Contrast(effects, IS_NONE(arg+1) ? 127 : ARG_INTEGER(1), ARG_OPT_IMAGE(0));
  			break;
  		case EW_CONVOLVE:
  			//[image! block! decimal! decimal! logic!]
  			if (IS_BLOCK(arg+1)) {
  				REBDEC filter[9];
  				REBSER* mtx = (REBSER*)ARG_BLOCK(1);
  				REBVAL* slot = BLK_HEAD(mtx);
  				REBCNT len = SERIES_TAIL(mtx) ,i, num = 0;
  
  				for (i = 0;i<len;i++){
  					if (IS_DECIMAL(slot+i))
  						filter[i] = VAL_DECIMAL(slot+i);
  					else if (IS_INTEGER(slot+i))
  						filter[i] = VAL_INT32(slot+i);
  					else
  						return -cmd;
  					num++;
  				}
  
  				if (num != 9) return -cmd;
  
  				FX_Convolve(effects, ARG_OPT_IMAGE(0),filter , ARG_DECIMAL(2), ARG_INTEGER(3), ARG_LOGIC(4));
  			}
  			break;
  		case EW_CROP:
  			FX_Crop(effects,ARG_OPT_IMAGE(0), IS_NONE(arg+1) ? 0 : &ARG_PAIR(1), IS_NONE(arg+2) ? 0 : &ARG_PAIR(2));
  			break;
  		case EW_DIFFERENCE:
  			FX_Difference(effects, IS_NONE(arg+2) ? def_color2 : ARG_TUPLE(2), ARG_OPT_IMAGE(0), ARG_OPT_IMAGE(1), (IS_NONE(arg+2)) ? 1 : 0);
  			break;
  
  		case EW_EMBOSS:
  			{
  				REBDEC filter[9] = {-1, 0, 1, -2, 0, 2, -1, 0, 1};
  				FX_Convolve(effects, ARG_OPT_IMAGE(0),filter , 6.0, 127, FALSE);
  			}
  			break;
  
  		case EW_EXTEND:
  			FX_Extend(effects,ARG_OPT_IMAGE(0), IS_NONE(arg+1) ? 0 : &ARG_PAIR(1), IS_NONE(arg+2) ? 0 : &ARG_PAIR(2));
  			break;
  
  		case EW_FIT:
  			if (IS_IMAGE(arg)){
  				REBINT type = 1, mode = 2;
  				if (ARG_WORD(0) == EW_RESAMPLE){
  					type = 2;
  					mode = 1;
  				}
  
  				FX_Fit(effects,ARG_IMAGE(0), ARG_WORDS(type,EW_NEAREST,EW_GAUSSIAN), ARG_WORD(mode) == EW_RESAMPLE, IS_NONE(arg+3) ? 1.0 : ARG_DECIMAL(3), FALSE);
  			}
  			break;
  
  		case EW_FLIP:
  			FX_Flip(effects, IS_NONE(arg+1) ? &def_pair : &ARG_PAIR(1), ARG_OPT_IMAGE(0));
  			break;
  
  		case EW_GRADCOL:
  			FX_Gradcol(effects, &ARG_PAIR(1), IS_NONE(arg+2) ? def_color1 : ARG_TUPLE(2), IS_NONE(arg+3) ? def_color2 : ARG_TUPLE(3),ARG_OPT_IMAGE(0));
  			break;
  
  		case EW_GRADIENT:
  			FX_Gradient(effects, &ARG_PAIR(1), IS_NONE(arg+2) ? def_color1 : ARG_TUPLE(2), IS_NONE(arg+3) ? def_color2 : ARG_TUPLE(3), ARG_OPT_IMAGE(0));
  			break;
  
  		case EW_GRADMUL:
  			FX_Gradmul(effects, &ARG_PAIR(1), IS_NONE(arg+2) ? def_color1 : ARG_TUPLE(2), IS_NONE(arg+3) ? def_color2 : ARG_TUPLE(3), ARG_OPT_IMAGE(0));
  			break;
  
  		case EW_GRAYSCALE:
  			FX_Grayscale(effects,ARG_OPT_IMAGE(0));
  			break;
  
  		case EW_HSV:
  			FX_HSV(effects, IS_NONE(arg+1) ? def_color2 : ARG_TUPLE(1), ARG_OPT_IMAGE(0));
  			break;
  
  		case EW_INVERT:
  			FX_Invert(effects,ARG_OPT_IMAGE(0));
  			break;
  		case EW_KEY:
  			if (IS_IMAGE(arg))
  				FX_Key(effects, IS_NONE(arg+1) ? def_color1 : ARG_TUPLE(1), ARG_IMAGE(0));
  			break;
  		case EW_LUMA:
  			FX_Luma(effects, IS_NONE(arg+1) ? 127 : ARG_INTEGER(1),ARG_OPT_IMAGE(0));
  			break;
  
  		case EW_MIX:
  			FX_Mix(effects, ARG_OPT_IMAGE(0), ARG_OPT_IMAGE(1));
  			break;
  
  		case EW_MULTIPLY:
  			{
  				REBINT i = 0x00FFFFFF;
  				REBYTE* color = (REBYTE*)&i;
  				if (IS_INTEGER(arg+3)) {
  					i = ARG_INTEGER(3);
  					i = i + (i << 8) + (i << 16);
  				} else if (IS_TUPLE(arg+2))
  					color = ARG_TUPLE(2);
  				FX_Multiply(effects, color ,ARG_OPT_IMAGE(0), ARG_OPT_IMAGE(1), (IS_NONE(arg+2) &&  IS_NONE(arg+3)) ? 1 : 0);
  			}
  			break;
  
  		case EW_REFLECT:
  			FX_Reflect(effects, IS_NONE(arg+1) ? &def_pair : &ARG_PAIR(1), ARG_OPT_IMAGE(0));
  			break;
  
  		case EW_ROTATE:
  			FX_Rotate(effects, IS_NONE(arg+1) ? 90 : ARG_INTEGER(1), ARG_OPT_IMAGE(0));
  			break;
  		case EW_SHADOW:
  			if (IS_IMAGE(arg))
  				FX_Shadow(effects, ARG_IMAGE(0), IS_NONE(arg+1) ? 0 : &ARG_PAIR(1), IS_NONE(arg+2) ? 0 : &ARG_PAIR(2), IS_NONE(arg+3) ? 0 : ARG_TUPLE(3), IS_NONE(arg+4) ? 0 : ARG_DECIMAL(4), IS_NONE(arg+5) ? 0 : ARG_WORD(5) == EW_ONLY);
  			break;
  		case EW_SHARPEN:
  //			FX_Sharpen(effects, ARG_OPT_IMAGE(0));
  			{
  				REBDEC filter[9] = {0, -1, 0, -1, 8, -1, 0, -1, 0};
  				FX_Convolve(effects, ARG_OPT_IMAGE(0),filter , 4.0, 0, FALSE);
  			}
  			break;
  		case EW_TILE:
  			if (IS_IMAGE(arg))
  				FX_Tile(effects, ARG_IMAGE(0), &ARG_PAIR(1));
  			break;
  		case EW_TILE_VIEW:
  			if (IS_IMAGE(arg)) {
  				REBPAR p;
  				Effect_Offset(effects, &p);
  				FX_Tile(effects, ARG_IMAGE(0), &p);
  			}
  			break;
  		case EW_TINT:
  			FX_Tint(effects, IS_NONE(arg+1) ? 127 : ARG_INTEGER(1),ARG_OPT_IMAGE(0));
  			break;
  		}
  	} while (TRUE);
  }
  