Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Added grafx2 app

  • Loading branch information...
commit b4546c9687940fea14c1a932aee4f30772106054 1 parent 2d4a420
@pelya authored
Showing with 48,957 additions and 4,292 deletions.
  1. +16 −0 checkMissing.sh
  2. +15 −4,292 exports-eclair.txt
  3. +36 −0 project/jni/application/grafx2/AndroidAppSettings.cfg
  4. BIN  project/jni/application/grafx2/AndroidData/data.zip
  5. +11 −0 project/jni/application/grafx2/grafx2/src/SDLMain.h
  6. +224 −0 project/jni/application/grafx2/grafx2/src/SFont.c
  7. +100 −0 project/jni/application/grafx2/grafx2/src/SFont.h
  8. +1,944 −0 project/jni/application/grafx2/grafx2/src/brush.c
  9. +129 −0 project/jni/application/grafx2/grafx2/src/brush.h
  10. +1,392 −0 project/jni/application/grafx2/grafx2/src/brush_ops.c
  11. +5,478 −0 project/jni/application/grafx2/grafx2/src/buttons.c
  12. +678 −0 project/jni/application/grafx2/grafx2/src/buttons.h
  13. +1,259 −0 project/jni/application/grafx2/grafx2/src/buttons_effects.c
  14. +529 −0 project/jni/application/grafx2/grafx2/src/const.h
  15. +3,499 −0 project/jni/application/grafx2/grafx2/src/engine.c
  16. +123 −0 project/jni/application/grafx2/grafx2/src/engine.h
  17. +54 −0 project/jni/application/grafx2/grafx2/src/errors.h
  18. +1,882 −0 project/jni/application/grafx2/grafx2/src/factory.c
  19. +13 −0 project/jni/application/grafx2/grafx2/src/factory.h
  20. +4,091 −0 project/jni/application/grafx2/grafx2/src/fileformats.c
  21. +2,037 −0 project/jni/application/grafx2/grafx2/src/filesel.c
  22. +59 −0 project/jni/application/grafx2/grafx2/src/filesel.h
  23. +1,037 −0 project/jni/application/grafx2/grafx2/src/global.h
  24. +2,994 −0 project/jni/application/grafx2/grafx2/src/graph.c
  25. +123 −0 project/jni/application/grafx2/grafx2/src/graph.h
  26. +8 −0 project/jni/application/grafx2/grafx2/src/haiku.h
  27. +863 −0 project/jni/application/grafx2/grafx2/src/help.c
  28. +66 −0 project/jni/application/grafx2/grafx2/src/help.h
  29. +2,966 −0 project/jni/application/grafx2/grafx2/src/helpfile.h
  30. +1,846 −0 project/jni/application/grafx2/grafx2/src/hotkeys.c
  31. +60 −0 project/jni/application/grafx2/grafx2/src/hotkeys.h
  32. +2,976 −0 project/jni/application/grafx2/grafx2/src/init.c
  33. +56 −0 project/jni/application/grafx2/grafx2/src/init.h
  34. +1,103 −0 project/jni/application/grafx2/grafx2/src/input.c
  35. +66 −0 project/jni/application/grafx2/grafx2/src/input.h
  36. +498 −0 project/jni/application/grafx2/grafx2/src/io.c
  37. +125 −0 project/jni/application/grafx2/grafx2/src/io.h
  38. +713 −0 project/jni/application/grafx2/grafx2/src/keyboard.c
  39. +77 −0 project/jni/application/grafx2/grafx2/src/keyboard.h
  40. +391 −0 project/jni/application/grafx2/grafx2/src/layers.c
  41. +35 −0 project/jni/application/grafx2/grafx2/src/layers.h
  42. +190 −0 project/jni/application/grafx2/grafx2/src/libraw2crtc.c
  43. +14 −0 project/jni/application/grafx2/grafx2/src/libraw2crtc.h
  44. +1,587 −0 project/jni/application/grafx2/grafx2/src/loadsave.c
  45. +259 −0 project/jni/application/grafx2/grafx2/src/loadsave.h
  46. +966 −0 project/jni/application/grafx2/grafx2/src/main.c
  47. +880 −0 project/jni/application/grafx2/grafx2/src/misc.c
  48. +167 −0 project/jni/application/grafx2/grafx2/src/misc.h
  49. +2,701 −0 project/jni/application/grafx2/grafx2/src/miscfileformats.c
  50. +934 −0 project/jni/application/grafx2/grafx2/src/mountlist.c
  51. +54 −0 project/jni/application/grafx2/grafx2/src/mountlist.h
  52. +1,415 −0 project/jni/application/grafx2/grafx2/src/op_c.c
  53. +218 −0 project/jni/application/grafx2/grafx2/src/op_c.h
