/* memory.h Copyright (C) 2004-2006 Mark Tyler and Dmitry Groshev This file is part of mtPaint. mtPaint is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. mtPaint is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with mtPaint in the file COPYING. */ #include /// Definitions, structures & variables #define MAX_WIDTH 16384 #define MAX_HEIGHT 16384 #define MIN_WIDTH 1 #define MIN_HEIGHT 1 #ifdef U_GUADALINEX #define DEFAULT_WIDTH 800 #define DEFAULT_HEIGHT 600 #else #define DEFAULT_WIDTH 640 #define DEFAULT_HEIGHT 480 #endif #define PALETTE_WIDTH 74 #define PALETTE_HEIGHT 4500 #define PATCH_WIDTH 324 #define PATCH_HEIGHT 324 #define TOOL_SQUARE 0 #define TOOL_CIRCLE 1 #define TOOL_HORIZONTAL 2 #define TOOL_VERTICAL 3 #define TOOL_SLASH 4 #define TOOL_BACKSLASH 5 #define TOOL_SPRAY 6 #define TOOL_SHUFFLE 7 #define TOOL_FLOOD 8 #define TOOL_SELECT 9 #define TOOL_LINE 10 #define TOOL_SMUDGE 11 #define TOOL_POLYGON 12 #define TOOL_CLONE 13 #define TOOL_GRADIENT 14 #define TOTAL_CURSORS 15 #define NO_PERIM(T) (((T) == TOOL_FLOOD) || ((T) == TOOL_SELECT) || \ ((T) == TOOL_POLYGON) || ((T) == TOOL_GRADIENT)) #define PROGRESS_LIM 262144 #define CHN_IMAGE 0 #define CHN_ALPHA 1 #define CHN_SEL 2 #define CHN_MASK 3 #define NUM_CHANNELS 4 #define CMASK_NONE 0 #define CMASK_IMAGE (1 << CHN_IMAGE) #define CMASK_RGBA ((1 << CHN_IMAGE) | (1 << CHN_ALPHA)) #define CMASK_ALL ((1 << NUM_CHANNELS) - 1) #define CMASK_CURR (1 << mem_channel) #define CMASK_FOR(A) (1 << (A)) char *channames[NUM_CHANNELS + 1], *allchannames[NUM_CHANNELS + 1]; typedef unsigned char *chanlist[NUM_CHANNELS]; typedef struct { chanlist img; png_color pal[256]; int cols, width, height, bpp; } undo_item; /// GRADIENTS #define MAX_GRAD 65536 #define GRAD_POINTS 256 typedef struct { /* Base values */ int status, x1, y1, x2, y2; // Gradient placement tool int len, rep, ofs; // Gradient length, repeat, and offset int gmode, rmode; // Gradient mode and repeat mode /* Derived values */ double wrep, wil1, wil2, xv, yv; int wmode; } grad_info; typedef struct { char gtype, otype; // Main and opacity gradient types char grev, orev; // Main and opacity reversal flags int vslen, oplen; // Current gradient lengths int cvslen, coplen; // Custom gradient lengths unsigned char *vs, *vsmap; // Current gradient data unsigned char *op, *opmap; // Current gradient opacities } grad_map; typedef unsigned char grad_store[(6 + NUM_CHANNELS * 4) * GRAD_POINTS]; grad_info gradient[NUM_CHANNELS]; // Per-channel gradient placement double grad_path, grad_x0, grad_y0; // Stroke gradient temporaries grad_map graddata[NUM_CHANNELS + 1]; // RGB + per-channel gradient data grad_store gradbytes; // Storage space for custom gradients int grad_opacity; // Preview opacity /* Gradient modes */ #define GRAD_MODE_NONE 0 #define GRAD_MODE_LINEAR 1 #define GRAD_MODE_BILINEAR 2 #define GRAD_MODE_RADIAL 3 #define GRAD_MODE_SQUARE 4 /* Boundary conditions */ #define GRAD_BOUND_STOP 0 #define GRAD_BOUND_LEVEL 1 #define GRAD_BOUND_REPEAT 2 #define GRAD_BOUND_MIRROR 3 /* Gradient types */ #define GRAD_TYPE_RGB 0 #define GRAD_TYPE_HSV 1 #define GRAD_TYPE_BK_HSV 2 #define GRAD_TYPE_CONST 3 #define GRAD_TYPE_CUSTOM 4 /// Bayer ordered dithering const unsigned char bayer[16]; #define BAYER_MASK 15 /* Use 16x16 matrix */ #define BAYER(x,y) (bayer[((x) ^ (y)) & BAYER_MASK] * 2 + bayer[(y) & BAYER_MASK]) /// Tint tool - contributed by Dmitry Groshev, January 2006 int tint_mode[3]; // [0] = off/on, [1] = add/subtract, [2] = button (none, left, middle, right : 0-3) int mem_cselect; int mem_unmask; int mem_gradient; /// FLOOD FILL SETTINGS double flood_step; int flood_cube, flood_img, flood_slide; int smudge_mode; /// IMAGE char mem_filename[256]; // File name of file loaded/saved chanlist mem_img; // Array of pointers to image channels int mem_channel; // Current active channel int mem_img_bpp; // Bytes per pixel = 1 or 3 int mem_changed; // Changed since last load/save flag 0=no, 1=changed int mem_width, mem_height; // Current image geometry float mem_icx, mem_icy; // Current centre x,y int mem_ics; // Has the centre been set by the user? 0=no 1=yes unsigned char *mem_clipboard; // Pointer to clipboard data unsigned char *mem_clip_mask; // Pointer to clipboard mask unsigned char *mem_clip_alpha; // Pointer to clipboard alpha unsigned char *mem_brushes; // Preset brushes image int brush_tool_type; // Last brush tool type int mem_brush_list[81][3]; // Preset brushes parameters int mem_clip_bpp; // Bytes per pixel int mem_clip_w, mem_clip_h; // Clipboard geometry int mem_clip_x, mem_clip_y; // Clipboard location on canvas int mem_nudge; // Nudge pixels per SHIFT+Arrow key during selection/paste int mem_preview; // Preview an RGB change int mem_prev_bcsp[6]; // BR, CO, SA, POSTERIZE, GAMMA, Hue #define MAX_UNDO 101 // Maximum number of undo levels + 1 undo_item mem_undo_im_[MAX_UNDO]; // Pointers to undo images + current image being edited int mem_undo_pointer; // Pointer to currently used image on canvas/screen int mem_undo_done; // Undo images that we have behind current image (i.e. possible UNDO) int mem_undo_redo; // Undo images that we have ahead of current image (i.e. possible REDO) int mem_undo_limit; // Max MB memory allocation limit int mem_undo_opacity; // Use previous image for opacity calculations? /// GRID int mem_show_grid, mem_grid_min; // Boolean show toggle & minimum zoom to show it at unsigned char mem_grid_rgb[3]; // RGB colour of grid /// PATTERNS char mem_patterns[81][8][8]; // Pattern bitmaps unsigned char *mem_pattern; // Original 0-1 pattern unsigned char *mem_col_pat; // Indexed 8x8 colourised pattern using colours A & B unsigned char *mem_col_pat24; // RGB 8x8 colourised pattern using colours A & B /// PREVIEW/TOOLS int tool_type, tool_size, tool_flow; // Currently selected tool int tool_opacity; // Opacity - 255 = solid int tool_pat; // Tool pattern number int pen_down; // Are we drawing? - Used to see if we need to do an UNDO int tool_ox, tool_oy; // Previous tool coords - used by continuous mode int mem_continuous; // Area we painting the static shapes continuously? int mem_brcosa_allow[3]; // BRCOSA RGB /// FILE int mem_xpm_trans; // Current XPM file transparency colour index int mem_xbm_hot_x, mem_xbm_hot_y; // Current XBM hot spot int mem_jpeg_quality; // JPEG quality setting /// PALETTE png_color mem_pal[256]; // RGB entries for all 256 palette colours png_color mem_pal_def[256]; // Default palette entries for new image int mem_pal_def_i; // Items in default palette int mem_cols; // Number of colours in the palette: 2..256 or 0 for no image char *mem_pals; // RGB screen memory holding current palette char mem_prot_mask[256]; // 256 bytes used for indexed images int mem_prot_RGB[256]; // Up to 256 RGB colours protected int mem_prot; // 0..256 : Number of protected colours in mem_prot_RGB int mem_col_[2]; // Index for colour A & B #define mem_col_A mem_col_[0] #define mem_col_B mem_col_[1] png_color mem_col_24[2]; // RGB for colour A & B #define mem_col_A24 mem_col_24[0] #define mem_col_B24 mem_col_24[1] int mem_background; // Non paintable area int mem_histogram[256]; /// Line iterator /* Indices 0 and 1 are current X and Y, 2 is number of pixels remaining */ typedef int linedata[10]; void line_init(linedata line, int x0, int y0, int x1, int y1); int line_step(linedata line); void line_nudge(linedata line, int x, int y); /// Procedures void init_istate(); // Set initial state of image variables int mem_count_all_cols(); // Count all colours - Using main image int mem_count_all_cols_real(unsigned char *im, int w, int h); // Count all colours - very memory greedy int mem_cols_used(int max_count); // Count colours used in main RGB image int mem_cols_used_real(unsigned char *im, int w, int h, int max_count, int prog); // Count colours used in RGB chunk and dump to found table void mem_cols_found_dl(unsigned char userpal[3][256]); // Convert results ready for DL code int get_next_line(char *input, int length, FILE *fp); // Get next length chars of text file int mt_round( float n ); // Round a float to nearest whole number int read_hex( char in ); // Convert character to hex value 0..15. -1=error int read_hex_dub( char *in ); // Read hex double char *grab_memory( int size, char byte ); // Malloc memory, reset all bytes void mem_clear(); // Remove old image if any // Allocate space for new image, removing old if needed int mem_new( int width, int height, int bpp, int cmask ); int valid_file( char *filename ); // Can this file be opened for reading? void mem_init(); // Initialise memory int mem_used(); // Return the number of bytes used in image + undo stuff int mem_used_layers(); // Return the number of bytes used in image + undo in all layers void mem_bacteria( int val ); // Apply bacteria effect val times the canvas area void do_effect( int type, int param ); // 0=edge detect 1=UNUSED 2=emboss void mem_gauss(double radiusX, double radiusY, int gcor); void mem_unsharp(double radius, double amount, int threshold, int gcor); /// PALETTE PROCS int mem_load_pal( char *file_name, png_color *pal ); // Load file into palette array >1 => cols read void mem_pal_load_def(); // Load default palette #define mem_pal_copy(A, B) memcpy((A), (B), sizeof(png_color) * 256) void mem_pal_init(); // Initialise whole of palette RGB int mem_pal_cmp( png_color *pal1, // Count itentical palette entries png_color *pal2 ); void mem_greyscale(int gcor); // Convert image to greyscale int mem_convert_rgb(); // Convert image to RGB int mem_convert_indexed(); // Convert image to Indexed Palette // Convert RGB->indexed using error diffusion with variety of options int mem_dither(unsigned char *old, int ncols, short *dither, int cspace, int dist, int limit, int selc, int serpent, double emult); int mem_quantize( unsigned char *old_mem_image, int target_cols, int type ); // Convert image to Indexed Palette using quantize void mem_invert(); // Invert the palette void mem_mask_setall(char val); // Clear/set all masks void mem_mask_init(); // Initialise RGB protection mask int mem_protected_RGB(int intcol); // Is this intcol in list? void mem_swap_cols(); // Swaps colours and update memory void repaint_swatch( int index ); // Update a palette swatch void mem_get_histogram(int channel); // Calculate how many of each colour index is on the canvas int do_posterize(int val, int posty); // Posterize a number int scan_duplicates(); // Find duplicate palette colours void remove_duplicates(); // Remove duplicate palette colours - call AFTER scan_duplicates int mem_remove_unused_check(); // Check to see if we can remove unused palette colours int mem_remove_unused(); // Remove unused palette colours void mem_scale_pal( int i1, int r1, int g1, int b1, int i2, int r2, int g2, int b2 ); // Generate a scaled palette // Create colour-transformed palette void transform_pal(png_color *pal1, png_color *pal2, int p1, int p2); void mem_pal_sort( int a, int i1, int i2, int rev ); // Sort colours in palette 0=luminance, 1=RGB void mem_pal_index_move( int c1, int c2 ); // Move index c1 to c2 and shuffle in between up/down void mem_canvas_index_move( int c1, int c2 ); // Similar to palette item move but reworks canvas pixels void set_zoom_centre( int x, int y ); // Nonclassical HSV: H is 0..6, S is 0.. 1, V is 0..255 void rgb2hsv(unsigned char *rgb, double *hsv); //// UNDO #define UNDO_PAL 0 /* Palette changes */ #define UNDO_XPAL 1 /* Palette and indexed image changes */ #define UNDO_COL 2 /* Palette and/or RGB image changes */ #define UNDO_DRAW 3 /* Changes to current channel / RGBA */ #define UNDO_INV 4 /* "Invert" operation */ #define UNDO_XFORM 5 /* Changes to all channels */ #define UNDO_FILT 6 /* Changes to current channel */ #define UNDO_PASTE 7 /* Paste operation (current / RGBA) */ #define UNDO_TOOL 8 /* Same as UNDO_DRAW but respects pen_down */ void undo_free_x(undo_item *undo); int mem_undo_next(int mode); // Call this after a draw event but before any changes to image // Get address of previous channel data (or current if none) unsigned char *mem_undo_previous(int channel); void mem_undo_backward(); // UNDO requested by user void mem_undo_forward(); // REDO requested by user #define UC_CREATE 1 /* Force create */ #define UC_NOCOPY 2 /* Forbid copy */ #define UC_DELETE 4 /* Force delete */ #define UC_PENDOWN 8 /* Respect pen_down */ int undo_next_core(int mode, int new_width, int new_height, int new_bpp, int cmask); //// Drawing Primitives int mem_clip_mask_init(unsigned char val); // Initialise the clipboard mask // Extract alpha info from RGB clipboard int mem_scale_alpha(unsigned char *img, unsigned char *alpha, int width, int height, int mode); void mem_mask_colors(unsigned char *mask, unsigned char *img, unsigned char v, int width, int height, int bpp, int col0, int col1); void mem_clip_mask_set(unsigned char val); // Mask colours A and B on the clipboard void mem_clip_mask_clear(); // Clear the clipboard mask void do_clone(int ox, int oy, int nx, int ny, int opacity, int mode); #define mem_smudge(A, B, C, D) do_clone((A), (B), (C), (D), MEM_BPP == 3 ? \ tool_opacity / 2 : 127, smudge_mode && mem_undo_opacity) #define mem_clone(A, B, C, D) do_clone((A), (B), (C), (D), MEM_BPP == 3 ? \ tool_opacity : -1, mem_undo_opacity) // Apply colour transform void do_transform(int start, int step, int cnt, unsigned char *mask, unsigned char *imgr, unsigned char *img0); void mem_flip_v(char *mem, char *tmp, int w, int h, int bpp); // Flip image vertically void mem_flip_h( char *mem, int w, int h, int bpp ); // Flip image horizontally int mem_sel_rot( int dir ); // Rotate clipboard 90 degrees int mem_image_rot( int dir ); // Rotate canvas 90 degrees int mem_rotate_free(double angle, int type, int gcor); // Rotate canvas by any angle (degrees) int mem_image_scale(int nw, int nh, int type, int gcor); // Scale image int mem_image_resize(int nw, int nh, int ox, int oy, int mode); // Resize image int mem_isometrics(int type); void mem_threshold(int channel, int level); // Threshold channel values void flood_fill( int x, int y, unsigned int target ); void sline( int x1, int y1, int x2, int y2 ); // Draw single thickness straight line void tline( int x1, int y1, int x2, int y2, int size ); // Draw size thickness straight line void g_para( int x1, int y1, int x2, int y2, int xv, int yv ); // Draw general parallelogram void f_rectangle( int x, int y, int w, int h ); // Draw a filled rectangle void f_circle( int x, int y, int r ); // Draw a filled circle void f_ellipse( int x1, int y1, int x2, int y2 ); // Draw a filled ellipse void o_ellipse( int x1, int y1, int x2, int y2, int thick ); // Draw an ellipse outline // Draw whatever is bounded by two pairs of lines void draw_quad(linedata line1, linedata line2, linedata line3, linedata line4); // A couple of shorthands to get an int representation of an RGB colour #define PNG_2_INT(var) ((var.red << 16) + (var.green << 8) + (var.blue)) #define MEM_2_INT(M,I) (((M)[(I)] << 16) + ((M)[(I) + 1] << 8) + (M)[(I) + 2]) #define INT_2_R(A) ((A) >> 16) #define INT_2_G(A) (((A) >> 8) & 0xFF) #define INT_2_B(A) ((A) & 0xFF) #define RGB_2_INT(R,G,B) (((R) << 16) + ((G) << 8) + (B)) #define MEM_BPP (mem_channel == CHN_IMAGE ? mem_img_bpp : 1) #define BPP(x) ((x) == CHN_IMAGE ? mem_img_bpp : 1) #define GET_PIXEL(x,y) (mem_img[CHN_IMAGE][(x) + (y) * mem_width]) #define POSTERIZE_MACRO res = 0.49 + ( ((1 << posty) - 1) * ((float) res)/255);\ res = 0.49 + 255 * ( ((float) res) / ((1 << posty) - 1) ); void prep_mask(int start, int step, int cnt, unsigned char *mask, unsigned char *mask0, unsigned char *img0); void process_mask(int start, int step, int cnt, unsigned char *mask, unsigned char *alphar, unsigned char *alpha0, unsigned char *alpha, unsigned char *trans, int opacity, int noalpha); void process_img(int start, int step, int cnt, unsigned char *mask, unsigned char *imgr, unsigned char *img0, unsigned char *img, int opacity, int sourcebpp); void paste_pixels(int x, int y, int len, unsigned char *mask, unsigned char *img, unsigned char *alpha, unsigned char *trans, int opacity); int pixel_protected(int x, int y); // generic void row_protected(int x, int y, int len, unsigned char *mask); void put_pixel( int x, int y ); // generic int get_pixel( int x, int y ); // generic int get_pixel_RGB( int x, int y ); // converter int get_pixel_img( int x, int y ); // from image int grad_value(int *dest, int slot, double x); int grad_pixel(unsigned char *dest, int x, int y); void grad_update(grad_info *grad); void gmap_setup(grad_map *gmap, grad_store gstore, int slot); void grad_def_update(); void prep_grad(int start, int step, int cnt, int x, int y, unsigned char *mask, unsigned char *op0, unsigned char *img0, unsigned char *alpha0); #define GRAD_CUSTOM_DATA(X) ((X) ? GRAD_POINTS * ((X) * 4 + 2) : 0) #define GRAD_CUSTOM_DMAP(X) (GRAD_POINTS * ((X) * 4 + 3)) #define GRAD_CUSTOM_OPAC(X) (GRAD_POINTS * ((X) * 4 + 4)) #define GRAD_CUSTOM_OMAP(X) (GRAD_POINTS * ((X) * 4 + 5)) void blend_channel(int start, int step, int cnt, unsigned char *mask, unsigned char *dest, unsigned char *src, int opacity); void blend_indexed(int start, int step, int cnt, unsigned char *rgb, unsigned char *img0, unsigned char *img, unsigned char *alpha0, unsigned char *alpha, int opacity); #define IF_IN_RANGE( x, y ) if ( x>=0 && y>=0 && xc ) a=b; else a=c; /* * Win32 libc (MSVCRT.DLL) violates the C standard as to malloc()'ed memory * alignment; this macro serves as part of a workaround for that problem */ #ifdef WIN32 #define ALIGNTO(p,s) ((void *)(((int)(p) + sizeof(s) - 1) & (-sizeof(s)))) #else #define ALIGNTO(p,s) ((void *)(p)) #endif