Sorry, we could not display the entire diff because it was too big.
View
16 checkMissing.sh
@@ -0,0 +1,16 @@
+#!/bin/sh
+# Print list of symbols inside libapplication.so which are not defined in Android libc
+# Internal compiler things like '__aeabi_ddiv' or '___Unwind_Resume' may be safely ignored
+rm -f exports.txt libapplication.txt
+cat exports-eclair.txt > exports.txt
+nm -g -p --undefined-only project/obj/local/armeabi/libapplication.so | cut -b 12- | sort > libapplication.txt
+for f in project/obj/local/armeabi/*.so; do
+ if [ "$f" = "project/obj/local/armeabi/libapplication.so" ]; then
+ continue
+ fi
+ nm -g -p --defined-only $f 2>/dev/null | cut -b 12- >> exports.txt
+done
+cat exports.txt | sort > exports1.txt
+mv -f exports1.txt exports.txt
+diff libapplication.txt exports.txt | grep \< | cut -d \ -f 2
+rm libapplication.txt exports.txt
View
4,307 exports-eclair.txt
15 additions, 4,292 deletions not shown
View
36 project/jni/application/grafx2/AndroidAppSettings.cfg
@@ -0,0 +1,36 @@
+# The application settings for Android libSDL port
+AppSettingVersion=17
+LibSdlVersion=1.2
+AppName="grafx2"
+AppFullName=com.grafx2
+ScreenOrientation=h
+InhibitSuspend=y
+AppDataDownloadUrl="!Data|data.zip"
+SdlVideoResize=y
+SdlVideoResizeKeepAspect=n
+NeedDepthBuffer=n
+SwVideoMode=y
+AppUsesMouse=y
+AppNeedsTwoButtonMouse=y
+AppNeedsArrowKeys=n
+AppNeedsTextInput=n
+AppUsesJoystick=n
+AppHandlesJoystickSensitivity=y
+AppUsesMultitouch=n
+NonBlockingSwapBuffers=n
+RedefinedKeys="SPACE TAB NO_REMAP NO_REMAP RETURN ESCAPE DELETE"
+AppTouchscreenKeyboardKeysAmount=0
+AppTouchscreenKeyboardKeysAmountAutoFire=0
+RedefinedKeysScreenKb="SPACE TAB PLUS MINUS RETURN ESCAPE DELETE"
+StartupMenuButtonTimeout=3000
+HiddenMenuOptions='OptionalDownloadConfig'
+MultiABI=n
+AppVersionCode=23178101
+AppVersionName="2.3.1781.01"
+CompiledLibraries="jpeg png sdl_image sdl_ttf lua"
+CustomBuildScript=n
+AppCflags='-DVIRT_KEY -D__ENABLE_LUA__ -std=c99'
+AppLdflags=''
+AppSubdirsBuild='grafx2/src'
+AppCmdline='sdl'
+ReadmeText='^You may press "Home" now - the data will be downloaded in background'
View
BIN  project/jni/application/grafx2/AndroidData/data.zip
Binary file not shown
View
11 project/jni/application/grafx2/grafx2/src/SDLMain.h
@@ -0,0 +1,11 @@
+/* SDLMain.m - main entry point for our Cocoa-ized SDL app
+ Initial Version: Darrell Walisser <dwaliss1@purdue.edu>
+ Non-NIB-Code & other changes: Max Horn <max@quendi.de>
+
+ Feel free to customize this file to suit your needs
+*/
+
+#import <Cocoa/Cocoa.h>
+
+@interface SDLMain : NSObject
+@end
View
224 project/jni/application/grafx2/grafx2/src/SFont.c
@@ -0,0 +1,224 @@
+/* vim:expandtab:ts=2 sw=2:
+*/
+/* SFont: a simple font-library that uses special .pngs as fonts
+ Copyright (C) 2003 Karl Bartel
+
+ License: GPL or LGPL (at your choice)
+ WWW: http://www.linux-games.com/sfont/
+
+ This program 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.
+
+ This program 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 this program; if not, see <http://www.gnu.org/licenses/>.
+
+ Karl Bartel
+ Cecilienstr. 14
+ 12307 Berlin
+ GERMANY
+ karlb@gmx.net
+*/
+#include <SDL.h>
+#include <SDL_video.h>
+
+#include <assert.h>
+#include <stdlib.h>
+#include "SFont.h"
+
+static Uint32 GetPixel(SDL_Surface *Surface, Sint32 X, Sint32 Y)
+{
+ Uint8 *bits;
+ Uint32 Bpp;
+
+ assert(X>=0);
+ assert(X<Surface->w);
+
+ Bpp = Surface->format->BytesPerPixel;
+ bits = ((Uint8 *)Surface->pixels)+Y*Surface->pitch+X*Bpp;
+
+ // Get the pixel
+ switch(Bpp) {
+ case 1:
+ return *((Uint8 *)Surface->pixels + Y * Surface->pitch + X);
+ break;
+ case 2:
+ return *((Uint16 *)Surface->pixels + Y * Surface->pitch/2 + X);
+ break;
+ case 3: { // Format/endian independent
+ Uint8 r, g, b;
+ r = *((bits)+Surface->format->Rshift/8);
+ g = *((bits)+Surface->format->Gshift/8);
+ b = *((bits)+Surface->format->Bshift/8);
+ return SDL_MapRGB(Surface->format, r, g, b);
+ }
+ break;
+ case 4:
+ return *((Uint32 *)Surface->pixels + Y * Surface->pitch/4 + X);
+ break;
+ }
+
+ return -1;
+}
+
+SFont_Font* SFont_InitFont(SDL_Surface* Surface)
+{
+ int x = 0, i = 33;
+ Uint32 pixel;
+ SFont_Font* Font;
+ Uint32 pink;
+
+ if (Surface == NULL)
+ return NULL;
+
+ Font = (SFont_Font *) malloc(sizeof(SFont_Font));
+ memset(Font, 0, sizeof(SFont_Font));
+
+ Font->Surface = Surface;
+
+ SDL_LockSurface(Surface);
+
+ pink = GetPixel(Surface, 0, 0);
+ while (x < Surface->w) {
+ if (GetPixel(Surface, x, 0) != pink) {
+ Font->CharBegin[i]=x;
+ while((x < Surface->w) && (GetPixel(Surface, x, 0)!= pink))
+ x++;
+ Font->CharWidth[i]=x-Font->CharBegin[i];
+ i++;
+ }
+ x++;
+ }
+
+ // Create lowercase characters, if not present
+ for (i=0; i <26; i++)
+ {
+ if (Font->CharWidth['a'+i]==0)
+ {
+ Font->CharBegin['a'+i]=Font->CharBegin['A'+i];
+ Font->CharWidth['a'+i]=Font->CharWidth['A'+i];
+ }
+ }
+
+ // Determine space width.
+ // This strange format doesn't allow font designer to write explicit
+ // space as a character.
+ // Rule: A space should be as large as the character " if available,
+ // or 'a' if it's not.
+ Font->Space = Font->CharWidth[(int)'"'];
+ if (Font->Space<2)
+ Font->Space = Font->CharWidth[(int)'a'];
+
+ pixel = GetPixel(Surface, 0, Surface->h-1);
+ SDL_UnlockSurface(Surface);
+ // No longer use SDL color keying
+ //SDL_SetColorKey(Surface, SDL_SRCCOLORKEY, pixel);
+ Font->Transparent=pixel;
+
+ return Font;
+}
+
+void SFont_FreeFont(SFont_Font* FontInfo)
+{
+ SDL_FreeSurface(FontInfo->Surface);
+ free(FontInfo);
+}
+
+void SFont_Write(SDL_Surface *Surface, const SFont_Font *Font,
+ int x, int y, const char *text)
+{
+ const char* c;
+ SDL_Rect srcrect, dstrect;
+
+ if(text == NULL)
+ return;
+
+ // these values won't change in the loop
+ srcrect.y = 1;
+ dstrect.y = y;
+ srcrect.h = dstrect.h = Font->Surface->h - 1;
+
+ for(c = text; *c != '\0' && x <= Surface->w ; c++) {
+ if (*c == '\n') {
+ dstrect.y += Font->Surface->h-1;
+ x=0;
+ continue;
+ }
+ // skip spaces and nonprintable characters
+ else if (*c == ' ' || Font->CharWidth[(int)*c]==0) {
+ x += Font->Space;
+ continue;
+ }
+
+ srcrect.w = Font->CharWidth[(int)*c];
+ dstrect.w = srcrect.w;
+ srcrect.x = Font->CharBegin[(int)*c];
+ dstrect.x = x;
+
+ SDL_BlitSurface(Font->Surface, &srcrect, Surface, &dstrect);
+
+ x += Font->CharWidth[(int)*c];
+ }
+}
+
+int SFont_TextWidth(const SFont_Font *Font, const char *text)
+{
+ const char* c;
+ int width = 0;
+ int previous_width = 0;
+
+ if(text == NULL)
+ return 0;
+
+ for(c = text; *c != '\0'; c++)
+ {
+ if (*c == '\n')
+ {
+ if (previous_width<width)
+ previous_width=width;
+ width=0;
+ }
+ else
+ // skip spaces and nonprintable characters
+ if (*c == ' ' || Font->CharWidth[(int)*c]==0)
+ {
+ width += Font->Space;
+ continue;
+ }
+
+ width += Font->CharWidth[(int)*c];
+ }
+
+ return previous_width<width ? width : previous_width;
+}
+
+int SFont_TextHeight(const SFont_Font* Font, const char *text)
+{
+ // Count occurences of '\n'
+ int nb_cr=0;
+ while (*text!='\0')
+ {
+ if (*text=='\n')
+ nb_cr++;
+ text++;
+ }
+
+ return (Font->Surface->h - 1) * (nb_cr+1);
+}
+
+/*
+// Do not use: Doesn't implement carriage returns
+
+void SFont_WriteCenter(SDL_Surface *Surface, const SFont_Font *Font,
+ int y, const char *text)
+{
+ SFont_Write(Surface, Font, Surface->w/2 - SFont_TextWidth(Font, text)/2,
+ y, text);
+}
+*/
View
100 project/jni/application/grafx2/grafx2/src/SFont.h
@@ -0,0 +1,100 @@
+/* vim:expandtab:ts=2 sw=2:
+*/
+/* SFont: a simple font-library that uses special bitmaps as fonts
+ Copyright (C) 2003 Karl Bartel
+
+ License: GPL or LGPL (at your choice)
+ WWW: http://www.linux-games.com/sfont/
+
+ This program 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.
+
+ This program 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 this program; if not, see <http://www.gnu.org/licenses/>.
+
+ Karl Bartel
+ Cecilienstr. 14
+ 12307 Berlin
+ GERMANY
+ karlb@gmx.net
+*/
+
+/************************************************************************
+* SFONT - SDL Font Library by Karl Bartel <karlb@gmx.net> *
+* *
+* All functions are explained below. For further information, take a *
+* look at the example files, the links at the SFont web site, or *
+* contact me, if you problem isn' addressed anywhere. *
+* *
+************************************************************************/
+//////////////////////////////////////////////////////////////////////////////
+///@file SFont.h
+/// Text rendering system, that uses bitmaps as fonts.
+/// Not specific to Grafx2, it writes to SDL_Surface.
+//////////////////////////////////////////////////////////////////////////////
+
+
+#ifndef _SFONT_H_
+#define _SFONT_H_
+
+#include <SDL.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///
+/// Declare one variable of this type for each font you are using.
+/// To load the fonts, load the font image into YourFont->Surface
+/// and call InitFont( YourFont );
+typedef struct {
+ SDL_Surface *Surface;
+ int CharBegin[256];
+ int CharWidth[256];
+ int Space;
+ unsigned char Transparent;
+} SFont_Font;
+
+///
+/// Initializes the font.
+/// @param Font this contains the suface with the font.
+/// The Surface must be loaded before calling this function
+SFont_Font* SFont_InitFont (SDL_Surface *Font);
+
+///
+/// Frees the font.
+/// @param Font The font to free
+/// The font must be loaded before using this function.
+void SFont_FreeFont(SFont_Font* Font);
+
+///
+/// Blits a string to a surface.
+/// @param Surface The surface you want to blit to.
+/// @param Font The font to use.
+/// @param text A string containing the text you want to blit.
+/// @param x Coordinates to start drawing.
+/// @param y Coordinates to start drawing.
+void SFont_Write(SDL_Surface *Surface, const SFont_Font *Font, int x, int y,
+ const char *text);
+
+/// Returns the width of "text" in pixels
+int SFont_TextWidth(const SFont_Font* Font, const char *text);
+/// Returns the height of "text" in pixels (which is always equal to Font->Surface->h)
+int SFont_TextHeight(const SFont_Font* Font, const char *text);
+
+/// Blits a string to Surface with centered x position
+void SFont_WriteCenter(SDL_Surface *Surface, const SFont_Font* Font, int y,
+ const char *text);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SFONT_H */
View
1,944 project/jni/application/grafx2/grafx2/src/brush.c
@@ -0,0 +1,1944 @@
+/* vim:expandtab:ts=2 sw=2:
+*/
+/* Grafx2 - The Ultimate 256-color bitmap paint program
+
+ Copyright 2008 Franck Charlet
+ Copyright 2007-2008 Adrien Destugues
+ Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud)
+
+ Grafx2 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; version 2
+ of the License.
+
+ Grafx2 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 Grafx2; if not, see <http://www.gnu.org/licenses/>
+
+********************************************************************************
+
+ Brush manipulation functions
+*/
+
+#include <math.h>
+#include <stdlib.h>
+#include <string.h> // memset()
+
+#include "global.h"
+#include "graph.h"
+#include "misc.h"
+#include "errors.h"
+#include "windows.h"
+#include "sdlscreen.h"
+#include "brush.h"
+
+
+// Calcul de redimensionnement du pinceau pour éviter les débordements de
+// l'écran et de l'image
+void Compute_clipped_dimensions(short * x,short * y,short * width,short * height)
+{
+ if ((*x)<Limit_left)
+ {
+ (*width)-=(Limit_left-(*x));
+ (*x)=Limit_left;
+ }
+
+ if (((*x)+(*width))>(Limit_right+1))
+ {
+ (*width)=(Limit_right-(*x))+1;
+ }
+
+ if ((*y)<Limit_top)
+ {
+ (*height)-=(Limit_top-(*y));
+ (*y)=Limit_top;
+ }
+
+ if (((*y)+(*height))>(Limit_bottom+1))
+ {
+ (*height)=(Limit_bottom-(*y))+1;
+ }
+}
+
+ // -- Calcul de redimensionnement du pinceau pour éviter les débordements
+ // de l'écran zoomé et de l'image --
+
+void Compute_clipped_dimensions_zoom(short * x,short * y,short * width,short * height)
+{
+ if ((*x)<Limit_left_zoom)
+ {
+ (*width)-=(Limit_left_zoom-(*x));
+ (*x)=Limit_left_zoom;
+ }
+
+ if (((*x)+(*width))>(Limit_right_zoom+1))
+ {
+ (*width)=(Limit_right_zoom-(*x))+1;
+ }
+
+ if ((*y)<Limit_top_zoom)
+ {
+ (*height)-=(Limit_top_zoom-(*y));
+ (*y)=Limit_top_zoom;
+ }
+
+ if (((*y)+(*height))>(Limit_bottom_zoom+1))
+ {
+ (*height)=(Limit_bottom_zoom-(*y))+1;
+ }
+}
+
+
+ // -- Afficher le pinceau (de façon définitive ou non) --
+
+void Display_paintbrush(short x,short y,byte color,byte is_preview)
+ // x,y: position du centre du pinceau
+ // color: couleur à appliquer au pinceau
+ // is_preview: "Il ne faut l'afficher qu'à l'écran"
+{
+ short start_x; // Position X (dans l'image) à partir de laquelle on
+ // affiche la brosse/pinceau
+ short start_y; // Position Y (dans l'image) à partir de laquelle on
+ // affiche la brosse/pinceau
+ short width; // width dans l'écran selon laquelle on affiche la
+ // brosse/pinceau
+ short height; // height dans l'écran selon laquelle on affiche la
+ // brosse/pinceau
+ short start_x_counter; // Position X (dans la brosse/pinceau) à partir
+ // de laquelle on affiche la brosse/pinceau
+ short start_y_counter; // Position Y (dans la brosse/pinceau) à partir
+ // de laquelle on affiche la brosse/pinceau
+ short x_pos; // Position X (dans l'image) en cours d'affichage
+ short y_pos; // Position Y (dans l'image) en cours d'affichage
+ short counter_x; // Position X (dans la brosse/pinceau) en cours
+ // d'affichage
+ short counter_y; // Position Y (dans la brosse/pinceau) en cours
+ // d'affichage
+ short end_counter_x; // Position X ou s'arrête l'affichade de la
+ // brosse/pinceau
+ short end_counter_y; // Position Y ou s'arrête l'affichade de la
+ // brosse/pinceau
+ byte temp_color; // color de la brosse en cours d'affichage
+ int position;
+ byte * temp;
+
+ if (is_preview==0 || Mouse_K==0) // pas de curseur si on est en preview et
+ // en train de cliquer
+ switch (Paintbrush_shape)
+ {
+ case PAINTBRUSH_SHAPE_NONE : // No paintbrush. for colorpicker for example
+ break;
+ case PAINTBRUSH_SHAPE_POINT : // !!! TOUJOURS EN PREVIEW !!!
+ if ( (Paintbrush_X>=Limit_left)
+ && (Paintbrush_X<=Limit_right)
+ && (Paintbrush_Y>=Limit_top)
+ && (Paintbrush_Y<=Limit_bottom) )
+ {
+ Pixel_preview(Paintbrush_X,Paintbrush_Y,color);
+ Update_part_of_screen(x,y,1,1);
+ }
+ break;
+
+ case PAINTBRUSH_SHAPE_COLOR_BRUSH : // Brush en couleur
+
+ start_x=x-Brush_offset_X;
+ start_y=y-Brush_offset_Y;
+ width=Brush_width;
+ height=Brush_height;
+ Compute_clipped_dimensions(&start_x,&start_y,&width,&height);
+ if (width<=0 || height<=0)
+ break;
+ start_x_counter=start_x-(x-Brush_offset_X);
+ start_y_counter=start_y-(y-Brush_offset_Y);
+ end_counter_x=start_x_counter+width;
+ end_counter_y=start_y_counter+height;
+
+ if (is_preview != 0)
+ {
+ if ( (width>0) && (height>0) )
+ Display_brush_color(
+ start_x-Main_offset_X,
+ start_y-Main_offset_Y,
+ start_x_counter,
+ start_y_counter,
+ width,
+ height,
+ Back_color,
+ Brush_width
+ );
+
+ if (Main_magnifier_mode != 0)
+ {
+ Compute_clipped_dimensions_zoom(&start_x,&start_y,&width,
+ &height
+ );
+
+ start_x_counter=start_x-(x-Brush_offset_X);
+ start_y_counter=start_y-(y-Brush_offset_Y);
+
+ if ( (width>0) && (height>0) )
+ {
+ // Corrections dues au Zoom:
+ start_x=(start_x-Main_magnifier_offset_X)*Main_magnifier_factor;
+ start_y=(start_y-Main_magnifier_offset_Y)*Main_magnifier_factor;
+ height=start_y+(height*Main_magnifier_factor);
+ if (height>Menu_Y)
+ height=Menu_Y;
+
+ Display_brush_color_zoom(Main_X_zoom+start_x,start_y,
+ start_x_counter,start_y_counter,
+ width,height,Back_color,
+ Brush_width,
+ Horizontal_line_buffer);
+ }
+ }
+
+ Update_part_of_screen(x-Brush_offset_X,y-Brush_offset_Y,Brush_width,Brush_height);
+
+ }
+ else
+ {
+ if ((Smear_mode != 0) && (Shade_table==Shade_table_left))
+ {
+ if (Smear_start != 0)
+ {
+ if ((width>0) && (height>0))
+ {
+ Copy_part_of_image_to_another(
+ Main_screen, start_x, start_y, width, height,
+ Main_image_width, Smear_brush,
+ start_x_counter, start_y_counter,
+ Smear_brush_width
+ );
+
+ Update_part_of_screen(start_x,start_y,width,height);
+ }
+ Smear_start=0;
+ }
+ else
+ {
+ for (y_pos = start_y, counter_y = start_y_counter;
+ counter_y < end_counter_y;
+ y_pos++, counter_y++
+ )
+ for (x_pos = start_x, counter_x = start_x_counter;
+ counter_x < end_counter_x;
+ x_pos++, counter_x++
+ )
+ {
+ temp_color = Read_pixel_from_current_screen(
+ x_pos,y_pos
+ );
+ position = (counter_y * Smear_brush_width)+ counter_x;
+ if ( (Read_pixel_from_brush(counter_x,counter_y) != Back_color)
+ && (counter_y<Smear_max_Y) && (counter_x<Smear_max_X)
+ && (counter_y>=Smear_min_Y) && (counter_x>=Smear_min_X) )
+ Display_pixel(x_pos,y_pos,Smear_brush[position]);
+ Smear_brush[position]=temp_color;
+ }
+
+ Update_part_of_screen(start_x,start_y,width,height);
+ }
+
+ Smear_min_X=start_x_counter;
+ Smear_min_Y=start_y_counter;
+ Smear_max_X=end_counter_x;
+ Smear_max_Y=end_counter_y;
+ }
+ else
+ {
+ if (Shade_table==Shade_table_left)
+ for (y_pos=start_y,counter_y=start_y_counter;counter_y<end_counter_y;y_pos++,counter_y++)
+ for (x_pos=start_x,counter_x=start_x_counter;counter_x<end_counter_x;x_pos++,counter_x++)
+ {
+ temp_color=Read_pixel_from_brush(counter_x,counter_y);
+ if (temp_color!=Back_color)
+ Display_pixel(x_pos,y_pos,temp_color);
+ }
+ else
+ for (y_pos=start_y,counter_y=start_y_counter;counter_y<end_counter_y;y_pos++,counter_y++)
+ for (x_pos=start_x,counter_x=start_x_counter;counter_x<end_counter_x;x_pos++,counter_x++)
+ {
+ if (Read_pixel_from_brush(counter_x,counter_y)!=Back_color)
+ Display_pixel(x_pos,y_pos,color);
+ }
+ }
+ Update_part_of_screen(start_x,start_y,width,height);
+
+ }
+ break;
+ case PAINTBRUSH_SHAPE_MONO_BRUSH : // Brush monochrome
+ start_x=x-Brush_offset_X;
+ start_y=y-Brush_offset_Y;
+ width=Brush_width;
+ height=Brush_height;
+ Compute_clipped_dimensions(&start_x,&start_y,&width,&height);
+ start_x_counter=start_x-(x-Brush_offset_X);
+ start_y_counter=start_y-(y-Brush_offset_Y);
+ end_counter_x=start_x_counter+width;
+ end_counter_y=start_y_counter+height;
+ if (is_preview != 0)
+ {
+ if ( (width>0) && (height>0) )
+ Display_brush_mono(start_x-Main_offset_X,
+ start_y-Main_offset_Y,
+ start_x_counter,start_y_counter,
+ width,height,
+ Back_color,Fore_color,
+ Brush_width);
+
+ if (Main_magnifier_mode != 0)
+ {
+ Compute_clipped_dimensions_zoom(&start_x,&start_y,&width,&height);
+ start_x_counter=start_x-(x-Brush_offset_X);
+ start_y_counter=start_y-(y-Brush_offset_Y);
+
+ if ( (width>0) && (height>0) )
+ {
+ // Corrections dues au Zoom:
+ start_x=(start_x-Main_magnifier_offset_X)*Main_magnifier_factor;
+ start_y=(start_y-Main_magnifier_offset_Y)*Main_magnifier_factor;
+ height=start_y+(height*Main_magnifier_factor);
+ if (height>Menu_Y)
+ height=Menu_Y;
+
+ Display_brush_mono_zoom(Main_X_zoom+start_x,start_y,
+ start_x_counter,start_y_counter,
+ width,height,
+ Back_color,Fore_color,
+ Brush_width,
+ Horizontal_line_buffer);
+
+ }
+ }
+
+ Update_part_of_screen(x-Brush_offset_X,y-Brush_offset_Y,Brush_width,Brush_height);
+ }
+ else
+ {
+ if ((Smear_mode != 0) && (Shade_table==Shade_table_left))
+ {
+ if (Smear_start != 0)
+ {
+ if ((width>0) && (height>0))
+ {
+ Copy_part_of_image_to_another(Main_screen,
+ start_x,start_y,
+ width,height,
+ Main_image_width,
+ Smear_brush,
+ start_x_counter,
+ start_y_counter,
+ Smear_brush_width);
+ Update_part_of_screen(start_x,start_y,width,height);
+ }
+ Smear_start=0;
+ }
+ else
+ {
+ for (y_pos=start_y,counter_y=start_y_counter;counter_y<end_counter_y;y_pos++,counter_y++)
+ for (x_pos=start_x,counter_x=start_x_counter;counter_x<end_counter_x;x_pos++,counter_x++)
+ {
+ temp_color=Read_pixel_from_current_screen(x_pos,y_pos);
+ position=(counter_y*Smear_brush_width)+counter_x;
+ if ( (Read_pixel_from_brush(counter_x,counter_y)!=Back_color)
+ && (counter_y<Smear_max_Y) && (counter_x<Smear_max_X)
+ && (counter_y>=Smear_min_Y) && (counter_x>=Smear_min_X) )
+ Display_pixel(x_pos,y_pos,Smear_brush[position]);
+ Smear_brush[position]=temp_color;
+ }
+
+ Update_part_of_screen(start_x,start_y,width,height);
+
+ }
+
+ Smear_min_X=start_x_counter;
+ Smear_min_Y=start_y_counter;
+ Smear_max_X=end_counter_x;
+ Smear_max_Y=end_counter_y;
+ }
+ else
+ {
+ for (y_pos=start_y,counter_y=start_y_counter;counter_y<end_counter_y;y_pos++,counter_y++)
+ for (x_pos=start_x,counter_x=start_x_counter;counter_x<end_counter_x;x_pos++,counter_x++)
+ {
+ if (Read_pixel_from_brush(counter_x,counter_y)!=Back_color)
+ Display_pixel(x_pos,y_pos,color);
+ }
+ Update_part_of_screen(start_x,start_y,width,height);
+ }
+ }
+ break;
+ default : // Pinceau
+ start_x=x-Paintbrush_offset_X;
+ start_y=y-Paintbrush_offset_Y;
+ width=Paintbrush_width;
+ height=Paintbrush_height;
+ Compute_clipped_dimensions(&start_x,&start_y,&width,&height);
+ start_x_counter=start_x-(x-Paintbrush_offset_X);
+ start_y_counter=start_y-(y-Paintbrush_offset_Y);
+ end_counter_x=start_x_counter+width;
+ end_counter_y=start_y_counter+height;
+ if (is_preview != 0)
+ {
+ temp=Brush;
+ Brush=Paintbrush_sprite;
+
+ if ( (width>0) && (height>0) )
+ Display_brush_mono(start_x-Main_offset_X,
+ start_y-Main_offset_Y,
+ start_x_counter,start_y_counter,
+ width,height,
+ 0,Fore_color,
+ MAX_PAINTBRUSH_SIZE);
+
+ if (Main_magnifier_mode != 0)
+ {
+ Compute_clipped_dimensions_zoom(&start_x,&start_y,&width,&height);
+ start_x_counter=start_x-(x-Paintbrush_offset_X);
+ start_y_counter=start_y-(y-Paintbrush_offset_Y);
+
+ if ( (width>0) && (height>0) )
+ {
+ // Corrections dues au Zoom:
+ start_x=(start_x-Main_magnifier_offset_X)*Main_magnifier_factor;
+ start_y=(start_y-Main_magnifier_offset_Y)*Main_magnifier_factor;
+ height=start_y+(height*Main_magnifier_factor);
+ if (height>Menu_Y)
+ height=Menu_Y;
+
+ Display_brush_mono_zoom(Main_X_zoom+start_x,start_y,
+ start_x_counter,start_y_counter,
+ width,height,
+ 0,Fore_color,
+ MAX_PAINTBRUSH_SIZE,
+ Horizontal_line_buffer);
+
+ }
+ }
+
+ Brush=temp;
+ }
+ else
+ {
+ if ((Smear_mode != 0) && (Shade_table==Shade_table_left))
+ {
+ if (Smear_start != 0)
+ {
+ if ((width>0) && (height>0))
+ {
+ Copy_part_of_image_to_another(Main_screen,
+ start_x,start_y,
+ width,height,
+ Main_image_width,
+ Smear_brush,
+ start_x_counter,
+ start_y_counter,
+ Smear_brush_width);
+ Update_part_of_screen(start_x,start_y,width,height);
+ }
+ Smear_start=0;
+ }
+ else
+ {
+ for (y_pos=start_y,counter_y=start_y_counter;counter_y<end_counter_y;y_pos++,counter_y++)
+ for (x_pos=start_x,counter_x=start_x_counter;counter_x<end_counter_x;x_pos++,counter_x++)
+ {
+ temp_color=Read_pixel_from_current_screen(x_pos,y_pos);
+ position=(counter_y*Smear_brush_width)+counter_x;
+ if ( (Paintbrush_sprite[(MAX_PAINTBRUSH_SIZE*counter_y)+counter_x] != 0)
+ // Le pinceau sert de masque pour dire quels pixels on doit traiter dans le rectangle
+ && (counter_y<Smear_max_Y) && (counter_x<Smear_max_X)
+ && (counter_y>=Smear_min_Y) && (counter_x>=Smear_min_X)
+ // On clippe l'effet smear entre Smear_Min et Smear_Max
+ )
+ Display_pixel(x_pos,y_pos,Smear_brush[position]);
+ Smear_brush[position]=temp_color;
+ }
+ Update_part_of_screen(start_x, start_y, width, height);
+ }
+
+
+ Smear_min_X=start_x_counter;
+ Smear_min_Y=start_y_counter;
+ Smear_max_X=end_counter_x;
+ Smear_max_Y=end_counter_y;
+ }
+ else
+ {
+ for (y_pos=start_y,counter_y=start_y_counter;counter_y<end_counter_y;y_pos++,counter_y++)
+ for (x_pos=start_x,counter_x=start_x_counter;counter_x<end_counter_x;x_pos++,counter_x++)
+ {
+ if (Paintbrush_sprite[(MAX_PAINTBRUSH_SIZE*counter_y)+counter_x] != 0)
+ Display_pixel(x_pos,y_pos,color);
+ }
+ Update_part_of_screen(start_x,start_y,width,height);
+ }
+ }
+ }
+}
+
+/// @return 0 on success, non-zero on failure (memory?).
+/// @param new_brush: Optionally, you can provide an already allocated new
+/// brush - otherwise, this function performs the allocation.
+/// @param old_brush: If the caller passes NULL, this function will free the old
+/// pixel data. If the caller provides the address of a (free) byte
+/// pointer, the function will make it point to the original pixel data,
+/// in this case it will be the caller's responsibility to free() it
+/// (after transferring pixels to Brush, usually).
+byte Realloc_brush(word new_brush_width, word new_brush_height, byte *new_brush, byte **old_brush)
+{
+
+ byte *new_smear_brush;
+ byte *new_brush_remapped;
+ word new_smear_brush_width;
+ word new_smear_brush_height;
+ byte new_brush_is_provided;
+
+ new_brush_is_provided = (new_brush!=NULL);
+
+ if (!new_brush_is_provided)
+ {
+ new_brush=(byte *)malloc(((long)new_brush_height)*new_brush_width);
+ if (new_brush == NULL)
+ {
+ Error(0);
+ if (old_brush)
+ *old_brush=NULL;
+ return 1;
+ }
+ }
+
+ new_smear_brush_width=(new_brush_width>MAX_PAINTBRUSH_SIZE)?new_brush_width:MAX_PAINTBRUSH_SIZE;
+ new_smear_brush_height=(new_brush_height>MAX_PAINTBRUSH_SIZE)?new_brush_height:MAX_PAINTBRUSH_SIZE;
+ new_smear_brush=NULL;
+ if ( (((long)Smear_brush_height)*Smear_brush_width) !=
+ (((long)new_smear_brush_width)*new_smear_brush_height) )
+ {
+ new_smear_brush=(byte *)malloc(((long)new_smear_brush_height)*new_smear_brush_width);
+ if (new_smear_brush == NULL)
+ {
+ Error(0);
+ if (old_brush)
+ *old_brush=NULL;
+ if (!new_brush_is_provided)
+ free(new_brush);
+ return 2;
+ }
+ }
+ new_brush_remapped=NULL;
+ if ( (((long)Brush_height)*Brush_width) !=
+ (((long)new_brush_height)*new_brush_width) )
+ {
+ new_brush_remapped=(byte *)malloc(((long)new_brush_height)*new_brush_width);
+ if (new_brush_remapped == NULL)
+ {
+ Error(0);
+ free(new_smear_brush);
+ if (old_brush)
+ *old_brush=NULL;
+ if (!new_brush_is_provided)
+ free(new_brush);
+ return 3;
+ }
+ }
+
+ // All allocations successful: can replace globals
+ Brush_width=new_brush_width;
+ Brush_height=new_brush_height;
+ Brush_original_back_color=Back_color;
+
+ if (new_smear_brush)
+ {
+ free(Smear_brush);
+ Smear_brush=new_smear_brush;
+ }
+ Smear_brush_width=new_smear_brush_width;
+ Smear_brush_height=new_smear_brush_height;
+
+ // Save or free the old brush pixels
+ if (old_brush)
+ *old_brush=Brush_original_pixels;
+ else
+ free(old_brush);
+ Brush_original_pixels=new_brush;
+ // Assign new brush
+ if (new_brush_remapped)
+ {
+ free(Brush);
+ Brush=new_brush_remapped;
+ }
+ return 0;
+}
+
+
+// -- Effacer le pinceau -- //
+//
+void Hide_paintbrush(short x,short y)
+ // x,y: position du centre du pinceau
+{
+ short start_x; // Position X (dans l'image) à partir de laquelle on
+ // affiche la brosse/pinceau
+ short start_y; // Position Y (dans l'image) à partir de laquelle on
+ // affiche la brosse/pinceau
+ short width; // width dans l'écran selon laquelle on affiche la
+ // brosse/pinceau
+ short height; // height dans l'écran selon laquelle on affiche la
+ // brosse/pinceau
+ short start_x_counter; // Position X (dans la brosse/pinceau) à partir
+ // de laquelle on affiche la brosse/pinceau
+ short start_y_counter; // Position Y (dans la brosse/pinceau) à partir
+ // de laquelle on affiche la brosse/pinceau
+ //short x_pos; // Position X (dans l'image) en cours d'affichage
+ //short y_pos; // Position Y (dans l'image) en cours d'affichage
+ //short counter_x; // Position X (dans la brosse/pinceau) en cours
+ //d'affichage
+ //short counter_y; // Position Y (dans la brosse/pinceau) en cours d'affichage
+ short end_counter_x; // Position X ou s'arrête l'affichage de la brosse/pinceau
+ short end_counter_y; // Position Y ou s'arrête l'affichage de la brosse/pinceau
+ byte * temp;
+
+ if (Mouse_K == 0)
+ switch (Paintbrush_shape)
+ {
+ case PAINTBRUSH_SHAPE_POINT :
+ if ( (Paintbrush_X>=Limit_left)
+ && (Paintbrush_X<=Limit_right)
+ && (Paintbrush_Y>=Limit_top)
+ && (Paintbrush_Y<=Limit_bottom) )
+ {
+ Pixel_preview(Paintbrush_X,Paintbrush_Y,Read_pixel_from_current_screen(Paintbrush_X,Paintbrush_Y));
+ Update_part_of_screen(Paintbrush_X,Paintbrush_Y,1,1);
+ }
+ break;
+ case PAINTBRUSH_SHAPE_COLOR_BRUSH : // Brush en couleur
+ case PAINTBRUSH_SHAPE_MONO_BRUSH : // Brush monochrome
+ start_x=x-Brush_offset_X;
+ start_y=y-Brush_offset_Y;
+ width=Brush_width;
+ height=Brush_height;
+ Compute_clipped_dimensions(&start_x,&start_y,&width,&height);
+ start_x_counter=start_x-(x-Brush_offset_X);
+ start_y_counter=start_y-(y-Brush_offset_Y);
+ end_counter_x=start_x_counter+width;
+ end_counter_y=start_y_counter+height;
+
+ if ( (width>0) && (height>0) )
+ Clear_brush(start_x-Main_offset_X,
+ start_y-Main_offset_Y,
+ start_x_counter,start_y_counter,
+ width,height,Back_color,
+ Main_image_width);
+
+ if (Main_magnifier_mode != 0)
+ {
+ Compute_clipped_dimensions_zoom(&start_x,&start_y,&width,&height);
+ start_x_counter=start_x;
+ start_y_counter=start_y;
+
+ if ( (width>0) && (height>0) )
+ {
+ // Corrections dues au Zoom:
+ start_x=(start_x-Main_magnifier_offset_X)*Main_magnifier_factor;
+ start_y=(start_y-Main_magnifier_offset_Y)*Main_magnifier_factor;
+ height=start_y+(height*Main_magnifier_factor);
+ if (height>Menu_Y)
+ height=Menu_Y;
+
+ Clear_brush_scaled(Main_X_zoom+start_x,start_y,
+ start_x_counter,start_y_counter,
+ width,height,Back_color,
+ Main_image_width,
+ Horizontal_line_buffer);
+ }
+ }
+ break;
+ default: // Pinceau
+ start_x=x-Paintbrush_offset_X;
+ start_y=y-Paintbrush_offset_Y;
+ width=Paintbrush_width;
+ height=Paintbrush_height;
+ Compute_clipped_dimensions(&start_x,&start_y,&width,&height);
+ start_x_counter=start_x-(x-Paintbrush_offset_X);
+ start_y_counter=start_y-(y-Paintbrush_offset_Y);
+ end_counter_x=start_x_counter+width;
+ end_counter_y=start_y_counter+height;
+
+ temp=Brush;
+ Brush=Paintbrush_sprite;
+
+ if ( (width>0) && (height>0) )
+ {
+ Clear_brush(start_x-Main_offset_X,
+ start_y-Main_offset_Y,
+ start_x_counter,start_y_counter,
+ width,height,0,
+ Main_image_width);
+ }
+
+ if (Main_magnifier_mode != 0)
+ {
+ Compute_clipped_dimensions_zoom(&start_x,&start_y,&width,&height);
+ start_x_counter=start_x;
+ start_y_counter=start_y;
+
+ if ( (width>0) && (height>0) )
+ {
+ // Corrections dues au Zoom:
+ start_x=(start_x-Main_magnifier_offset_X)*Main_magnifier_factor;
+ start_y=(start_y-Main_magnifier_offset_Y)*Main_magnifier_factor;
+ height=start_y+(height*Main_magnifier_factor);
+ if (height>Menu_Y)
+ height=Menu_Y;
+
+ Clear_brush_scaled(Main_X_zoom+start_x,start_y,
+ start_x_counter,start_y_counter,
+ width,height,0,
+ Main_image_width,
+ Horizontal_line_buffer);
+ }
+ }
+
+ Brush=temp;
+ break;
+ }
+}
+
+
+
+void Capture_brush(short start_x,short start_y,short end_x,short end_y,short clear)
+{
+ short temp;
+ short x_pos;
+ short y_pos;
+ word new_brush_width;
+ word new_brush_height;
+
+
+ // On commence par "redresser" les bornes:
+ if (start_x>end_x)
+ {
+ temp=start_x;
+ start_x =end_x;
+ end_x =temp;
+ }
+ if (start_y>end_y)
+ {
+ temp=start_y;
+ start_y =end_y;
+ end_y =temp;
+ }
+
+ // On ne capture la nouvelle brosse que si elle est au moins partiellement
+ // dans l'image:
+
+ if ((start_x<Main_image_width) && (start_y<Main_image_height))
+ {
+ // On met les décalages du tiling à 0 pour eviter toute incohérence.
+ // Si par hasard on voulait les mettre à
+ // min(Tiling_Decalage_?,Brosse_?a??eur-1)
+ // il faudrait penser à les initialiser à 0 dans "MAIN.C".
+ Tiling_offset_X=0;
+ Tiling_offset_Y=0;
+
+ // Ensuite, on calcule les dimensions de la brosse:
+ new_brush_width=(end_x-start_x)+1;
+ new_brush_height=(end_y-start_y)+1;
+
+ if (start_x+new_brush_width>Main_image_width)
+ new_brush_width=Main_image_width-start_x;
+ if (start_y+new_brush_height>Main_image_height)
+ new_brush_height=Main_image_height-start_y;
+
+ if (Realloc_brush(new_brush_width, new_brush_height, NULL, NULL))
+ return; // Unable to allocate the new brush, keep the old one.
+
+ Copy_image_to_brush(start_x,start_y,Brush_width,Brush_height,Main_image_width);
+
+ // On regarde s'il faut effacer quelque chose:
+ if (clear != 0)
+ {
+ for (y_pos=start_y;y_pos<start_y+Brush_height;y_pos++)
+ for (x_pos=start_x;x_pos<start_x+Brush_width;x_pos++)
+ {
+ Pixel_in_current_screen(x_pos,y_pos,Back_color,1);
+ }
+ Update_part_of_screen(start_x,start_y,Brush_width,Brush_height);
+ }
+ // Grab palette
+ memcpy(Brush_original_palette, Main_palette,sizeof(T_Palette));
+ // Remap (no change)
+ Remap_brush();
+
+ // On centre la prise sur la brosse
+ Brush_offset_X=(Brush_width>>1);
+ Brush_offset_Y=(Brush_height>>1);
+ }
+}
+
+
+void Rotate_90_deg(void)
+{
+ byte * old_brush;
+
+ if (Realloc_brush(Brush_height, Brush_width, NULL, &old_brush))
+ {
+ Error(0);
+ return;
+ }
+ Rotate_90_deg_lowlevel(old_brush,Brush_original_pixels,Brush_height,Brush_width);
+
+ free(old_brush);
+
+ // Remap according to the last used remap table
+ Remap_general_lowlevel(Brush_colormap,Brush_original_pixels,Brush,Brush_width,Brush_height,Brush_width);
+
+ // On centre la prise sur la brosse
+ Brush_offset_X=(Brush_width>>1);
+ Brush_offset_Y=(Brush_height>>1);
+}
+
+
+void Remap_brush(void)
+{
+ short x_pos; // Variable de balayage de la brosse
+ short y_pos; // Variable de balayage de la brosse
+ int color;
+
+
+ // On commence par initialiser le tableau de booléens à faux
+ for (color=0;color<=255;color++)
+ Brush_colormap[color]=0;
+
+ // On calcule la table d'utilisation des couleurs
+ for (y_pos=0;y_pos<Brush_height;y_pos++)
+ for (x_pos=0;x_pos<Brush_width;x_pos++)
+ Brush_colormap[*(Brush_original_pixels + y_pos * Brush_width + x_pos)]=1;
+
+ // On n'est pas censé remapper la couleur de transparence, sinon la brosse
+ // changera de forme, donc on dit pour l'instant qu'elle n'est pas utilisée
+ // ainsi on ne s'embêtera pas à la recalculer
+ Brush_colormap[Back_color]=0;
+
+ // On va maintenant se servir de la table comme table de
+ // conversion: pour chaque indice, la table donne une couleur de
+ // remplacement.
+ // Note : Seules les couleurs utilisées on besoin d'êtres recalculées: les
+ // autres ne seront jamais consultées dans la nouvelle table de
+ // conversion puisque elles n'existent pas dans la brosse, donc elles
+ // ne seront pas utilisées par Remap_general_lowlevel.
+ for (color=0;color<=255;color++)
+ if (Brush_colormap[color] != 0)
+ {
+ byte r,g,b;
+ r=Brush_original_palette[color].R;
+ g=Brush_original_palette[color].G;
+ b=Brush_original_palette[color].B;
+
+ // When remapping to same palette, ensure we keep same color index
+ if (r==Main_palette[color].R && g==Main_palette[color].G && b==Main_palette[color].B)
+ Brush_colormap[color]=color;
+ else
+ // Usual method: closest by r g b
+ Brush_colormap[color]=Best_color_perceptual_except(r,g,b,Back_color);
+ }
+
+ // Il reste une couleur non calculée dans la table qu'il faut mettre à
+ // jour: c'est la couleur de fond. On l'avait inhibée pour éviter son
+ // calcul inutile, mais comme il est possible qu'elle soit quand même dans
+ // la brosse, on va mettre dans la table une relation d'équivalence entre
+ // les deux palettes: comme on ne veut pas que la couleur soit remplacée,
+ // on va dire qu'on veut qu'elle soit remplacée par la couleur en question.
+ Brush_colormap[Back_color]=Back_color;
+
+ // Maintenant qu'on a une super table de conversion qui n'a que le nom
+ // qui craint un peu, on peut faire l'échange dans la brosse de toutes les
+ // teintes.
+ Remap_general_lowlevel(Brush_colormap,Brush_original_pixels,Brush,Brush_width,Brush_height,Brush_width);
+
+}
+
+
+
+void Outline_brush(void)
+{
+ long /*Pos,*/x_pos,y_pos;
+ byte state;
+ byte * old_brush;
+ word old_width;
+ word old_height;
+ int i;
+
+ old_width=Brush_width;
+ old_height=Brush_height;
+
+ SWAP_PBYTES(Brush, Brush_original_pixels);
+ if(Realloc_brush(Brush_width+2, Brush_height+2, NULL, &old_brush))
+ {
+ Error(0);
+ SWAP_PBYTES(Brush, Brush_original_pixels);
+ return;
+ }
+
+ // On remplit la bordure ajoutée par la Backcolor
+ memset(Brush,Back_color,((long)Brush_width)*Brush_height);
+
+ // On copie la brosse courante dans la nouvelle
+ Copy_part_of_image_to_another(old_brush, // source
+ 0, 0, old_width, old_height, old_width,
+ Brush, // Destination
+ 1, 1, Brush_width);
+
+ // Si on "outline" avec une couleur différente de la Back_color on y va!
+ if (Fore_color!=Back_color)
+ {
+ // 1er balayage (horizontal)
+ for (y_pos=1; y_pos<Brush_height-1; y_pos++)
+ {
+ state=0;
+ for (x_pos=1; x_pos<Brush_width-1; x_pos++)
+ {
+ if (old_brush[((y_pos-1)*old_width)+x_pos-1]==Back_color)
+ {
+ if (state != 0)
+ {
+ Pixel_in_brush(x_pos,y_pos,Fore_color);
+ state=0;
+ }
+ }
+ else if (state == 0)
+ {
+ Pixel_in_brush(x_pos-1,y_pos,Fore_color);
+ state=1;
+ }
+ }
+ // Cas du dernier pixel à droite de la ligne
+ if (state != 0)
+ Pixel_in_brush(x_pos,y_pos,Fore_color);
+ }
+
+ // 2ème balayage (vertical)
+ for (x_pos=1; x_pos<Brush_width-1; x_pos++)
+ {
+ state=0;
+ for (y_pos=1; y_pos<Brush_height-1; y_pos++)
+ {
+ if (old_brush[((y_pos-1)*old_width)+x_pos-1]==Back_color)
+ {
+ if (state != 0)
+ {
+ Pixel_in_brush(x_pos,y_pos,Fore_color);
+ state=0;
+ }
+ }
+ else if (state == 0)
+ {
+ Pixel_in_brush(x_pos,y_pos-1,Fore_color);
+ state=1;
+ }
+ }
+ // Cas du dernier pixel en bas de la colonne
+ if (state != 0)
+ Pixel_in_brush(x_pos,y_pos,Fore_color);
+ }
+ }
+ // Adopt the current palette.
+ memcpy(Brush_original_palette, Main_palette,sizeof(T_Palette));
+ memcpy(Brush_original_pixels, Brush, (long)Brush_width*Brush_height);
+ for (i=0; i<256; i++)
+ Brush_colormap[i]=i;
+ //--
+
+ // On recentre la prise sur la brosse
+ Brush_offset_X=(Brush_width>>1);
+ Brush_offset_Y=(Brush_height>>1);
+
+ free(old_brush); // Libération de l'ancienne brosse
+
+}
+
+
+void Nibble_brush(void)
+{
+ long x_pos,y_pos;
+ byte state;
+ byte * old_brush;
+ word old_width;
+ word old_height;
+ int i;
+
+ if ( (Brush_width>2) && (Brush_height>2) )
+ {
+ old_width=Brush_width;
+ old_height=Brush_height;
+
+ SWAP_PBYTES(Brush, Brush_original_pixels);
+ if (Realloc_brush(Brush_width-2, Brush_height-2, NULL, &old_brush))
+ {
+ Error(0);
+ SWAP_PBYTES(Brush, Brush_original_pixels);
+ return;
+ }
+ // On copie l'ancienne brosse dans la nouvelle
+ Copy_part_of_image_to_another(old_brush, // source
+ 1,
+ 1,
+ old_width-2,
+ old_height-2,
+ old_width,
+ Brush, // Destination
+ 0,
+ 0,
+ Brush_width);
+
+ // 1er balayage (horizontal)
+ for (y_pos=0; y_pos<Brush_height; y_pos++)
+ {
+ state=(old_brush[(y_pos+1)*old_width]!=Back_color);
+ for (x_pos=0; x_pos<Brush_width; x_pos++)
+ {
+ if (old_brush[((y_pos+1)*old_width)+x_pos+1]==Back_color)
+ {
+ if (state != 0)
+ {
+ if (x_pos>0)
+ Pixel_in_brush(x_pos-1,y_pos,Back_color);
+ state=0;
+ }
+ }
+ else
+ {
+ if (state == 0)
+ {
+ Pixel_in_brush(x_pos,y_pos,Back_color);
+ state=1;
+ }
+ }
+ }
+ // Cas du dernier pixel à droite de la ligne
+ if (old_brush[((y_pos+1)*old_width)+x_pos+1]==Back_color)
+ Pixel_in_brush(x_pos-1,y_pos,Back_color);
+ }
+
+ // 2ème balayage (vertical)
+ for (x_pos=0; x_pos<Brush_width; x_pos++)
+ {
+ state=(old_brush[old_width+x_pos+1]!=Back_color);;
+ for (y_pos=0; y_pos<Brush_height; y_pos++)
+ {
+ if (old_brush[((y_pos+1)*old_width)+x_pos+1]==Back_color)
+ {
+ if (state)
+ {
+ if (y_pos>0)
+ Pixel_in_brush(x_pos,y_pos-1,Back_color);
+ state=0;
+ }
+ }
+ else
+ {
+ if (state == 0)
+ {
+ Pixel_in_brush(x_pos,y_pos,Back_color);
+ state=1;
+ }
+ }
+ }
+ // Cas du dernier pixel en bas de la colonne
+ if (old_brush[((y_pos+1)*old_width)+x_pos+1]==Back_color)
+ Pixel_in_brush(x_pos,y_pos-1,Back_color);
+ }
+
+ free(old_brush);
+ // Adopt the current palette.
+ memcpy(Brush_original_palette, Main_palette,sizeof(T_Palette));
+ memcpy(Brush_original_pixels, Brush, (long)Brush_width*Brush_height);
+ for (i=0; i<256; i++)
+ Brush_colormap[i]=i;
+ //--
+
+ // On recentre la prise sur la brosse
+ Brush_offset_X=(Brush_width>>1);
+ Brush_offset_Y=(Brush_height>>1);
+
+ }
+}
+
+
+
+void Capture_brush_with_lasso(int vertices, short * points,short clear)
+{
+ short start_x=Limit_right+1;
+ short start_y=Limit_bottom+1;
+ short end_x=Limit_left-1;
+ short end_y=Limit_top-1;
+ unsigned short temp;
+ short x_pos;
+ short y_pos;
+ word new_brush_width;
+ word new_brush_height;
+
+ // On recherche les bornes de la brosse:
+ for (temp=0; temp<2*vertices; temp+=2)
+ {
+ x_pos=points[temp];
+ y_pos=points[temp+1];
+ if (x_pos<start_x)
+ start_x=x_pos;
+ if (x_pos>end_x)
+ end_x=x_pos;
+ if (y_pos<start_y)
+ start_y=y_pos;
+ if (y_pos>end_y)
+ end_y=y_pos;
+ }
+
+ // On clippe ces bornes à l'écran:
+ if (start_x<Limit_left)
+ start_x=Limit_left;
+ if (end_x>Limit_right)
+ end_x=Limit_right;
+ if (start_y<Limit_top)
+ start_y=Limit_top;
+ if (end_y>Limit_bottom)
+ end_y=Limit_bottom;
+
+ // On ne capture la nouvelle brosse que si elle est au moins partiellement
+ // dans l'image:
+
+ if ((start_x<Main_image_width) && (start_y<Main_image_height))
+ {
+ // On met les décalages du tiling à 0 pour eviter toute incohérence.
+ // Si par hasard on voulait les mettre à
+ // min(Tiling_Decalage_?,Brosse_?a??eur-1)
+ // il faudrait penser à les initialiser à 0 dans "MAIN.C".
+ Tiling_offset_X=0;
+ Tiling_offset_Y=0;
+
+ // Ensuite, on calcule les dimensions de la brosse:
+ new_brush_width=(end_x-start_x)+1;
+ new_brush_height=(end_y-start_y)+1;
+
+ if (Realloc_brush(new_brush_width, new_brush_height, NULL, NULL))
+ {
+ Error(0);
+ return;
+ }
+
+ Brush_offset_X=start_x;
+ Brush_offset_Y=start_y;
+
+ Pixel_figure=Pixel_figure_in_brush;
+
+ memset(Brush,Back_color,(long)Brush_width*Brush_height);
+ Polyfill_general(vertices,points,~Back_color);
+
+ // On retrace les bordures du lasso:
+ for (temp=1; temp<vertices; temp++)
+ {
+ Draw_line_general(points[(temp-1)<<1],points[((temp-1)<<1)+1],
+ points[temp<<1],points[(temp<<1)+1],
+ ~Back_color);
+ }
+ Draw_line_general(points[(vertices-1)<<1],points[((vertices-1)<<1)+1],
+ points[0],points[1],
+ ~Back_color);
+
+ // On scanne la brosse pour remplacer tous les pixels affectés par le
+ // polyfill par ceux de l'image:
+ for (y_pos=start_y;y_pos<=end_y;y_pos++)
+ for (x_pos=start_x;x_pos<=end_x;x_pos++)
+ if (Read_pixel_from_brush(x_pos-start_x,y_pos-start_y)!=Back_color)
+ {
+ Pixel_in_brush(x_pos-start_x,y_pos-start_y,Read_pixel_from_current_layer(x_pos,y_pos));
+ // On regarde s'il faut effacer quelque chose:
+ if (clear)
+ Pixel_in_current_screen(x_pos,y_pos,Back_color,0);
+ }
+ // Grab palette
+ memcpy(Brush_original_palette, Main_palette,sizeof(T_Palette));
+ // Init colormap
+ for (temp=0; temp<256; temp++)
+ Brush_colormap[temp]=temp;
+ // Copy Brush to original
+ memcpy(Brush_original_pixels, Brush, (long)Brush_width*Brush_height);
+
+ // On centre la prise sur la brosse
+ Brush_offset_X=(Brush_width>>1);
+ Brush_offset_Y=(Brush_height>>1);
+ }
+}
+
+
+
+//------------------------- Etirement de la brosse ---------------------------
+
+void Stretch_brush(short x1, short y1, short x2, short y2)
+{
+ byte * new_brush;
+ int new_brush_width; // Width de la nouvelle brosse
+ int new_brush_height; // Height de la nouvelle brosse
+ int x_flipped, y_flipped;
+
+ // Compute new brush dimensions
+ if ((new_brush_width=x1-x2)<0)
+ {
+ x_flipped=1;
+ new_brush_width=-new_brush_width;
+ }
+ new_brush_width++;
+
+ if ((new_brush_height=y1-y2)<0)
+ {
+ y_flipped=1;
+ new_brush_height=-new_brush_height;
+ }
+ new_brush_height++;
+
+ new_brush=((byte *)malloc(new_brush_width*new_brush_height));
+ if (!new_brush)
+ {
+ Error(0);
+ return;
+ }
+
+ Rescale(Brush_original_pixels, Brush_width, Brush_height, new_brush, new_brush_width, new_brush_height, x2<x1, y2<y1);
+
+ if (Realloc_brush(new_brush_width, new_brush_height, new_brush, NULL))
+ {
+ free(new_brush);
+ Error(0);
+ return;
+ }
+ // Remap according to the last used remap table
+ Remap_general_lowlevel(Brush_colormap,Brush_original_pixels,Brush,Brush_width,Brush_height,Brush_width);
+
+ Brush_offset_X=(Brush_width>>1);
+ Brush_offset_Y=(Brush_height>>1);
+
+}
+
+
+
+void Stretch_brush_preview(short x1, short y1, short x2, short y2)
+{
+ int src_x_pos,src_y_pos;
+ int initial_src_x_pos,initial_src_y_pos;
+ int delta_x,delta_y;
+ int dest_x_pos,dest_y_pos;
+ int initial_dest_x_pos,initial_dest_y_pos;
+ int final_dest_x_pos,final_dest_y_pos;
+ int dest_width,dest_height;
+ byte color;
+
+
+ // 1er calcul des positions destination extremes:
+ initial_dest_x_pos=Min(x1,x2);
+ initial_dest_y_pos=Min(y1,y2);
+ final_dest_x_pos =Max(x1,x2);
+ final_dest_y_pos =Max(y1,y2);
+
+ // Calcul des dimensions de la destination:
+ dest_width=final_dest_x_pos-initial_dest_x_pos+1;
+ dest_height=final_dest_y_pos-initial_dest_y_pos+1;
+
+ // Calcul des vecteurs d'incrémentation :
+ delta_x=(Brush_width<<16)/dest_width;
+ delta_y=(Brush_height<<16)/dest_height;
+
+ // 1er calcul de la position X initiale dans la source:
+ initial_src_x_pos=(Brush_width<<16)*
+ (Max(initial_dest_x_pos,Limit_left)-
+ initial_dest_x_pos)/dest_width;
+ // Calcul du clip de la destination:
+ initial_dest_x_pos=Max(initial_dest_x_pos,Limit_left);
+ final_dest_x_pos =Min(final_dest_x_pos ,Limit_visible_right);
+ // On discute selon l'inversion en X
+ if (x1>x2)
+ {
+ // Inversion -> Inversion du signe de delta_x
+ delta_x=-delta_x;
+ initial_src_x_pos=(Brush_width<<16)-1-initial_src_x_pos;
+ }
+
+ // 1er calcul de la position Y initiale dans la source:
+ initial_src_y_pos=(Brush_height<<16)*
+ (Max(initial_dest_y_pos,Limit_top)-
+ initial_dest_y_pos)/dest_height;
+ // Calcul du clip de la destination:
+ initial_dest_y_pos=Max(initial_dest_y_pos,Limit_top);
+ final_dest_y_pos =Min(final_dest_y_pos ,Limit_visible_bottom);
+ // On discute selon l'inversion en Y
+ if (y1>y2)
+ {
+ // Inversion -> Inversion du signe de delta_y
+ delta_y=-delta_y;
+ initial_src_y_pos=(Brush_height<<16)-1-initial_src_y_pos;
+ }
+
+ // Pour chaque ligne :
+ src_y_pos=initial_src_y_pos;
+ for (dest_y_pos=initial_dest_y_pos;dest_y_pos<=final_dest_y_pos;dest_y_pos++)
+ {
+ // Pour chaque colonne:
+ src_x_pos=initial_src_x_pos;
+ for (dest_x_pos=initial_dest_x_pos;dest_x_pos<=final_dest_x_pos;dest_x_pos++)
+ {
+ color=Read_pixel_from_brush(src_x_pos>>16,src_y_pos>>16);
+ if (color!=Back_color)
+ Pixel_preview(dest_x_pos,dest_y_pos,color);
+
+ src_x_pos+=delta_x;
+ }
+
+ src_y_pos+=delta_y;
+ }
+ Update_part_of_screen(initial_dest_x_pos,initial_dest_y_pos,dest_width,dest_height);
+}
+
+/// Returns the minimum of 4 integers.
+int Min4(long int a, long int b, long int c, long int d)
+{
+ if (a<b)
+ if (c<d)
+ return a<c?a:c;
+ else
+ return a<d?a:d;
+ else
+ if (c<d)
+ return b<c?b:c;
+ else
+ return b<d?b:d;
+}
+
+//-------------------- Brush distort -------------------------------
+
+// That's a lot of globals, but it saves stack space in the recursive calls.
+static Func_pixel Pixel_for_distort;
+static byte * Distort_buffer;
+static short Distort_buffer_width;
+
+/// Draw a pixel in the target buffer. No clipping.
+void Pixel_in_distort_buffer(word x_pos,word y_pos,byte color)
+{
+ *(Distort_buffer+y_pos*Distort_buffer_width+x_pos)=color;
+}
+
+/// Returns the maximum of 4 integers.
+int Max4( long int a, long int b, long int c, long int d)
+{
+ if (a>b)
+ if (c>d)
+ return a>c?a:c;
+ else
+ return a>d?a:d;
+ else
+ if (c>d)
+ return b>c?b:c;
+ else
+ return b>d?b:d;
+}
+
+// Recursive function for linear distortion.
+void Draw_brush_linear_distort(unsigned long int tex_min_x,
+ unsigned long int tex_min_y,
+ unsigned long int tex_max_x,
+ unsigned long int tex_max_y,
+ long int x1,
+ long int y1,
+ long int x2,
+ long int y2,
+ long int x3,
+ long int y3,
+ long int x4,
+ long int y4)
+{
+ static byte color;
+ // bounding rectangle
+ static long int min_x, max_x, min_y, max_y;
+
+ min_x=Min4(x1,x2,x3,x4);
+ max_x=Max4(x1,x2,x3,x4);
+ min_y=Min4(y1,y2,y3,y4);
+ max_y=Max4(y1,y2,y3,y4);
+
+ if ((max_x>>16) - (min_x>>16) <= 1 && (max_y>>16) - (min_y>>16) <= 1)
+ //if (max_x - min_x <= 1<<16 && max_y - min_y <= 1<<16)
+ {
+ if ((min_x<(max_x&0x7FFF0000)) && (min_y<(max_y&0x7FFF0000)))
+ {
+ color=Read_pixel_from_brush((tex_min_x)>>16,(tex_min_y)>>16);
+ if (color!=Back_color)
+ Pixel_for_distort(min_x>>16,min_y>>16,color);
+ }
+ return;
+ }
+ // Cut in 4 quarters and repeat
+ // "top left"
+ Draw_brush_linear_distort(tex_min_x,
+ tex_min_y,
+ (tex_min_x+tex_max_x)>>1,
+ (tex_min_y+tex_max_y)>>1,
+ x1,
+ y1,
+ (x1+x2)>>1,
+ (y1+y2)>>1,
+ (x1+x2+x3+x4)>>2,
+ (y1+y2+y3+y4)>>2,
+ (x1+x4)>>1,
+ (y1+y4)>>1);
+
+ // "top right"
+ Draw_brush_linear_distort((tex_min_x+tex_max_x)>>1,
+ tex_min_y,
+ tex_max_x,
+ (tex_min_y+tex_max_y)>>1,
+ (x1+x2)>>1,
+ (y1+y2)>>1,
+ x2,
+ y2,
+ (x2+x3)>>1,
+ (y2+y3)>>1,
+ (x1+x2+x3+x4)>>2,
+ (y1+y2+y3+y4)>>2);
+
+ // "bottom right"
+ Draw_brush_linear_distort((tex_min_x+tex_max_x)>>1,
+ (tex_min_y+tex_max_y)>>1,
+ tex_max_x,
+ tex_max_y,
+ (x1+x2+x3+x4)>>2,
+ (y1+y2+y3+y4)>>2,
+ (x2+x3)>>1,
+ (y2+y3)>>1,
+ x3,
+ y3,
+ (x3+x4)>>1,
+ (y3+y4)>>1);
+
+ // "bottom left"
+ Draw_brush_linear_distort(tex_min_x,
+ (tex_min_y+tex_max_y)>>1,
+ (tex_min_x+tex_max_x)>>1,
+ tex_max_y,
+ (x1+x4)>>1,
+ (y1+y4)>>1,
+ (x1+x2+x3+x4)>>2,
+ (y1+y2+y3+y4)>>2,
+ (x3+x4)>>1,
+ (y3+y4)>>1,
+ x4,
+ y4);
+
+ return;
+}
+
+/// Draws a distorted version of the brush, mapped over the given quad (picture coordinates).
+void Distort_brush_preview(short x1, short y1, short x2, short y2, short x3, short y3, short x4, short y4)
+{
+ Pixel_for_distort=Pixel_figure_preview;
+ Draw_brush_linear_distort(0, 0, (Brush_width<<16), (Brush_height<<16), (x1<<16), (y1<<16), (x2<<16), (y2<<16), (x3<<16), (y3<<16), (x4<<16), (y4<<16));
+}
+
+/// Modifies the current brush, mapping it over the given quad.
+void Distort_brush(short x1, short y1, short x2, short y2, short x3, short y3, short x4, short y4)
+{
+ short min_x, max_x, min_y, max_y;
+ short width, height;
+ byte * new_brush;
+
+ // Move all coordinates to start on (0,0)
+ min_x=Min4(x1,x2,x3,x4);
+ max_x=Max4(x1,x2,x3,x4);
+ min_y=Min4(y1,y2,y3,y4);
+ max_y=Max4(y1,y2,y3,y4);
+
+ x1-=min_x;
+ x2-=min_x;
+ x3-=min_x;
+ x4-=min_x;
+
+ y1-=min_y;
+ y2-=min_y;
+ y3-=min_y;
+ y4-=min_y;
+
+ width=Max(max_x-min_x, 1);
+ height=Max(max_y-min_y, 1);
+
+ new_brush=((byte *)malloc((long)width*height));
+ if (!new_brush)
+ {
+ // Out of memory while allocating new brush
+ Error(0);
+ return;
+ }
+
+ // Fill the new brush with backcolor, originally.
+ memset(new_brush,Back_color,((long)width)*height);
+
+ // Call distort routine
+ Pixel_for_distort=Pixel_in_distort_buffer;
+ Distort_buffer=new_brush;
+ Distort_buffer_width=width;
+ Draw_brush_linear_distort(0, 0, (Brush_width<<16), (Brush_height<<16), (x1<<16), (y1<<16), (x2<<16), (y2<<16), (x3<<16), (y3<<16), (x4<<16), (y4<<16));
+
+ if (Realloc_brush(width, height, new_brush, NULL))
+ {
+ free(new_brush);
+ Error(0);
+ return;
+ }
+ // Remap according to the last used remap table
+ Remap_general_lowlevel(Brush_colormap,Brush_original_pixels,Brush,Brush_width,Brush_height,Brush_width);
+
+ // Re-center brush handle
+ Brush_offset_X=(Brush_width>>1);
+ Brush_offset_Y=(Brush_height>>1);
+
+}
+
+//------------------------- Rotation de la brosse ---------------------------
+
+#ifndef NAN
+ #define NAN (-1.0e20F)
+ #define isnan(x) ((x)==NAN)
+#endif
+float * ScanY_Xt[2];
+float * ScanY_Yt[2];
+float * ScanY_X[2];
+
+
+void Interpolate_texture(int start_x,int start_y,int xt1,int yt1,
+ int end_x ,int end_y ,int xt2,int yt2,int height)
+{
+ int x_pos,y_pos;
+ int incr_x,incr_y;
+ int i,cumul;
+ int delta_x,delta_y;
+ int delta_xt=xt2-xt1;
+ int delta_yt=yt2-yt1;
+ int delta_x2=end_x-start_x;
+ int delta_y2=end_y-start_y;
+ float xt,yt;
+
+
+ x_pos=start_x;
+ y_pos=start_y;
+
+ if (start_x<end_x)
+ {
+ incr_x=+1;
+ delta_x=delta_x2;
+ }
+ else
+ {
+ incr_x=-1;
+ delta_x=-delta_x2;
+ }
+
+ if (start_y<end_y)
+ {
+ incr_y=+1;
+ delta_y=delta_y2;
+ }
+ else
+ {
+ incr_y=-1;
+ delta_y=-delta_y2;
+ }
+
+ if (delta_x>delta_y)
+ {
+ cumul=delta_x>>1;
+ for (i=0; i<=delta_x; i++)
+ {
+ if (cumul>=delta_x)
+ {
+ cumul-=delta_x;
+ y_pos+=incr_y;
+ }
+
+ if ((y_pos>=0) && (y_pos<height))
+ {
+ xt=(((float)((x_pos-start_x)*delta_xt))/(float)delta_x2) + (float)xt1;
+ yt=(((float)((x_pos-start_x)*delta_yt))/(float)delta_x2) + (float)yt1;
+ if (isnan(ScanY_X[0][y_pos])) // Gauche non défini
+ {
+ ScanY_X[0][y_pos]=(float)x_pos;
+ ScanY_Xt[0][y_pos]=xt;
+ ScanY_Yt[0][y_pos]=yt;
+ }
+ else
+ {
+ if ((float)x_pos>=ScanY_X[0][y_pos])
+ {
+ if (isnan(ScanY_X[1][y_pos]) // Droit non défini
+ || (x_pos>ScanY_X[1][y_pos]))
+ {
+ ScanY_X[1][y_pos]=(float)x_pos;
+ ScanY_Xt[1][y_pos]=xt;
+ ScanY_Yt[1][y_pos]=yt;
+ }
+ }
+ else
+ {
+ if (isnan(ScanY_X[1][y_pos])) // Droit non défini
+ {
+ ScanY_X[1][y_pos]=ScanY_X[0][y_pos];
+ ScanY_Xt[1][y_pos]=ScanY_Xt[0][y_pos];
+ ScanY_Yt[1][y_pos]=ScanY_Yt[0][y_pos];
+ ScanY_X[0][y_pos]=(float)x_pos;
+ ScanY_Xt[0][y_pos]=xt;
+ ScanY_Yt[0][y_pos]=yt;
+ }
+ else
+ {
+ ScanY_X[0][y_pos]=(float)x_pos;
+ ScanY_Xt[0][y_pos]=xt;
+ ScanY_Yt[0][y_pos]=yt;
+ }
+ }
+ }
+ }
+ x_pos+=incr_x;
+ cumul+=delta_y;
+ }
+ }
+ else
+ {
+ cumul=delta_y>>1;
+ for (i=0; i<=delta_y; i++)
+ {
+ if (cumul>=delta_y)
+ {
+ cumul-=delta_y;
+ x_pos+=incr_x;
+ }
+
+ if ((y_pos>=0) && (y_pos<height))
+ {
+ xt=(((float)((y_pos-start_y)*delta_xt))/(float)delta_y2) + (float)xt1;
+ yt=(((float)((y_pos-start_y)*delta_yt))/(float)delta_y2) + (float)yt1;
+ if (isnan(ScanY_X[0][y_pos])) // Gauche non défini
+ {
+ ScanY_X[0][y_pos]=(float)x_pos;
+ ScanY_Xt[0][y_pos]=xt;
+ ScanY_Yt[0][y_pos]=yt;
+ }
+ else
+ {
+ if ((float)x_pos>=ScanY_X[0][y_pos])
+ {
+ if (isnan(ScanY_X[1][y_pos]) // Droit non défini
+ || (x_pos>ScanY_X[1][y_pos]))
+ {
+ ScanY_X[1][y_pos]=(float)x_pos;
+ ScanY_Xt[1][y_pos]=xt;
+ ScanY_Yt[1][y_pos]=yt;
+ }
+ }
+ else
+ {
+ if (isnan(ScanY_X[1][y_pos])) // Droit non défini
+ {
+ ScanY_X[1][y_pos]=ScanY_X[0][y_pos];
+ ScanY_Xt[1][y_pos]=ScanY_Xt[0][y_pos];
+ ScanY_Yt[1][y_pos]=ScanY_Yt[0][y_pos];
+ ScanY_X[0][y_pos]=(float)x_pos;
+ ScanY_Xt[0][y_pos]=xt;
+ ScanY_Yt[0][y_pos]=yt;
+ }
+ else
+ {
+ ScanY_X[0][y_pos]=(float)x_pos;
+ ScanY_Xt[0][y_pos]=xt;
+ ScanY_Yt[0][y_pos]=yt;
+ }
+ }
+ }
+ }
+ y_pos+=incr_y;
+ cumul+=delta_x;
+ }
+ }
+}
+
+
+
+void Compute_quad_texture(int x1,int y1,int xt1,int yt1,
+ int x2,int y2,int xt2,int yt2,
+ int x3,int y3,int xt3,int yt3,
+ int x4,int y4,int xt4,int yt4,
+ byte * buffer, int width, int height)
+{
+ int x_min,/*x_max,*/y_min/*,y_max*/;
+ int x,y,xt,yt;
+ int start_x,end_x,line_width;
+ float temp;
+ //byte color;
+
+ x_min=Min(Min(x1,x2),Min(x3,x4));
+ y_min=Min(Min(y1,y2),Min(y3,y4));
+
+ ScanY_Xt[0]=(float *)malloc(height*sizeof(float));
+ ScanY_Xt[1]=(float *)malloc(height*sizeof(float));
+ ScanY_Yt[0]=(float *)malloc(height*sizeof(float));
+ ScanY_Yt[1]=(float *)malloc(height*sizeof(float));
+ ScanY_X[0] =(float *)malloc(height*sizeof(float));
+ ScanY_X[1] =(float *)malloc(height*sizeof(float));
+
+ // Fill_general avec des valeurs égales à NAN.
+ for (y=0; y<height; y++)
+ {
+ ScanY_X[0][y]=NAN ;
+ ScanY_X[1][y]=NAN;
+ }
+
+ Interpolate_texture(x1-x_min,y1-y_min,xt1,yt1,x3-x_min,y3-y_min,xt3,yt3,height);
+ Interpolate_texture(x3-x_min,y3-y_min,xt3,yt3,x4-x_min,y4-y_min,xt4,yt4,height);
+ Interpolate_texture(x4-x_min,y4-y_min,xt4,yt4,x2-x_min,y2-y_min,xt2,yt2,height);
+ Interpolate_texture(x2-x_min,y2-y_min,xt2,yt2,x1-x_min,y1-y_min,xt1,yt1,height);
+
+ for (y=0; y<height; y++)
+ {
+ start_x=Round(ScanY_X[0][y]);
+ end_x =Round(ScanY_X[1][y]);
+
+ line_width=1+end_x-start_x;
+
+ for (x=0; x<start_x; x++)
+ buffer[x+(y*width)]=Back_color;
+ for (; x<=end_x; x++)
+ {
+ temp=(float)(0.5+(float)x-ScanY_X[0][y])/(float)line_width;
+ xt=Round((float)(ScanY_Xt[0][y])+(temp*(ScanY_Xt[1][y]-ScanY_Xt[0][y])));
+ yt=Round((float)(ScanY_Yt[0][y])+(temp*(ScanY_Yt[1][y]-ScanY_Yt[0][y])));
+ if (xt>=0 && yt>=0)
+ buffer[x+(y*width)]=*(Brush_original_pixels + yt * Brush_width + xt);
+ }
+ for (; x<width; x++)
+ buffer[x+(y*width)]=Back_color;
+ }
+
+ free(ScanY_Xt[0]);
+ free(ScanY_Xt[1]);
+ free(ScanY_Yt[0]);
+ free(ScanY_Yt[1]);
+ free(ScanY_X[0]);
+ free(ScanY_X[1]);
+
+ ScanY_Xt[0] = ScanY_Xt[1] = ScanY_Yt[0] = ScanY_Yt[1] = ScanY_X[0] = ScanY_X[1] = NULL;
+}
+
+
+
+void Rotate_brush(float angle)
+{
+ byte * new_brush;
+ int new_brush_width; // Width de la nouvelle brosse
+ int new_brush_height; // Height de la nouvelle brosse
+
+ short x1,y1,x2,y2,x3,y3,x4,y4;
+ int start_x,end_x,start_y,end_y;
+ int x_min,x_max,y_min,y_max;
+ float cos_a=cos(angle);
+ float sin_a=sin(angle);
+
+ // Calcul des coordonnées des 4 coins:
+ // 1 2
+ // 3 4
+
+ start_x=1-(Brush_width>>1);
+ start_y=1-(Brush_height>>1);
+ end_x=start_x+Brush_width-1;
+ end_y=start_y+Brush_height-1;
+
+ Transform_point(start_x,start_y, cos_a,sin_a, &x1,&y1);
+ Transform_point(end_x ,start_y, cos_a,sin_a, &x2,&y2);
+ Transform_point(start_x,end_y , cos_a,sin_a, &x3,&y3);
+ Transform_point(end_x ,end_y , cos_a,sin_a, &x4,&y4);
+
+ // Calcul des nouvelles dimensions de la brosse:
+ x_min=Min(Min((int)x1,(int)x2),Min((int)x3,(int)x4));
+ x_max=Max(Max((int)x1,(int)x2),Max((int)x3,(int)x4));
+ y_min=Min(Min((int)y1,(int)y2),Min((int)y3,(int)y4));
+ y_max=Max(Max((int)y1,(int)y2),Max((int)y3,(int)y4));
+
+ new_brush_width=x_max+1-x_min;
+ new_brush_height=y_max+1-y_min;
+
+ new_brush=(byte *)malloc(new_brush_width*new_brush_height);
+
+ if (!new_brush)
+ {
+ Error(0);
+ return;
+ }
+ // Et maintenant on calcule la nouvelle brosse tournée.
+ Compute_quad_texture(x1,y1, 0, 0,
+ x2,y2,Brush_width-1, 0,
+ x3,y3, 0,Brush_height-1,
+ x4,y4,Brush_width-1,Brush_height-1,
+ new_brush,new_brush_width,new_brush_height);
+
+ if (Realloc_brush(new_brush_width, new_brush_height, new_brush, NULL))
+ {
+ free(new_brush);
+ return;
+ }
+ // Remap according to the last used remap table
+ Remap_general_lowlevel(Brush_colormap,Brush_original_pixels,Brush,Brush_width,Brush_height,Brush_width);
+
+ // Center offsets
+ Brush_offset_X=(Brush_width>>1);
+ Brush_offset_Y=(Brush_height>>1);
+
+}
+
+
+
+void Draw_quad_texture_preview(int x1,int y1,int xt1,int yt1,
+ int x2,int y2,int xt2,int yt2,
+ int x3,int y3,int xt3,int yt3,
+ int x4,int y4,int xt4,int yt4)
+{
+ int x_min,x_max,y_min,y_max;
+ int x,y,xt,yt;
+ int y_,y_min_;
+ int start_x,end_x,width,height;
+ float temp;
+ byte color;
+
+ x_min=Min(Min(x1,x2),Min(x3,x4));
+ x_max=Max(Max(x1,x2),Max(x3,x4));
+ y_min=Min(Min(y1,y2),Min(y3,y4));
+ y_max=Max(Max(y1,y2),Max(y3,y4));
+ height=1+y_max-y_min;
+
+ ScanY_Xt[0]=(float *)malloc(height*sizeof(float));
+ ScanY_Xt[1]=(float *)malloc(height*sizeof(float));
+ ScanY_Yt[0]=(float *)malloc(height*sizeof(float));
+ ScanY_Yt[1]=(float *)malloc(height*sizeof(float));
+ ScanY_X[0] =(float *)malloc(height*sizeof(float));
+ ScanY_X[1] =(float *)malloc(height*sizeof(float));
+
+ // Fill_general avec des valeurs égales à NAN.
+ for (y=0; y<height; y++)
+ {
+ ScanY_X[0][y]=NAN;
+ ScanY_X[1][y]=NAN;
+ }
+
+ Interpolate_texture(x1,y1-y_min,xt1,yt1,x3,y3-y_min,xt3,yt3,height);
+ Interpolate_texture(x3,y3-y_min,xt3,yt3,x4,y4-y_min,xt4,yt4,height);
+ Interpolate_texture(x4,y4-y_min,xt4,yt4,x2,y2-y_min,xt2,yt2,height);
+ Interpolate_texture(x2,y2-y_min,xt2,yt2,x1,y1-y_min,xt1,yt1,height);
+
+ y_min_=y_min;
+ if (y_min<Limit_top) y_min=Limit_top;
+ if (y_max>Limit_bottom) y_max=Limit_bottom;
+
+ for (y_=y_min; y_<=y_max; y_++)
+ {
+ y=y_-y_min_;
+ start_x=Round(ScanY_X[0][y]);
+ end_x =Round(ScanY_X[1][y]);
+
+ width=1+end_x-start_x;
+
+ if (start_x<Limit_left) start_x=Limit_left;
+ if ( end_x>Limit_right) end_x=Limit_right;
+
+ for (x=start_x; x<=end_x; x++)
+ {
+ temp=(float)(0.5+(float)x-ScanY_X[0][y])/(float)width;
+ xt=Round((float)(ScanY_Xt[0][y])+(temp*(ScanY_Xt[1][y]-ScanY_Xt[0][y])));
+ yt=Round((float)(ScanY_Yt[0][y])+(temp*(ScanY_Yt[1][y]-ScanY_Yt[0][y])));
+ if (xt>=0 && yt>=0)
+ {
+ color=Read_pixel_from_brush(xt,yt);
+ if (color!=Back_color)
+ Pixel_preview(x,y_,color);
+ }
+ }
+ }
+
+ free(ScanY_Xt[0]);
+ free(ScanY_Xt[1]);
+ free(ScanY_Yt[0]);
+ free(ScanY_Yt[1]);
+ free(ScanY_X[0]);
+ free(ScanY_X[1]);
+
+ ScanY_Xt[0] = ScanY_Xt[1] = ScanY_Yt[0] = ScanY_Yt[1] = ScanY_X[0] = ScanY_X[1] = NULL;
+}
+
+
+void Rotate_brush_preview(float angle)
+{
+ short x1,y1,x2,y2,x3,y3,x4,y4;
+ int start_x,end_x,start_y,end_y;
+ float cos_a=cos(angle);
+ float sin_a=sin(angle);
+
+ // Calcul des coordonnées des 4 coins:
+ // 1 2
+ // 3 4
+
+ start_x=1-(Brush_width>>1);
+ start_y=1-(Brush_height>>1);
+ end_x=start_x+Brush_width-1;
+ end_y=start_y+Brush_height-1;
+
+ Transform_point(start_x,start_y, cos_a,sin_a, &x1,&y1);
+ Transform_point(end_x ,start_y, cos_a,sin_a, &x2,&y2);
+ Transform_point(start_x,end_y , cos_a,sin_a, &x3,&y3);
+ Transform_point(end_x ,end_y , cos_a,sin_a, &x4,&y4);
+
+ x1+=Brush_rotation_center_X;
+ y1+=Brush_rotation_center_Y;
+ x2+=Brush_rotation_center_X;
+ y2+=Brush_rotation_center_Y;
+ x3+=Brush_rotation_center_X;
+ y3+=Brush_rotation_center_Y;
+ x4+=Brush_rotation_center_X;
+ y4+=Brush_rotation_center_Y;
+
+ // Et maintenant on dessine la brosse tournée.
+ Draw_quad_texture_preview(x1,y1, 0, 0,
+ x2,y2,Brush_width-1, 0,
+ x3,y3, 0,Brush_height-1,
+ x4,y4,Brush_width-1,Brush_height-1);
+ start_x=Min(Min(x1,x2),Min(x3,x4));
+ end_x=Max(Max(x1,x2),Max(x3,x4));
+ start_y=Min(Min(y1,y2),Min(y3,y4));
+ end_y=Max(Max(y1,y2),Max(y3,y4));
+ Update_part_of_screen(start_x,start_y,end_x-start_x+1,end_y-start_y+1);
+}
+/*
+/// Sets brush's original palette and color mapping.
+void Brush_set_palette(T_Palette *palette)
+{
+ int i;
+ byte need_remap;
+
+ need_remap=0;
+
+ memcpy(Brush_original_palette,palette,sizeof(T_Palette));
+ for (i=0;i<256;i++)
+ {
+ if (Brush_original_palette[i].R!=Main_palette[i].R
+ || Brush_original_palette[i].G!=Main_palette[i].G
+ || Brush_original_palette[i].B!=Main_palette[i].B)
+ {
+ need_remap=1;
+ }
+ }
+
+}
+*/
View
129 project/jni/application/grafx2/grafx2/src/brush.h
@@ -0,0 +1,129 @@
+/* vim:expandtab:ts=2 sw=2:
+*/
+/* Grafx2 - The Ultimate 256-color bitmap paint program
+
+ Copyright 2007-2008 Adrien Destugues
+ Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud)
+
+ Grafx2 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; version 2
+ of the License.
+
+ Grafx2 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 Grafx2; if not, see <http://www.gnu.org/licenses/>
+*/
+
+//////////////////////////////////////////////////////////////////////////////
+///@file brush.h
+/// Actions on the brush.
+//////////////////////////////////////////////////////////////////////////////
+
+#ifndef __BRUSH_H_
+#define __BRUSH_H_
+
+#include "struct.h"
+
+/*!
+ Gets the brush from the picture.
+ @param start_x left edge coordinate in the picture
+ @param start_y upper edge coordinate in the picture
+ @param end_x right edge coordinate in the picture
+ @param end_y bottom edge coordinate in the picture
+ @param clear If 1, the area is also cleared from the picture.
+*/
+void Capture_brush(short start_x,short start_y,short end_x,short end_y,short clear);
+
+/*!
+ Rotates the brush to the right.
+*/
+void Rotate_90_deg(void);
+
+/*!
+ Stretch the brush to fit the given rectangle.
+*/
+void Stretch_brush(short x1, short y1, short x2, short y2);
+
+/*!
+ Stretch the brush to fit the given rectangle.
+ Uses fast approximation for the preview while drawing the rectangle on screen.
+*/
+void Stretch_brush_preview(short x1, short y1, short x2, short y2);
+
+/*!
+ Rotates the brush to the right from the given angle.
+*/
+void Rotate_brush(float angle);
+
+/*!
+ Stretch the brush to fit the given rectangle.
+ Uses fast approximation for the preview while changing the angle.
+*/
+void Rotate_brush_preview(float angle);
+
+/*!
+ Remap the brush palette to the nearest color in the picture one.
+ Used when switching to the spare page.
+*/
+
+/*!
+ Distort the brush on the screen.
+*/
+void Distort_brush_preview(short x1, short y1, short x2, short y2, short x3, short y3, short x4, short y4);
+
+/*!
+ Replace the brush by a distorted version of itself.
+*/
+void Distort_brush(short x1, short y1, short x2, short y2, short x3, short y3, short x4, short y4);
+
+
+void Remap_brush(void);
+
+/*!
+ Get color indexes used by the brush.
+*/
+void Get_colors_from_brush(void);
+
+/*!
+ Outline the brush, add 1 foreground-colored pixel on the edges.
+ Edges are detected considering the backcolor as transparent.
+*/
+void Outline_brush(void);
+
+/*!
+ Nibble the brush, remove 1 pixel on the edges and make it transparent (ie filled with back color).
+ Edges are detected considering the backcolor as transparent.
+*/
+void Nibble_brush(void);
+
+/*!
+ Get brush from picture according to a freehand form.
+ @param vertices number of points in the freehand form
+ @param points array of points coordinates
+ @param clear If set to 1, the captured area is also cleared from the picture.
+*/
+void Capture_brush_with_lasso(int vertices, short * points,short clear);
+
+
+///
+/// Changes the Brush size.
+/// @return 0 on success, non-zero on failure (memory?).
+/// @param new_brush: Optionally, you can provide an already allocated new
+/// brush - otherwise, this function performs the allocation.
+/// @param old_brush: If the caller passes NULL, this function will free the old
+/// pixel data. If the caller provides the address of a (free) byte
+/// pointer, the function will make it point to the original pixel data,
+/// in this case it will be the caller's responsibility to free() it
+/// (after transferring pixels to Brush, usually).
+byte Realloc_brush(word new_brush_width, word new_brush_height, byte *new_brush, byte **old_brush);
+
+/// Sets brush's original palette and color mapping.
+void Brush_set_palette(T_Palette *palette);
+
+
+#endif
View
1,392 project/jni/application/grafx2/grafx2/src/brush_ops.c
@@ -0,0 +1,1392 @@
+/* vim:expandtab:ts=2 sw=2:
+*/
+/* Grafx2 - The Ultimate 256-color bitmap paint program
+
+ Copyright 2007 Adrien Destugues
+ Copyright 2009 Franck Charlet
+ Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud)
+
+ Grafx2 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; version 2
+ of the License.
+
+ Grafx2 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 Grafx2; if not, see <http://www.gnu.org/licenses/>
+*/
+//////////////////////////////////////////////////////////////////////////////
+///@file brush_ops.c
+/// Code for operations about the brush (grabbing, rotating, ...) and magnifier
+//////////////////////////////////////////////////////////////////////////////
+
+#include <math.h>
+#include <stdlib.h>
+
+#include