/data/common/media/grafx2/fonts/5pxtinyfont.png |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
Property changes: |
Added: svn:mime-type |
+application/octet-stream |
\ No newline at end of property |
/data/common/media/grafx2/fonts/8pxfont.png |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
Property changes: |
Added: svn:mime-type |
+application/octet-stream |
\ No newline at end of property |
/data/common/media/grafx2/fonts/GrafX2_Black.gif |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
Property changes: |
Added: svn:mime-type |
+application/octet-stream |
\ No newline at end of property |
/data/common/media/grafx2/fonts/GrafX2_Dark.gif |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
Property changes: |
Added: svn:mime-type |
+application/octet-stream |
\ No newline at end of property |
/data/common/media/grafx2/fonts/PF_Arma_5__.png |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
Property changes: |
Added: svn:mime-type |
+application/octet-stream |
\ No newline at end of property |
/data/common/media/grafx2/fonts/PF_Easta_7_.png |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
Property changes: |
Added: svn:mime-type |
+application/octet-stream |
\ No newline at end of property |
/data/common/media/grafx2/fonts/PF_Easta_7__.png |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
Property changes: |
Added: svn:mime-type |
+application/octet-stream |
\ No newline at end of property |
/data/common/media/grafx2/fonts/PF_Ronda_7__.png |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
Property changes: |
Added: svn:mime-type |
+application/octet-stream |
\ No newline at end of property |
/data/common/media/grafx2/fonts/PF_Tempesta_5.png |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
Property changes: |
Added: svn:mime-type |
+application/octet-stream |
\ No newline at end of property |
/data/common/media/grafx2/fonts/PF_Tempesta_5_.png |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
Property changes: |
Added: svn:mime-type |
+application/octet-stream |
\ No newline at end of property |
/data/common/media/grafx2/fonts/PF_Tempesta_5__.png |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
Property changes: |
Added: svn:mime-type |
+application/octet-stream |
\ No newline at end of property |
/data/common/media/grafx2/fonts/PF_Tempesta_5___.png |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
Property changes: |
Added: svn:mime-type |
+application/octet-stream |
\ No newline at end of property |
/data/common/media/grafx2/fonts/PF_Tempesta_7.png |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
Property changes: |
Added: svn:mime-type |
+application/octet-stream |
\ No newline at end of property |
/data/common/media/grafx2/fonts/PF_Tempesta_7_.png |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
Property changes: |
Added: svn:mime-type |
+application/octet-stream |
\ No newline at end of property |
/data/common/media/grafx2/fonts/PF_Tempesta_7__.png |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
Property changes: |
Added: svn:mime-type |
+application/octet-stream |
\ No newline at end of property |
/data/common/media/grafx2/fonts/PF_Tempesta_7___.png |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
Property changes: |
Added: svn:mime-type |
+application/octet-stream |
\ No newline at end of property |
/data/common/media/grafx2/fonts/PF_Westa_7_.png |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
Property changes: |
Added: svn:mime-type |
+application/octet-stream |
\ No newline at end of property |
/data/common/media/grafx2/fonts/PF_Westa_7__.png |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
Property changes: |
Added: svn:mime-type |
+application/octet-stream |
\ No newline at end of property |
/data/common/media/grafx2/fonts/Tuffy.ttf |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
Property changes: |
Added: svn:mime-type |
+application/octet-stream |
\ No newline at end of property |
/data/common/media/grafx2/fonts/colorfont.pcx |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
Property changes: |
Added: svn:mime-type |
+application/octet-stream |
\ No newline at end of property |
/data/common/media/grafx2/gfx2.gif |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
Property changes: |
Added: svn:mime-type |
+application/octet-stream |
\ No newline at end of property |
/data/common/media/grafx2/gfx2.png |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
Property changes: |
Added: svn:mime-type |
+application/octet-stream |
\ No newline at end of property |
/data/common/media/grafx2/gfx2def.ini |
---|
0,0 → 1,420 |
###### GrafX2 initialization file ###### Fichier d'initialisation de GrafX2 ## |
# # # # |
# You may modify this file with any # Vous pouvez modifier ce fichier avec # |
# standard ASCII text editor. # n'importe quel éditeur de texte # |
# # ASCII standard. # |
# # # |
# Comments are preceded by ';' or # Les commentaires sont précédés par # |
# '#'. # ';' ou '#'. # |
# # # |
# Options are not case sensitive and # Les options ne sont pas sensibles à # |
# spaces are ignored. # la casse et les espaces sont ignorés.# |
# # # |
# You must not change the order of # Vous ne devez pas changer l'ordre # |
# the sections and their options. # des sections et de leurs options. # |
# You must not delete or put into # Vous ne devez pas effacer ou mettre # |
# comment any section nor option. # en commentaire une section ou option.# |
# # # |
# Each option is preceded by a # Chaque option est précédée par un # |
# comment which explains its meaning. # commentaire qui explique sa fonction.# |
# # # |
############################################################################## |
[MOUSE] # [SOURIS] |
; The sensitivity of the mouse can | La sensibilité de la souris peut |
; take values from 1 to 4. The | prendre des valeurs de 1 à 4. Plus |
; smaller values, the faster. | les valeurs sont petites, plus c'est |
; This only takes effect in | rapide. Ce paramétrage n'est utilisé |
; fullscreen modes. | que dans les modes "plein écran". |
; | |
X_sensitivity = 1 ; (default 1) |
Y_sensitivity = 1 ; (default 1) |
; Unused setting, only kept for compatibility. |
X_correction_factor = 0 ; (default 0) |
Y_correction_factor = 0 ; (default 0) |
; Aspect of the main cursor (cross) | Aspect du curseur principal (croix) |
; 1: Solid | 1: Solide |
; 2: Transparent | 2: Transparent |
; 3: Thin (solid) | 3: Fin (solide) |
Cursor_aspect = 1 ; (default 1) |
[MENU] # [MENU] |
; Colors of the menus (the black | Couleurs des menus (la couleur noire |
; and the white colors cannot be | et la couleur blanche ne peuvent pas |
; modified). | être modifiées). |
; Values are in {Red,Green,Blue} | Les valeurs sont dans l'ordre {Rouge, |
; order and are between 0 and 63. | Vert,Bleu} et vont de 0 à 63. |
Light_color = 42,42,42 ; (default 42,42,42) |
Dark_color = 27,27,27 ; (default 27,27,27) |
; |
; Light_color = 24,25,30 ; \_ Nightmare |
; Dark_color = 13,14,19 ; / |
; |
; Light_color = 10,45,28 ; \_ Forest |
; Dark_color = 5,27,12 ; / |
; |
; Light_color = 48,41,26 ; \_ Gold |
; Dark_color = 26,22,15 ; / |
; |
; Light_color = 10,40,55 ; \_ Oceanic |
; Dark_color = 10,20,32 ; / |
; Aspect ratio and size of the | Proportion des menus et de la barre |
; menus and the tool-bar. | d'outils. |
; Possible values: | Valeurs possibles: |
; 0: Do not adapt (pixels are not | 0: Ne pas adapter (les pixels ne sont |
; stretched) | pas étirés) |
; 1: Adapt the menus and the tool- | 1: Adapter les menus et la barre |
; bar according to the resolution| d'outils suivant la résolution |
; 2: Slightly adapt the ratio of | 2: Adapter légèrement les proportions |
; the menus and tool-bar | des menus et de la barre d'outils |
; -1:Do not adapt (like 0) | -1:Ne pas adapter (comme 0) |
; -2:Stretch by x2 maximum | -2:Etire au double de taille si possible |
; -3:Stretch by x3 maximum | -3:Etire au triple de taille si possible |
; -4:Stretch by x4 maximum | -3:Etire au quadruple de taille si |
; | possible. |
Menu_ratio = -2 ; (default -2) |
[FILE_SELECTOR] # [SELECTEUR_DE_FICHIERS] |
; Show hidden files and | Afficher les fichiers et répertoires |
; directories (values are 'yes' or | cachés (les valeurs sont 'yes' ou |
; 'no'). | 'no'). |
Show_hidden_files = no ; (default 'no') |
Show_hidden_directories = no ; (default 'no') |
; Delay before displaying a preview | Délai avant d'afficher une preview |
; in file-selectors (in 18.2th of | dans les sélecteurs de fichiers (en |
; second). Possible values range | 18.2èmes de seconde) Les valeurs |
; from 1 to 256. | possibles vont de 1 à 256. |
Preview_delay = 8 ; (default 8) |
; Maximize the preview of the | Maximiser la preview des images pour |
; pictures so that it is as big as | qu'elle soit aussi grande que |
; possible. If you're not in the | possible. |
; same resolution as the picture's | Si vous n'êtes pas dans la même réso- |
; one, it can try to correct the | lution que celle de l'image, cela peut |
; aspect ratio, but if the picture | essayer de corriger les proportions, |
; does not fill the whole screen, | mais si l'image ne prend pas tout |
; it can be worse. | l'écran, cela peut être pire. |
Maximize_preview = no ; (default 'no') |
; This option is used to place the | Cette option est utilisée pour placer |
; selection bar on a filename by | la barre de sélection sur un nom de |
; typing its first letters. | fichier en tapant ses 1ères lettres. |
; For example, if you want to find | Par exemple, si vous voulez trouver le |
; the "PICTURE.PKM" in a directory | fichier "PICTURE.PKM" dans un réper- |
; that also contains "PALETTE.PAL", | toire contenant également le fichier |
; you'll just have to type P and I. | "PALETTE.PAL", vous n'aurez qu'à taper |
; The different values of "FFF" | P puis I. |
; indicate if you want to find the | Les different valeurs de "FFF" |
; name in both files and directories| indiquent si vous voulez trouvez le nom |
; or just in only one of these: | dans les fichiers ET les répertoires ou |
; 0: files and directories | simplement dans l'un OU l'autre. |
; 1: files only | 0: fichiers et répertoires |
; 2: directories only | 1: fichiers seulement |
; | 2: répertoires seulement |
Find_file_fast = 0 ; (default 0) |
[LOADING] # [CHARGEMENT] |
; Automatically set the resolution | Passer automatiquement dans la bonne |
; when loading a picture. | résolution lors du chargement d'une |
; You should set this value to | image. |
; 'yes' after disabling the video | Vous devriez définir cette option à |
; modes that are not supported by | 'yes' après avoir inhibé les modes |
; your video card or monitor. | vidéo qui ne sont pas supportés par |
; | votre matériel. |
Auto_set_resolution = no ; (default 'no') |
; If the variable above is set to | Si la variable ci-dessus est à 'yes', |
; 'yes', this one tells if you want | celle-ci indique si vous voulez |
; to set the resolution according | définir la résolution suivant: |
; to: | 1: les dimensions de "l'écran |
; 1: the internal "original screen" | d'origine" internes à l'image |
; dimensions of the picture | 2: les véritables dimensions de |
; 2: the actual dimensions of the | l'image |
; picture | |
Set_resolution_according_to = 1 ; (default 1) |
; If you load a picture with a | Si vous chargez une image ayant une |
; palette of less than 256 colors, | palette de moins de 256 couleurs, |
; this option defines if you want | cette option indique si vous souhaitez |
; to clear the palette or to keep | effacer la palette ou bien conserver |
; the colors of the previous | les couleurs de l'image précédente qui |
; picture that are over the number | se situent au-delà du nombre de la |
; of colors of the new picture. | nouvelle image. |
; For example, if you load a | Par exemple, si vous chargez une image |
; 32-color picture, the colors 32 | de 32 couleurs, les couleurs 32 à 255 |
; to 255 will be set to black if | seront passées en noir si cette option |
; this option is set to 'yes', or | est à 'yes', ou bien elles resteront |
; they will be kept unchanged if | inchangées si elle est à 'no'. |
; this option is set to 'no'. | |
Clear_palette = yes ; (default 'yes') |
[MISCELLANEOUS] # [DIVERS] |
; Draw the limits of the picture. | Afficher les limites de l'image |
Draw_limits = yes ; (default 'yes') |
; Adjust the brush grabbing in | Ajuster la capture de brosse en mode |
; "grid" mode. | "grille". |
Adjust_brush_pick = yes ; (default 'yes') |
; Coordinates: | Coordonnées: |
; 1: Relative | 1: Relatives |
; 2: Absolute | 2: Absolues |
Coordinates = 1 ; (default 1) |
; Create a backup file when saving. | Créer un fichier backup lors des |
; | sauvegardes. |
Backup = no ; (default 'no') |
; Number of pages stored in memory | Nombre de pages stockées en mémoire |
; for "undoing". | destinées à annuler les dernières |
; Values are between 1 and 99. | modifications. Valeurs entre 1 et 99. |
Undo_pages = 20 ; (default 20) |
; Speed of the scroll-bars (in VBLs | Vitesse des barre de défilement (en |
; waited) while clicking with the | VBLs attendus) lorsque l'un des |
; left or right button of the mouse.| boutons de la souris est enfoncé. |
; Values can be between 1 and 255. | Les valeurs sont comprises entre 1 et |
; The bigger values, the slower. | 255. Plus elles sont grandes, plus |
; | c'est lent. |
Gauges_scrolling_speed_Left = 10 ; (default 10) |
Gauges_scrolling_speed_Right = 3 ; (default 3) |
; Automatically save the configu- | Enregistre automatiquement la configu- |
; ration when exiting the program. | ration lorsqu'on quitte le programme. |
Auto_save = yes ; (default 'yes') |
; Maximum number of vertices used | Nombre maximum de vertex utilisés dans |
; in filled polygons and polyforms, | les polygônes et polyformes pleins, et |
; and lasso. Possible values range | le lasso. Les valeurs possibles vont |
; from 2 to 16384. | de 2 à 16384. |
; Each vertex takes 4 bytes. | Chaque vertex prend 4 octets. |
Vertices_per_polygon = 1024 ; (default 1024) |
; Automatically zoom into the | Zoomer automatiquement la zone pointée |
; pointed area when you press the | par la souris lorsque vous appuyez sur |
; short-key of the Magnifier button | la touche de raccourci de la loupe. |
; while being above the picture. | |
Fast_zoom = yes ; (default 'yes') |
; Separate the colors in the tool- | Séparer les couleurs dans la barre |
; bar by a black squaring. | d'outils par un quadrillage noir. |
Separate_colors = no ; (default 'no') |
; Initial value of the feedback for | Valeur initiale du "feedback" pour les |
; the drawing modes (cf. docs). | modes de dessin (cf. docs). |
FX_feedback = yes ; (default 'yes') |
; When you reduce the palette or | Si vous réduisez la palette ou "zappez" |
; "zap" some colors out of it, it is| quelques couleurs, il est possible |
; possible that there are not enough| qu'il ne reste pas assez de couleurs |
; colors left to draw the menus. | pour afficher les menus. Mettre cette |
; Switching the following variable | variable à 'yes' ramènera automatiquent |
; on will bring back the colors of | les couleurs du menu s'il reste moins |
; the menu if there are less than 4 | de 4 couleurs après une "réduction" ou |
; colors left after "reducing" or | un "zapping". |
; "zapping". | |
Safety_colors = yes ; (default 'yes') |
; Display a message at startup | Afficher un message au démarrage |
; telling the version number of the | indiquant le numéro de version du |
; program. | programme. |
Opening_message = yes ; (default 'yes') |
; Take the Stencil into account when| Prendre le Stencil en compte lorsqu'on |
; clearing the image. | efface l'image. |
Clear_with_stencil = yes ; (default 'yes') |
; Directly set the discontinuous | Passer automatiquement en mode de |
; freehand drawing mode after brush | dessin discontinu après la prise d'une |
; grabbing. | brosse. |
Auto_discontinuous = no ; (default 'no') |
; Save the screen dimensions in GIF | Sauver les dimensions de l'écran dans |
; files. If you want to read these | les fichiers GIF. Si vous voulez lire |
; files with Photoshop or Alchemy, | ces fichiers avec Photoshop ou Alchemy, |
; and maybe some other programs, you| et peut-être d'autres programmes, vous |
; must set this option to 'no'. | devez mettre cette option à 'no'. |
Save_screen_size_in_GIF = no ; (default 'no') |
; Automaticaly count the number of | Compter automatiquement le nombre de |
; different colors used when opening| couleurs différentes utilisées lors de |
; the palette editor window. (Set it| d'ouverture de la fenêtre d'édition de |
; to 'no' if you have a slow PC or | la palette. (Mettez-le à 'no' si vous |
; if you edit huge pictures) | avez un PC lent ou bien si vous éditez |
; | d'énormes images). |
Auto_nb_colors_used = yes ; (default 'yes') |
; Default video mode at startup | Mode vidéo par défaut au |
; (see the list by running the | démarrage (voir la liste en lançant |
; program with argument "/?". | le programme avec l'option "/?". |
Default_video_mode = window ; (default 'window') |
; Window dimensions. The program | Dimensions de la fenêtre en mode |
; remembers the last window size. | fenêtré. |
Default_window_size = 640,480 ; (default '640,480') |
; This setting allows you merge successive mouse movements into a single |
; mouse movement. You should only use it if you are using a mouse which |
; reports at 200Hz or more, and you experience lag when using discontinuous |
; hand-drawing with large brushes (this tool tries to paste the brush and |
; update the screen on each new mouse position) In this case, set this to 2 |
; or more, to ignore some intermediate mouse reports when a more recent one |
; is present. |
; Note that with a value superior to 1, you lose precision with continuous |
; hand-drawing, as intermediate mouse positions are skipped. |
Merge_movement = 0 ; (default 0) |
; Number of columns in the palette of the menu bar. Can be any number from |
; 1 to 256. If there is not enough room, the program will display less |
; columns. But your preference will be kept, and as soon as there is more |
; space in the screen, more columns will be shown. |
; |
Palette_Cells_X = 16; (Default 16) |
; Number of lines in the palette of the menu. Can be any number from |
; 1 to 16. The menu can always display the number of lines you request. |
; |
Palette_Cells_Y = 4; (Default 4) |
; Bookmarked directories. Leave the directory blank for unused ones. |
; |
Bookmark_label = |
Bookmark_directory = |
Bookmark_label = |
Bookmark_directory = |
Bookmark_label = |
Bookmark_directory = |
Bookmark_label = |
Bookmark_directory = |
; In the classic layout, the palette in the menu has colors from left to |
; right. If you prefer the colors ordered top to bottom, set this option |
; to YES. |
; |
Palette_vertical = YES; (Default YES) |
; The program remembers the last window position, if the |
; OS isn't able to do it by itself. (ie: Windows) |
Window_position = 9999,9999; (Default 9999,9999 which means: NA) |
; This is the time (in milliseconds) between two clicks for Grafx2 to |
; recognize a double-click. Double-click is used mostly in the palette |
; area of the menu: double-click a color to open the palette. |
Double_click_speed = 500; (Default 500) |
; When you press two digit keys in rapid succession (ex: 3 8), Grafx2 |
; sets transparency to 38% (instead of 30% then 80%). This setting |
; allows you to set the maximum delay between two keypresses for |
; GrafX2 to recognize them as a combo. |
Double_key_speed = 500; (Default 500) |
; Name of the skinfile you want to | Nom du fichier skin que vous voulez |
; use. | utiliser. |
; Default : (empty to let the program choose) |
Skin_file = |
; Name of the font file (8x8) you | Nom du fichier police de caractère |
; want to use. | 8x8 utilisée dans les menus. |
; Default : (empty to let the program choose) |
Font_file = |
; This determines the color value for the grid. Each pixel of |
; the grid will be displayed by XOR-ing the original color with |
; the value of this setting. |
; For example, if you always paint 16-color images, you can set it |
; to 16 so the color of the grid are 16 for 0, 17 for 1, etc. |
; Then you can set colors 16-31 as lighter/darker variants |
; of your original palette, resulting in a pretty grid ! |
; |
; Valid values are 1 to 255. |
Grid_XOR_color = 255; (Default 255) |
; This records the last pixel ratio used, to restore it on start. |
; Valid values are from 0 to 7 for: Simple, Wide, Tall, Double, |
; Triple, Wide2, Tall2, Quadruple. |
; |
Pixel_ratio = 0; (Default 0) |
; This records the visibility of toolbars, to restore them on start. |
; It's a bitfield, where 1=Status, 2=Layers/Animation, 4=Tools |
; |
Menubars_visible = 255; (Default 255) |
; This enables a mode where right mouse buttons acts as |
; a color picker, with most tools. |
; |
Right_click_colorpick = NO; (Default NO) |
; When this mode is active, scrolling the view (and the magnifier view) |
; affects both the main image and the spare page - as long as they have |
; the same dimensions. |
; |
Sync_views = YES; (Default YES) |
; This setting determines which key inverts the mouse buttons |
; when it's held : A left click is then interpreted as a right-click. |
; It's especially useful for one-button controllers, |
; such as touchscreens and tablets. |
; Possible values are 0 (none), 1 (control), 2 (alt) |
; |
Swap_buttons = 1; (Default 1) |
; Last directory browsed with the script selector. |
; Leave blank to initially start in (data directory)/scripts |
; |
Scripts_directory = |
; When this setting is disabled, and you create a shortcut with a key that |
; is already associated to another shortcut, Grafx2 will unset the latter. |
; If you enable this mode, Grafx2 will not make such check, so you can design |
; shortcuts that trigger several actions at once. |
; |
Allow_multi_shortcuts = no; (Default no) |
; Determines if the Tilemap tool should identify tiles that are mirrored |
; version of other tiles, on the X axis. |
; |
Tilemap_detect_mirrored_x = no; (Default no) |
; Determines if the Tilemap tool should identify tiles that are mirrored |
; version of other tiles, on the Y axis. |
; |
Tilemap_detect_mirrored_y = no; (Default no) |
; Determines if the Tilemap tool should identify tiles that are reversed |
; versions of other tiles (180°). |
; |
Tilemap_detect_mirrored_xy = no; (Default no) |
; Determines if the Tilemap tool should show the number of distinct tiles |
; at the end of analysis. |
; |
Tilemap_count = no; (Default no) |
; Enables the virtual keyboard when the user enters a textbox. |
; |
; 0=Auto (guess), 1=ON, 2=OFF |
Use_virtual_keyboard = 0; (Default 0) |
; Indicates if new images should by default use layers. The alternative |
; is animation frames. |
; |
Default_mode_layers = no; (Default no) |
; end of configuration |
/data/common/media/grafx2/grafx2 |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
Property changes: |
Added: svn:mime-type |
+application/octet-stream |
\ No newline at end of property |
/data/common/media/grafx2/scripts/_tst_AAFilter.lua |
---|
0,0 → 1,30 |
-- Apply a kind of AA filter on picture |
-- Get the picture size |
w, h = getpicturesize(); |
-- Here is the filtering matrix |
matrix = { |
{ 0, -1, 0 }, |
{ -1, 5, -1 }, |
{ 0, -1, 0 }}; |
-- Loop trough all the pixels |
-- To make this script simpler we don't handle the picture borders |
-- (the matrix would get pixels outside the picture space) |
-- for var = start_value, end_value, step do ... |
for y = 1, h - 2, 1 do |
for x = 1, w - 2, 1 do |
filtered = |
matrix[1][1] * getbackuppixel(x - 1, y - 1) + |
matrix[1][2] * getbackuppixel(x , y - 1) + |
matrix[1][3] * getbackuppixel(x + 1, y - 1) + |
matrix[2][1] * getbackuppixel(x - 1, y ) + |
matrix[2][2] * getbackuppixel(x , y ) + |
matrix[2][3] * getbackuppixel(x + 1, y ) + |
matrix[3][1] * getbackuppixel(x - 1, y + 1) + |
matrix[3][2] * getbackuppixel(x , y + 1) + |
matrix[3][3] * getbackuppixel(x + 1, y + 1); |
putpicturepixel(x,y,filtered); |
end |
end |
/data/common/media/grafx2/scripts/_tst_GradientBrush.lua |
---|
0,0 → 1,7 |
w, h = getbrushsize() |
for x = 0, w - 1, 1 do |
for y = 0, h - 1, 1 do |
putbrushpixel(x, y, (x+y)%256); |
end |
end |
/data/common/media/grafx2/scripts/_tst_Settings.lua |
---|
0,0 → 1,33 |
-- Test LUA inputbox |
-- this script tests the inputbox |
w, h = getbrushsize() |
--[[ |
messagebox( |
"Forecolor: " .. getforecolor() .. "\n" .. |
"Backcolor: " .. getbackcolor() .. "\n" .. |
"Transparent color: " .. gettranscolor() .. "\n" .. |
"Brush dimensions: " .. w .. "x" .. h |
) |
]] |
ok, w, h = inputbox("Modify brush", |
"RGB", 1, 0, 1, -1, |
"HSV", 0, 0, 1, -1, |
"HSL", 0, 0, 1, -1, |
"Width", w, -900.0,900.0, 3, |
"Height", h, -900.0,900.0, 4, |
"X Flip", 0, 0, 1, 0, |
"Y Flip", 0, 0, 1, 0, |
"Degrees",1, 0, 1, -2, |
"Radians",0, 0, 1, -2 |
); |
if ok == true then |
messagebox( |
"w: " .. w .. "\n" .. |
"h: " .. h .. "\n" |
) |
end |
/data/common/media/grafx2/scripts/_tst_dialog.lua |
---|
0,0 → 1,66 |
local counter=0; |
local printcounter = function () |
windowprint(10,54, string.format("% .3d", counter)); |
end; |
windowopen(100,150, "Dialogtest"); |
windowbutton(6, 18, 54, 14, "Close", 27); -- 1, shortcut=ESC |
windowrepeatbutton(6, 38, 14, 14, "+"); -- 2 |
windowrepeatbutton(26, 38, 14, 14, "-"); -- 3 |
windowbutton(6, 70, 54, 14, "Help"); -- 4 |
windowinput(6, 88, 10); |
printcounter(); |
repeat |
local button, button2, key = windowdodialog(); |
if button == 2 then -- "+" |
counter=counter+1; |
printcounter(); |
end |
if button == 3 then -- "-" |
counter=counter-1; |
printcounter(); |
end |
if button == 4 then -- "Help" |
messagebox("Help screen"); |
end |
until key == 27 or button == 1; |
windowclose(); |
-- messagebox(tostring(button) .. " " .. tostring(button2)); |
---- Open_window(149,118,"Grid"); |
-- Display_cursor(); |
-- Hide_cursor(); |
---- Close_window(); |
---- Update_window_area(0,0,Window_width, Window_height); |
---- clicked_button=Window_clicked_button(); |
-- |
-- -- standard button |
---- Window_set_normal_button(12,92,51,14,"Cancel",0,1,KEY_ESC); -- 1 |
-- -- repeatable button (while held) |
---- Window_set_repeatable_button(202,43,13,11,"-",0,1,SDLK_LAST); -- 8 |
-- -- text input |
-- Window_set_input_button(29,24,3); -- 3 |
-- Window_input_content(input_x_button,str); |
-- Readline(31,26,str,3,INPUT_TYPE_INTEGER); |
-- |
-- -- dropdown |
-- Window_set_dropdown_button(216, 158, 84,14,84,"Preset...", 0,0,1,RIGHT_SIDE|LEFT_SIDE,1); |
-- Window_dropdown_clear_items(Button); |
-- Window_dropdown_add_item(Button,0,"Set"); |
-- |
-- -- vertical scroller |
-- mix_scroller = Window_set_scroller_button(31,20,84,256,1,Main_backups->Pages->Gradients->Range[Current_gradient].Mix); |
-- Window_draw_slider(mix_scroller); |
-- |
-- -- display |
---- Print_in_window(11,26, "X:",MC_Dark,MC_Light); |
---- Print_in_window_limited(Button->Pos_X+3+10,Button->Pos_Y+2,Config.Bookmark_label[bookmark_number],8,MC_Black,MC_Light); |
-- Window_display_frame_in( 6, 21,110, 52); |
-- Window_display_frame(6,17,130,37); |
-- Window_rectangle(panel->Pos_X, panel->Pos_Y, panel->Width, panel->Height+1, MC_Light); |
/data/common/media/grafx2/scripts/_tst_dialog2.lua |
---|
0,0 → 1,33 |
-- |
-- test of GUI library |
-- |
run("libs/gui.lua") |
local counter = gui.label{x=10, y=54, value=0, format="% .3d"} |
local form = gui.dialog{ |
title="Dialogtest", |
w=100, |
h=150, |
counter, |
gui.button{ label="+", |
x=6, y=38, w=14, h=14, repeatable=true, click=function() |
counter.value=counter.value+1; |
counter:render(); |
end}, |
gui.button{ label="-", |
x=26, y=38, w=14, h=14, repeatable=true, click=function() |
counter.value=counter.value-1; |
counter:render(); |
end}, |
gui.button{ label="Help", |
x=6, y=70, w=54, h=14, click=function() |
messagebox("Help screen"); |
end}, |
gui.button{ label="Close", |
x=6, y=18, w=54, h=14, key=27, click=function() |
return true; -- causes closing |
end}, |
} |
form:run() |
/data/common/media/grafx2/scripts/libs/gui.lua |
---|
0,0 → 1,111 |
-- |
-- Event-driven GUI library |
-- |
-- |
gui = { |
-- |
-- dialog() -- |
-- |
dialog = function(args) |
local dia = { |
title = args.title, |
w = args.w, |
h = args.h, |
-- |
widgets = {}, |
-- an indexed array, starting at 1. Used for calling the relevant |
-- callback when a numbered control is clicked. |
callbacks = {}, |
-- |
-- dialog.run() -- |
-- |
run = function(this) |
windowopen(this.w,this.h, this.title or ""); |
-- examine all elements |
for _,widget in ipairs(this.widgets) do |
widget:render() |
end |
repeat |
local button, button2, key = windowdodialog(); |
if button > 0 then |
local c = this.callbacks[button] |
-- run the callback and stop the form if it returns true |
if c ~= nil and c(this) then |
break; |
end |
end |
until key == 27; |
windowclose(); |
end |
} |
local id = 1; |
-- examine all elements |
for _,value in ipairs(args) do |
-- all arguments that are tables are assumed to be widgets |
if type(value)=="table" then |
table.insert(dia.widgets, value) |
-- clickable widgets take up an auto-numbered id |
if (value.click) then |
dia.callbacks[id] = value.click |
id=id+1 |
end |
end |
end |
return dia; |
end, |
-- |
-- button() -- |
-- |
button = function(args) |
local but = { |
x = args.x, |
y = args.y, |
w = args.w, |
h = args.h, |
key = args.key, |
label = args.label, |
click = args.click or donothing, |
render = args.repeatable and function(this) |
windowrepeatbutton(this.x, this.y, this.w, this.h, this.label, this.key or -1); |
end |
or function(this) |
windowbutton(this.x, this.y, this.w, this.h, this.label, this.key or -1); |
end |
} |
return but; |
end, |
-- |
-- label() -- |
-- |
label = function(args) |
local fld = { |
x = args.x, |
y = args.y, |
value = args.value, |
format = args.format, |
fg = args.fg or 0, |
bg = args.bg or 2, |
render = function(this) |
if type(this.format) then |
windowprint(this.x, this.y, string.format(this.format, this.value), this.fg, this.bg); |
else |
windowprint(this.x, this.y, this.value, this.fg, this.bg); |
end |
end |
} |
return fld; |
end, |
-- "do nothing" function. Used as default callback |
donothing = function(this) |
end |
} |
/data/common/media/grafx2/scripts/samples_2.4/brush/ApplyColor.lua |
---|
0,0 → 1,129 |
--BRUSH Remap: Apply PenColor |
--by Richard Fhager |
--http://hem.fyristorg.com/dawnbringer/ |
-- Copyright 2010 Richard Fhager |
-- |
-- 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; version 2 |
-- of the License. See <http://www.gnu.org/licenses/> |
run("../libs/dawnbringer_lib.lua") |
OK,tin,clz,fade,amt,brikeep,falloff,nobg,nopen,briweight = inputbox("Apply PenColor 2 Brush", |
"1. Tint", 1, 0,1,-1, |
"2. Colorize", 0, 0,1,-1, |
"BG->FG color Fade", 0, 0,1,0, |
"AMOUNT % (0-100)", 100, 0,100,0, |
"Preserve Brightness", 1, 0,1,0, |
"Bri/Dark FallOff", 1, 0,1,0, |
"Exclude Background", 1,0,1,0, |
"Exclude PenColor", 0,0,1,0, |
"ColMatch Bri-Weight %", 25, 0,100,0 |
); |
if OK == true then |
function cap(v) return math.min(255,math.max(v,0)); end |
w, h = getbrushsize() |
fg = getforecolor() |
bg = getbackcolor() |
fR,fG,fB = getcolor(fg) |
bR,bG,bB = getcolor(bg) |
pal = db.fixPalette(db.makePalList(256)) |
if nobg == 1 then |
pal = db.stripIndexFromPalList(pal,bg) -- Remove background color from pallist |
end |
if nopen == 1 then |
pal = db.stripIndexFromPalList(pal,fg) -- Remove Pencolor from pallist |
end |
amtA = amt / 100 |
amtR = 1 - amtA |
-- Normalize Pen Color |
lev = (fR+fG+fB)/3 |
fR = fR - lev |
fG = fG - lev |
fB = fB - lev |
--------------------------------------------------- |
-- Colorize (Colourant) (just apply colorbalance) |
-- Tint (make grayscale and apply colorbalance) |
-- |
-- I think it should be the other way around since colorize is the process of adding color to B&W film... |
-- But this is the what Brilliance and others call it |
-- |
if clz == 1 or tin == 1 then |
cols = {} |
for n = 0, 255, 1 do |
r,g,b = getcolor(n) |
a = db.getBrightness(r,g,b) |
mR,mG,mB = fR,fG,fB |
-- Fade between bg & fg pencolor across dark-bright |
if fade == 1 then |
lf = a / 255 |
lr = 1 - lf |
mR = bR*lr + fR*lf |
mG = bG*lr + fG*lf |
mB = bB*lr + fB*lf |
lev = (mR+mG+mB)/3 |
mR = mR - lev |
mG = mG - lev |
mB = mB - lev |
end |
fr,fg,fb = mR,mG,mB |
if brikeep == 1 then |
-- Loose Brightness preservation (ex: applying full red to dark colors) |
brin = db.getBrightness(cap(r+mR),cap(g+mG),cap(b+mB)) |
itot = brin - a |
fr = mR - itot |
fg = mG - itot |
fb = mB - itot |
end |
-- Falloff (Effect weakens at dark and bright colors) |
if falloff == 1 then |
fo = 1 - math.abs((a - 127.5)/127.5)^2 |
fr = fr * fo |
fg = fg * fo |
fb = fb * fo |
end |
if tin == 1 then |
--cols[n+1] = matchcolor((a+fr)*amtA + r*amtR, (a+fg)*amtA + g*amtR, (a+fb)*amtA + b*amtR) |
cols[n+1] = db.getBestPalMatchHYBRID({(a+fr)*amtA+r*amtR, (a+fg)*amtA + g*amtR, (a+fb)*amtA + b*amtR},pal,briweight / 100,true) |
end |
if clz == 1 then |
--cols[n+1] = matchcolor((r+fr)*amtA + r*amtR, (g+fg)*amtA + g*amtR, (b+fb)*amtA + b*amtR) |
cols[n+1] = db.getBestPalMatchHYBRID({(r+fr)*amtA+r*amtR, (g+fg)*amtA + g*amtR, (b+fb)*amtA + b*amtR},pal,briweight / 100,true) |
end |
end |
if nobg == 1 then cols[getbackcolor()+1] = getbackcolor(); end |
for x = 0, w - 1, 1 do |
for y = 0, h - 1, 1 do |
putbrushpixel(x, y, cols[getbrushpixel(x,y) + 1]); |
end |
end |
end; |
-- eof Colorize & Tint |
-------------------------------------------------------- |
end -- OK |
/data/common/media/grafx2/scripts/samples_2.4/brush/Fisheye.lua |
---|
0,0 → 1,31 |
--BRUSH Distortion: FishEye |
--by Richard Fhager |
--http://hem.fyristorg.com/dawnbringer/ |
-- Copyright 2010 Richard Fhager |
-- |
-- 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; version 2 |
-- of the License. See <http://www.gnu.org/licenses/> |
-- This script was adopted from Evalion, a Javascript codecrafting/imageprocessing project |
--http://goto.glocalnet.net/richard_fhager/evalion/evalion.html |
w, h = getbrushsize() |
for y = 0, h - 1, 1 do |
for x = 0, w - 1, 1 do |
ox = x / w; |
oy = y / h; |
v = (math.cos((ox-0.5)*math.pi)*math.cos((oy-0.5)*math.pi))*0.85; |
ox = (1 + ox - (ox-0.5)*v) % 1; |
oy = (1 + oy - (oy-0.5)*v) % 1; |
c = getbrushbackuppixel(math.floor(ox*w),math.floor(oy*h)); |
putbrushpixel(x, y, c); |
end |
end |
/data/common/media/grafx2/scripts/samples_2.4/brush/GrayscaleAvg.lua |
---|
0,0 → 1,24 |
--BRUSH Remap: Grayscale (average) |
--by Richard Fhager |
--http://hem.fyristorg.com/dawnbringer/ |
-- Copyright 2010 Richard Fhager |
-- |
-- 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; version 2 |
-- of the License. See <http://www.gnu.org/licenses/> |
w, h = getbrushsize() |
for x = 0, w - 1, 1 do |
for y = 0, h - 1, 1 do |
r, g, b = getcolor(getbrushpixel(x,y)) |
a = (r+g+b)/3 |
putbrushpixel(x, y, matchcolor(a,a,a)); |
end |
end |
/data/common/media/grafx2/scripts/samples_2.4/brush/GrayscaleDesat.lua |
---|
0,0 → 1,36 |
--BRUSH Remap: Grayscale (desaturate) |
--by Richard Fhager |
--http://hem.fyristorg.com/dawnbringer/ |
-- Copyright 2010 Richard Fhager |
-- |
-- 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; version 2 |
-- of the License. See <http://www.gnu.org/licenses/> |
-- This script was adopted from Evalion, a Javascript codecrafting/imageprocessing project |
--http://goto.glocalnet.net/richard_fhager/evalion/evalion.html |
percent = 100 |
-- |
function desaturate(percent,r,g,b) -- V1.0 by Richard Fhager |
p = percent / 100 |
a = (math.min(math.max(r,g,b),255) + math.max(math.min(r,g,b),0)) * 0.5 * p |
r = r + (a-r*p) |
g = g + (a-g*p) |
b = b + (a-b*p) |
return r,g,b |
end |
-- |
w, h = getbrushsize() |
for x = 0, w - 1, 1 do |
for y = 0, h - 1, 1 do |
putbrushpixel(x, y, matchcolor(desaturate(percent,getcolor(getbrushpixel(x,y))))); |
end |
end |
/data/common/media/grafx2/scripts/samples_2.4/brush/Halfsmooth.lua |
---|
0,0 → 1,34 |
--BRUSH: Halfsize with smoothscaling |
--by Richard Fhager |
--http://hem.fyristorg.com/dawnbringer/ |
-- Copyright 2010 Richard Fhager |
-- |
-- 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; version 2 |
-- of the License. See <http://www.gnu.org/licenses/> |
w, h = getbrushsize() |
setbrushsize(math.floor(w/2),math.floor(h/2)) |
for x = 0, w - 1, 2 do |
for y = 0, h - 1, 2 do |
r1,g1,b1 = getcolor(getbrushbackuppixel(x,y)); |
r2,g2,b2 = getcolor(getbrushbackuppixel(x+1,y)); |
r3,g3,b3 = getcolor(getbrushbackuppixel(x,y+1)); |
r4,g4,b4 = getcolor(getbrushbackuppixel(x+1,y+1)); |
r = (r1 + r2 + r3 + r4 ) / 4; |
g = (g1 + g2 + g3 + g4 ) / 4; |
b = (b1 + b2 + b3 + b4 ) / 4; |
c = matchcolor(r,g,b); |
putbrushpixel(x/2, y/2, c); |
end |
end |
/data/common/media/grafx2/scripts/samples_2.4/brush/Waves.lua |
---|
0,0 → 1,42 |
--BRUSH Distortion: Waves v1.0 |
--by Richard Fhager |
--http://hem.fyristorg.com/dawnbringer/ |
-- Copyright 2010 Richard Fhager |
-- |
-- 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; version 2 |
-- of the License. See <http://www.gnu.org/licenses/> |
-- This script was adopted from Evalion, a Javascript codecrafting/imageprocessing project |
-- http://goto.glocalnet.net/richard_fhager/evalion/evalion.html |
--frq = 2 |
--amp = 0.3 |
-- Adjust power of frequency & amplitude |
frq_adj = 2 |
amp_adj = 0.02 |
ok,frq,amp = inputbox("Settings", |
"Frequency 1-10", 3, 1,10,0, |
"Amplitude 1-10", 3, 1,10,0 |
); |
w, h = getbrushsize() |
for y = 0, h - 1, 1 do |
for x = 0, w - 1, 1 do |
ox = x / w; |
oy = y / h; |
ox = (1 + ox + math.sin(oy*math.pi*frq*frq_adj)*amp*amp_adj) % 1; |
c = getbrushbackuppixel(math.floor(ox*w),y); |
putbrushpixel(x, y, c); |
end |
end |
/data/common/media/grafx2/scripts/samples_2.4/codenetsend.lua |
---|
0,0 → 1,17 |
-- Codenet send for grafx2 2.4 and up, by Michael Ilsaas. |
-- Sends the latest saved picture. Set the IP address of the C64 in the line below. |
ip = "192.168.0.64"; -- <-- IP address of the C64. |
fn, fp = getfilename(); |
picfile = assert(io.open(fp .. '/' .. fn ,"r")); |
picsize = picfile:seek("end") |
picfile:close(); |
if picsize == 9000 or picsize == 9002 then -- check for hires |
os.execute("echo AQgLCAoAnjIwNjIAAAAArQDdKfwJAo0A3ak4jRjQqQiNFtCpO40R0KkAjSDQogC9DA6dAGC9DA+dAGG9DBCdAGK9DBGdAGO9DBKdAGS9DBOdAGW9DBSdAGa9DBWdAGe9DBadAGi9DBedAGm9DBidAGq9DBmdAGu9DBqdAGy9DBudAG29DBydAG69DB2dAG/o4ADQm6IAvQwenQBwvQwfnQBxvQwgnQByvQwhnQBzvQwinQB0vQwjnQB1vQwknQB2vQwlnQB3vQwmnQB4vQwnnQB5vQwonQB6vQwpnQB7vQwqnQB8vQwrnQB9vQwsnQB+vQwtnQB/6OAA0JuiAL1MLZ0ATL1MLp0ATb1ML50ATr1MMJ0AT+jgANDjvUUJnQDAvUUKnQDBvUULnQDCvUUMnQDDvUUNnQDEvUUOnQDF6OAA0NdMAMCpwI00A6mojTUDqQCNNgOpQI03A60B3gkBjQHeor+gxCBbwxAJqQagwqkITLnESKkYoMJoqQ14IP7DEPtYIOH/0ANMucR4IP7DMPGtRAPJCNDqrUUD8ArJBtDhIA/DTDzArUYDyUXQ1K1MAym/DU0D0MqtTwPJEfA2yQHwCKkCIKzCTDzArVoDyQjQIKkAjVoDGK1cA2kIjVwDkAruXQPQBe5cA/D2IDjCIJnCTDzArVwDyRnQB61dA8k+8AipAyCswkw8wK1iA8nK0OCtYwPJH9DZrWUDSKkBjWUDqQCNSAONXgONYAOF+oX7qSCNSQOpGI1fA6kRjWEDrVoDrlwDjloDjVwDrVsDrl0DjlsDjV0DGKISpft9UwOF+6X6fVIDhfrKyhDukAjm+9AE5vrw+KX6Sf+NYAOl+0n/jWEDTl8DIDjCIJnCrWYDhf2tZwOF/K5oA6xpA2jJBPAPyQXwPskG8GvJB/B6TDzAziDQpQFIKfgJA4UBrmkDoAC5agOR/MjK0PdohQHuINAYmGX8ha6FLaX9aQCFr4UuTDzAqTOFAZhIivASrWoDoACR/MiR/MjQ+Ob9ytDzaKrwC61qA6AAkfzIytD6qTeFAUw8wKX80ALG/cb8pf1IpfxIqQhMucSiCL35wZ1AA8oQ96kDSKk/SKkITLnEIFmmIDOlTK6nQkNERk5PIFJSLU5FVCBGT1VORC4NAFJSLU5FVCBGT1VORC4gQ1M4OTAwQSBSRVZJU0lPTiAAogO9UgOdVgO9NAOdUgPKEPGpgI1OA6kAjVADjVEDhfqF+xiiEqX7fUcDhful+n1GA4X6ysoQ7pAI5vvQBOb68Pil+kn/jVADpftJ/41RA6IFvT4DnTgDvb/EnT4DyhDxYBitSQNpDqqtSANpANAEikxpxGBIohy9RgOdXgPKEPeiB6kAnVoDytD6hfqF+41IA6k0jUkDqQGNTwOpA41aA2iNWwMYoh6l+31bA4X7pfp9WgOF+srKEO6QCOb70ATm+vD4pfpJ/41cA6X7Sf+NXQMgOMJMmcKiB71Tw91GA9A5yhD1ogO9NAPdXgPQLMoQ9akCjU0Dogm9TgOdWAO9v8SdTgPKEPGiA700A51UA8oQ9yCHwqk8TGnEYAABCAAGBAABhvyE/SC5wxABYEip/4X6oACYSBhprCDtw4ol+oX6mCX6hfpoqMjAA9DnpfrJ/9AaoACx/KrImEix/KhoSEoJrCDcw2ioyMAG0OipgqIFoA8g3MOpiaLToAAg3MNoYKkAIO3D4A7QF8Bj0BOpASDtw4rQC8ALsAeYOOkHkAFgqf9gCo0C3qkAKo0D3o4E3owF3mAKjQLeqQAqjQPergTerAXeYKmSIO3DmCl/0AOp/2CtCd6tCN6sCd6uCN6Y0CngyLAlikoIqvAToACtCN6ZOAPIrQnemTgDyMrQ7yiQBq0I3pk4A6kAYIpImPAOogCtCN6tCd7o0PeI0PRoqvAMrQjeyvAGrQneytD0qf9gosmODN6iAI4N3o0O3o4P3kipkiDtw5gpf/ASrQnerQjerAnergjeIEPETHrEqZwg7cOYKQHw2mhKaQCqoAC5OAONCN7IuTgDjQneyMrQ72CpAI0g0GAAgBCxMhg= | base64 -d > /tmp/picview.prg"); |
else |
os.execute("echo AQgLCAoAnjIwNjIAAAAArQDdKfwJAo0A3ak4jRjQqRiNFtCpO40R0K0/NY0h0KkAjSDQogC9Lw6dAGC9Lw+dAGG9LxCdAGK9LxGdAGO9LxKdAGS9LxOdAGW9LxSdAGa9LxWdAGe9LxadAGi9LxedAGm9LxidAGq9LxmdAGu9LxqdAGy9LxudAG29LxydAG69Lx2dAG/o4ADQm6IAvS8enQBwvS8fnQBxvS8gnQByvS8hnQBzvS8inQB0vS8jnQB1vS8knQB2vS8lnQB3vS8mnQB4vS8nnQB5vS8onQB6vS8pnQB7vS8qnQB8vS8rnQB9vS8snQB+vS8tnQB/6OAA0JuiAL1vLZ0ATL1vLp0ATb1vL50ATr1vMJ0AT+jgANDjvVcxnQDYvVcynQDZvVcznQDavVc0nQDb6OAA0OO9aAmdAMC9aAqdAMG9aAudAMK9aAydAMO9aA2dAMS9aA6dAMXo4ADQ10wAwKnAjTQDqaiNNQOpAI02A6lAjTcDrQHeCQGNAd6iv6DEIFvDEAmpBqDCqQhMucRIqRigwmipDXgg/sMQ+1gg4f/QA0y5xHgg/sMw8a1EA8kI0OqtRQPwCskG0OEgD8NMPMCtRgPJRdDUrUwDKb8NTQPQyq1PA8kR8DbJAfAIqQIgrMJMPMCtWgPJCNAgqQCNWgMYrVwDaQiNXAOQCu5dA9AF7lwD8PYgOMIgmcJMPMCtXAPJGdAHrV0DyT7wCKkDIKzCTDzArWIDycrQ4K1jA8kf0NmtZQNIqQGNZQOpAI1IA41eA41gA4X6hfupII1JA6kYjV8DqRGNYQOtWgOuXAOOWgONXAOtWwOuXQOOWwONXQMYohKl+31TA4X7pfp9UgOF+srKEO6QCOb70ATm+vD4pfpJ/41gA6X7Sf+NYQNOXwMgOMIgmcKtZgOF/a1nA4X8rmgDrGkDaMkE8A/JBfA+yQbwa8kH8HpMPMDOINClAUgp+AkDhQGuaQOgALlqA5H8yMrQ92iFAe4g0BiYZfyFroUtpf1pAIWvhS5MPMCpM4UBmEiK8BKtagOgAJH8yJH8yND45v3K0PNoqvALrWoDoACR/MjK0PqpN4UBTDzApfzQAsb9xvyl/Uil/EipCEy5xKIIvfnBnUADyhD3qQNIqT9IqQhMucQgWaYgM6VMrqdCQ0RGTk8gUlItTkVUIEZPVU5ELg0AUlItTkVUIEZPVU5ELiBDUzg5MDBBIFJFVklTSU9OIACiA71SA51WA700A51SA8oQ8amAjU4DqQCNUAONUQOF+oX7GKISpft9RwOF+6X6fUYDhfrKyhDukAjm+9AE5vrw+KX6Sf+NUAOl+0n/jVEDogW9PgOdOAO9v8SdPgPKEPFgGK1JA2kOqq1IA2kA0ASKTGnEYEiiHL1GA51eA8oQ96IHqQCdWgPK0PqF+oX7jUgDqTSNSQOpAY1PA6kDjVoDaI1bAxiiHqX7fVsDhful+n1aA4X6ysoQ7pAI5vvQBOb68Pil+kn/jVwDpftJ/41dAyA4wkyZwqIHvVPD3UYD0DnKEPWiA700A91eA9AsyhD1qQKNTQOiCb1OA51YA72/xJ1OA8oQ8aIDvTQDnVQDyhD3IIfCqTxMacRgAAEIAAYEAAGG/IT9ILnDEAFgSKn/hfqgAJhIGGmsIO3DiiX6hfqYJfqF+mioyMAD0Oel+sn/0BqgALH8qsiYSLH8qGhISgmsINzDaKjIwAbQ6KmCogWgDyDcw6mJotOgACDcw2hgqQAg7cPgDtAXwGPQE6kBIO3DitALwAuwB5g46QeQAWCp/2AKjQLeqQAqjQPejgTejAXeYAqNAt6pACqNA96uBN6sBd5gqZIg7cOYKX/QA6n/YK0J3q0I3qwJ3q4I3pjQKeDIsCWKSgiq8BOgAK0I3pk4A8itCd6ZOAPIytDvKJAGrQjemTgDqQBgikiY8A6iAK0I3q0J3ujQ94jQ9Giq8AytCN7K8AatCd7K0PSp/2CiyY4M3qIAjg3ejQ7ejg/eSKmSIO3DmCl/8BKtCd6tCN6sCd6uCN4gQ8RMesSpnCDtw5gpAfDaaEppAKqgALk4A40I3si5OAONCd7IytDvYKkAjSDQYACAELEyGA== | base64 -d > /tmp/picview.prg"); |
end |
if picsize == 9000 or picsize == 10001 then -- check for loadaddress, add two bytes if not found |
os.execute('echo a >> /tmp/picview.prg'); |
end |
os.execute('cat '.. fp .. '/' .. fn .. ' >> /tmp/picview.prg'); -- append pic to c64 binary |
os.execute("codenet -x /tmp/picview.prg -n "..ip); -- send file to c64 |
/data/common/media/grafx2/scripts/samples_2.4/demo/3DPalette.lua |
---|
0,0 → 1,460 |
--3D-Palette viewer V0.72 (HSL-models added, 3D-World added, Pen-color only cycles thru unique colors, InputBox) |
--by Richard 'Dawnbringer' Fhager |
-- Mouse: Rotate Cube (Stops animation) |
-- Arrow-keys: Move Cube (in 3D world) |
-- F1: Start/Stop animation |
-- F2: Reset |
-- F3: Increase Color-Size |
-- F4: Decrease Color-Size |
-- F5: (Wip) Cycle thru selected PenColor (Note that only unique colors are displayed) |
-- F9: RGB-space model |
--F10: HSL-space model |
--F11: HSLcubic-space model |
-- "+" (Num): Zoom In |
-- "-" (Num): Zoom Out |
-- Esc: Exit script |
-- Drawing updated, rectangle missing, Sep11 |
run("../libs/dawnbringer_lib.lua") |
BRIDIAG_SHOW = 1 -- Show brightness/Grayscale diagonal (1 = on, 0 = off) |
ANIM = 1 -- Animation (1 = on, 0 = off) |
BOX_DRK = 8 -- Darkest color used for box (0-255) |
BOX_BRI = 112 -- Brightest color used for box (0-255) |
COLSIZE_BASE = 26 -- Colors base size (value to adjusted by palette-size, with 2 cols maxsize is v / 1.23) |
-- |
OK,RGB,HSL,HSLC,BOX_BRI,COLSIZE_BASE,SET800x600 = inputbox("3D-Palette Viewer Settings", |
"1. RGB space [F9]", 1, 0,1,-1, |
"2. HSL space [F10]", 0, 0,1,-1, |
"3. HSL-cubic space [F11]",0, 0,1,-1, |
"Box Brightness (16-255)", BOX_BRI, 16,255,0, |
"Col Size (1-100) [F3/F4]", COLSIZE_BASE, 1,100,0, |
"Set Screen to 800x600", 1,0,1,0 |
); |
-- |
if OK then |
if SET800x600 == 1 then setpicturesize(800,600); end |
SPACE = "rgb" |
FORM = "cube" |
if HSL == 1 then |
SPACE = "hsl" |
FORM = "cylinder" |
end |
if HSLC == 1 then |
SPACE = "hsl_cubic" |
FORM = "cube" |
end |
pal = db.fixPalette(db.makePalList(256)) |
FG = getforecolor() |
BG = getbackcolor() |
palcol = FG |
-- |
function initColors(space) |
for n = 1, #pal, 1 do |
c = pal[n]; |
if space == "rgb" then |
cols[n] = {c[1]/128-1,c[2]/128-1,c[3]/128-1,c[4]}; |
end |
if space == "hsl_cubic" then |
cols[n] = {} |
cols[n][1] = (db.getHUE(c[1],c[2],c[3],0) / 6.0 * 255) / 128 - 1 |
cols[n][2] = (db.getSaturation(c[1],c[2],c[3])) / 128 - 1 |
cols[n][3] = (db.getLightness(c[1],c[2],c[3])) / 128 - 1 |
cols[n][4] = c[4] |
end |
if space == "hsl" then |
cols[n] = {} |
hue = db.getHUE(c[1],c[2],c[3],0) / 6.0 * math.pi*2 |
rad = db.getSaturation(c[1],c[2],c[3]) / 256 |
cols[n][1] = math.cos(hue) * rad |
cols[n][2] = math.sin(hue) * rad |
cols[n][3] = (db.getLightness(c[1],c[2],c[3])) / 128 - 1 |
cols[n][4] = c[4] |
end |
end |
end |
-- |
cols = {} -- Make points of palette colors |
colz = {} -- To hold calculated points |
initColors(SPACE) |
function initPointsAndLines(form,bridiag) |
if form == "cube" then |
pts = {{-1,1,-1},{1,1,-1},{1,-1,-1},{-1,-1,-1}, -- The box |
{-1,1, 1},{1,1, 1},{1,-1, 1},{-1,-1, 1}} |
lin = {{1,2},{2,3},{3,4},{4,1},{5,6},{6,7},{7,8},{8,5},{1,5},{2,6},{3,7},{4,8}} -- Box Lines |
if bridiag == 1 then lin[13] = {4,6}; end |
end |
if form == "cylinder" then |
p = 28 |
pts = {} |
lin = {} |
for n = 1, p, 1 do |
x = math.cos(math.pi*2 / p * (n-1)) |
y = math.sin(math.pi*2 / p * (n-1)) |
pts[n] = {x,y,-1} |
lin[n] = {n,1 + (n%p)} |
pts[n + p] = {x,y,1} |
lin[n + p] = {n+p,p + 1 + (n%p)} |
end |
lin[p*2+1] = {1,p+1} -- Red (0 degrees) |
lin[p*2+2] = {p+1,p+1+math.ceil(p/2)} -- Lightness end (needs an even # of points to work) |
end |
end |
boxp = {} -- To hold the calculated points |
initPointsAndLines(FORM,BRIDIAG_SHOW) |
w,h = getpicturesize() |
CX,CY = w/2, h/2 |
function initAndReset() |
XANG, YANG, ZANG, ZOOM, COLSIZE_ADJ, XD, YD, WORLD_X, WORLD_Y, ZSELECT = 0,0,0,0,0,0,0,0,0,0 |
end |
initAndReset() |
SIZE = math.min(w,h)/4 |
DIST = 5 -- Distance perspective modifier, ~5 is nominal, more means "less 3D" |
CMAXSIZE = math.floor(COLSIZE_BASE / ((#pal)^0.3)) |
--CMAXSIZE = 8 |
CMINSIZE = 1 -- Negative values are ok. Color are never smaller than 1 pix |
BOX_LINE_DIV = 20 -- Number of colors/segments that a box-line can be divided into (depth) |
BOX_DIV_MULT = BOX_LINE_DIV / (math.sqrt(3)*2) |
-- Box depth colors |
box_div = {} |
for n = 0, BOX_LINE_DIV-1, 1 do |
c = BOX_DRK + (BOX_BRI / (BOX_LINE_DIV - 1)) * n |
--box_div[BOX_LINE_DIV - n] = matchcolor(c,c,c) |
box_div[BOX_LINE_DIV - n] = db.getBestPalMatchHYBRID({c,c,c},pal,0.5,true) |
end |
--BOX_COL = matchcolor(80,80,80) |
BKG_COL = matchcolor(0,0,0) |
--CUR_COL = matchcolor(112,112,112) |
function rotate3D(x,y,z,Xsin,Ysin,Zsin,Xcos,Ycos,Zcos) -- PrecCalced cos&sin for speed |
local x1,x2,x3,y1,y2,y3,f,xp,yp |
x1 = x |
y1 = y * Xcos + z * Xsin |
z1 = z * Xcos - y * Xsin |
x2 = x1 * Ycos - z1 * Ysin |
y2 = y1 |
z2 = x1 * Ysin + z1 * Ycos |
x3 = x2 * Zcos - y2 * Zsin |
y3 = x2 * Zsin + y2 * Zcos |
z3 = z2 |
return x3,y3,z3 |
end |
function do3D(x,y,z,zoom,dist,Xsin,Ysin,Zsin,Xcos,Ycos,Zcos) -- PrecCalced cos&sin for speed |
local x1,x2,x3,y1,y2,y3,f,xp,yp |
x1 = x |
y1 = y * Xcos + z * Xsin |
z1 = z * Xcos - y * Xsin |
x2 = x1 * Ycos - z1 * Ysin |
y2 = y1 |
z2 = x1 * Ysin + z1 * Ycos |
x3 = x2 * Zcos - y2 * Zsin |
y3 = x2 * Zsin + y2 * Zcos |
z3 = z2 |
f = dist/(z3 + dist + zoom) |
xp = x3 * f |
yp = y3 * f |
return xp,yp,z3 |
end |
function draw3Dline(x1,y1,z1,x2,y2,z2,div,mult,depthlist) |
local s,xt,yt,xd,yd,zd,xf,yf |
xd = (x2 - x1) / div |
yd = (y2 - y1) / div |
zd = (z2 - z1) / div |
xf,yf = x1,y1 |
for s = 1, div, 1 do |
-- Depth assumes a 1-Box (z ranges from -sq(3) to sq(3)) |
depth = math.floor(1 + (z1+zd*s + 1.732) * mult) |
xt = x1 + xd*s -- + math.random()*8 |
yt = y1 + yd*s -- + math.random()*8 |
c = depthlist[depth] |
if c == null then c = 1; end -- Something isn't perfect, error is super rare but this controls it |
--db.line(xf,yf,xt,yt,c) |
drawline(xf,yf,xt,yt,c) |
xf = xt |
yf = yt |
end |
end |
function killinertia() |
XD = 0 |
YD = 0 |
end |
-- If using 1-box, z is -sq(3) to sq(3) |
minz = math.sqrt(3) |
totz = minz * 2 |
maxrad = CMAXSIZE - CMINSIZE |
--q = 0 |
--delay = 4 |
--move = 0.03 |
while 1 < 2 do |
-- Time-for-space-wiggle...or somekindof attempt |
--WORLD_X = -move |
--q = (q + 1) % delay |
--if q < delay/2 then WORLD_X = move; end |
clearpicture(BKG_COL) |
Xsin = math.sin(XANG); Xcos = math.cos(XANG) |
Ysin = math.sin(YANG); Ycos = math.cos(YANG) |
Zsin = math.sin(ZANG); Zcos = math.cos(ZANG) |
-- Rotate Box points |
for n = 1, #pts, 1 do |
p = pts[n] |
x,y,z = p[1],p[2],p[3] |
XP,YP,zp = rotate3D(x,y,z,Xsin,Ysin,Zsin,Xcos,Ycos,Zcos) |
boxp[n] = {XP,YP,zp} |
end |
-- Rotate Colors in palette |
for n = 1, #cols, 1 do |
p = cols[n] |
x,y,z,c = p[1],p[2],p[3],p[4] |
XP,YP,zp = rotate3D(x,y,z,Xsin,Ysin,Zsin,Xcos,Ycos,Zcos) |
colz[n] = {XP,YP,zp,c} |
end |
------------------------------------ |
-- Control world |
------------------------------------ |
-- Calculate points anew |
-- Worldize Box points |
for n = 1, #boxp, 1 do |
s = SIZE |
v = boxp[n] |
x = v[1] + WORLD_X |
y = v[2] + WORLD_Y |
z = v[3] |
f = DIST/(z + DIST + ZOOM) |
XP = CX + x * f * s |
YP = CY + y * f * s |
boxp[n] = {XP,YP,z} |
end |
-- Worldize Colors in palette |
for n = 1, #colz, 1 do |
s = SIZE |
v = colz[n] |
x = v[1] + WORLD_X |
y = v[2] + WORLD_Y |
z = v[3] |
c = v[4] |
f = DIST/(z + DIST + ZOOM) |
XP = CX + x * f * s |
YP = CY + y * f * s |
colz[n] = {XP,YP,z,c} |
end |
------------------------------------- |
------------------------------------- |
-- Brightness Diagonal |
--if BRIDIAG_SHOW == 1 then |
-- p1 = boxp[4] |
-- p2 = boxp[6] |
-- x1,y1,z1 = p1[1],p1[2],p1[3] |
-- x2,y2,z2 = p2[1],p2[2],p2[3] |
-- draw3Dline(x1,y1,z1,x2,y2,z2,BOX_LINE_DIV,BOX_DIV_MULT,box_div) |
--end |
--c1 = math.min(FG,BG) |
--c2 = math.max(FG,BG) |
--p = colz[26] |
--XP1,YP1,zp1,c1 = p[1],p[2],p[3],p[4] |
--for n = #colz, 1, -1 do |
-- p = colz[27] |
-- XP2,YP2,zp2,c2 = p[1],p[2],p[3],p[4] |
-- drawline(XP1,YP1,XP2,YP2,c1) |
--end |
-- sort on z |
db.sorti(colz,3) |
-- Draw colors |
for n = #colz, 1, -1 do |
p = colz[n] |
XP,YP,zp,c = p[1],p[2],p[3],p[4] |
radius = CMINSIZE + maxrad - (zp+minz) / totz * maxrad |
dorad = math.floor(radius - ZOOM*2 + COLSIZE_ADJ) |
if dorad >= 1 then |
--db.drawCircle(XP,YP,dorad,c) |
drawdisk(XP,YP,dorad,c) |
--db.drawRectangle(XP,YP,dorad,dorad,c) |
else putpicturepixel(XP,YP,c) |
end |
if c == FG or c == BG then |
sz = math.max(3,dorad + 3) |
if c == BKG_COL then v = (c+128) % 255; c = matchcolor(v,v,v); end |
db.drawRectangleLine(XP-sz,YP-sz,sz*2,sz*2,c) |
end |
end -- colz |
-- Draw box |
for n = 1, #lin, 1 do |
l = lin[n] |
p1 = boxp[l[1]] |
p2 = boxp[l[2]] |
x1,y1,z1 = p1[1],p1[2],p1[3] |
x2,y2,z2 = p2[1],p2[2],p2[3] |
draw3Dline(x1,y1,z1,x2,y2,z2,BOX_LINE_DIV,BOX_DIV_MULT,box_div) |
end -- eof box |
--updatescreen(); if (waitbreak(0.00)==1) then return; end |
repeat |
old_key = key; |
old_mouse_x = mouse_x; |
old_mouse_y = mouse_y; |
old_mouse_b = mouse_b; |
updatescreen() |
moved, key, mouse_x, mouse_y, mouse_b = waitinput(0) |
if mouse_b == 1 then ANIM = 0; end |
if (key==27) then |
return; |
end |
if (key==282) then ANIM = (ANIM+1) % 2; end -- F1: Stop/Start Animation |
if (key==283) then initAndReset(); end -- F2: Reset all values |
if (key==284) then COLSIZE_ADJ = COLSIZE_ADJ + 0.5; end -- F3 |
if (key==285) then COLSIZE_ADJ = COLSIZE_ADJ - 0.5; end -- F4 |
--messagebox(key) |
if (key==286) then |
--FG = (FG + 1) % 255; |
palcol = (palcol + 1) % #pal |
FG = pal[palcol+1][4] |
setforecolor(FG); |
setcolor(0,getcolor(0)) -- Force update of palette until setforecolor() is fixed |
end -- F5 |
if (key==290) then -- F9 |
initColors("rgb") |
initPointsAndLines("cube",BRIDIAG_SHOW) |
end |
if (key==291) then -- F10 |
initColors("hsl") |
initPointsAndLines("cylinder", 0) -- Bridiag won't show even if turned on, it's only for cube |
end |
if (key==292) then -- F11 |
initColors("hsl_cubic") |
initPointsAndLines("cube",BRIDIAG_SHOW) |
end |
if (key==269) then ZOOM = ZOOM + 0.1; end |
if (key==270) then ZOOM = ZOOM - 0.1; end |
if (key==32) then |
ZSELECT = (ZSELECT + math.pi/2) % (2*math.pi); |
--YANG = ((YANG - math.pi/2) % (math.pi*2)); |
--XANG = ((XANG + math.pi/2) % (math.pi*2)); |
YANG = ((YANG + math.pi/2) % (math.pi*2)); |
XANG = ((XANG + math.pi/2) % (math.pi*2)); |
YANG = ((YANG - math.pi/2) % (math.pi*2)); |
end -- Rotate Z 90 Degrees |
SPEED = math.pi / 100 |
if (key==273) then WORLD_Y = WORLD_Y - 0.05; killinertia(); end |
if (key==274) then WORLD_Y = WORLD_Y + 0.05; killinertia(); end |
if (key==276) then WORLD_X = WORLD_X - 0.05; killinertia(); end |
if (key==275) then WORLD_X = WORLD_X + 0.05; killinertia(); end |
until ((mouse_b == 1 and (old_mouse_x~=mouse_x or old_mouse_y~=mouse_y)) or key~=0 or ANIM==1 or math.abs(XD)>0.01 or math.abs(YD)>0.01); |
if ANIM == 0 then |
if (mouse_b==1 and (old_mouse_x~=mouse_x or old_mouse_y~=mouse_y)) then -- Inertia |
XD = (mouse_y - old_mouse_y)*0.005 |
YD = (mouse_x - old_mouse_x)*0.005 |
else |
XD = XD*0.92 |
YD = YD*0.92 |
end |
XANG = ((XANG - XD) % (math.pi*2)); |
YANG = ((YANG + YD) % (math.pi*2)); |
ZANG = ZSELECT |
end |
if ANIM == 1 then |
XANG = (XANG + math.pi/300) % (math.pi*2) |
YANG = (YANG + math.pi/500) % (math.pi*2) |
ZANG = (ZANG + math.pi/1000) % (math.pi*2) |
end |
--XANG = ((CY-mouse_y) / 200 % (math.pi*2)); |
--YANG = ((mouse_x - CX) / 200 % (math.pi*2)); |
--ZANG = 0 |
statusmessage("x"..math.floor(XANG*57.3).."° y"..math.floor(YANG*57.3).."° z"..math.floor(ZANG*57.3).."° Zm: "..math.floor(-ZOOM*10).." ") |
end |
end -- OK |
/data/common/media/grafx2/scripts/samples_2.4/demo/Ellipse.lua |
---|
0,0 → 1,68 |
--PICTURE scene: Ellipse update-demo (anim) |
--Demonstrates 'interactive' features. |
--by Richard Fhager |
-- Copyright 2011 Richard Fhager |
-- |
-- 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; version 2 |
-- of the License. See <http://www.gnu.org/licenses/> |
-- |
-- rot: Rotation in degrees |
-- stp: Step is # of line segments (more is "better") |
-- a & b are axis-radius |
function ellipse2(x,y,a,b,stp,rot,col) |
local n,m=math,rad,al,sa,ca,sb,cb,ox,oy,x1,y1,ast |
m = math; rad = m.pi/180; ast = rad * 360/stp; |
sb = m.sin(-rot * rad); cb = m.cos(-rot * rad) |
for n = 0, stp, 1 do |
ox = x1; oy = y1; |
sa = m.sin(ast*n) * b; ca = m.cos(ast*n) * a |
x1 = x + ca * cb - sa * sb |
y1 = y + ca * sb + sa * cb |
if (n > 0) then drawline(ox,oy,x1,y1,col); end |
end |
end |
-- |
setpicturesize(300,300) |
setcolor(0,96,96,96) |
setcolor(1,255,255,128) |
r1 = 100 |
r2 = 50 |
rt = 0 |
frames = 100 |
while (1 < 2) do |
r1t = 10 + math.random() * 140 |
r2t = 10 + math.random() * 140 |
rtt = math.random() * 360 |
for n = 0, frames-1, 1 do |
clearpicture(0) |
f2 = n / frames |
f1 = 1 - f2 |
r1a = r1*f1 + r1t*f2 |
r2a = r2*f1 + r2t*f2 |
rta = rt*f1 + rtt*f2 |
-- x, y, r1, r2, stp, rot, col |
ellipse2(150, 150, r1a, r2a, 50, rta, 1) |
statusmessage('press ESC to stop') |
updatescreen();if (waitbreak(0)==1) then return end |
end |
r1,r2,rt = r1a,r2a,rta |
end |
/data/common/media/grafx2/scripts/samples_2.4/demo/FlipPicture.lua |
---|
0,0 → 1,17 |
-- flip picture - Copyright 2010 Paulo Silva |
-- 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; version 2 of the License. See <http://www.gnu.org/licenses/> |
w,h=getpicturesize(); |
ok,flipx,flipy=inputbox("flip picture","flip x",1,0,1,-1,"flip y",0,0,1,-1); |
if ok==true then |
if flipx==1 then |
for y=0,h-1,1 do |
for x=0,w/2,1 do |
c1=getpicturepixel(x,y);c2=getpicturepixel(w-x-1,y) |
putpicturepixel(x,y,c2);putpicturepixel(w-x-1,y,c1) |
end;end |
else |
for y=0,h/2,1 do |
for x=0,w-1,1 do |
c1=getpicturepixel(x,y);c2=getpicturepixel(x,h-y-1) |
putpicturepixel(x,y,c2);putpicturepixel(x,h-y-1,c1) |
end;end;end;end |
/data/common/media/grafx2/scripts/samples_2.4/demo/SierpinskyCarpet.lua |
---|
0,0 → 1,59 |
--PICTURE: Pattern - Sierpinsky carpet v1.0 |
--by Richard Fhager |
--http://hem.fyristorg.com/dawnbringer/ |
-- Email: dawnbringer@hem.utfors.se |
-- MSN: annassar@hotmail.com |
-- |
-- Copyright 2010 Richard Fhager |
-- |
-- 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; version 2 |
-- of the License. See <http://www.gnu.org/licenses/> |
-- This script was adopted from Evalion, a Javascript codecrafting/imageprocessing project |
-- http://goto.glocalnet.net/richard_fhager/evalion/evalion.html |
-- |
frac = {{1,1,1},{1,0,1},{1,1,1}} |
iter = 6 |
-- |
function pattern(x,y,p,n,i) -- Fractal Pattern V1.0 by Richard Fhager (mod allows for wrapping) |
py = #p |
px = #p[1] |
while ((p[1+math.abs(math.floor(y*py))%py][1+math.abs(math.floor(x*px))%px]) == 1 and n<i) do |
x=x*px-math.floor(x*px); |
y=y*py-math.floor(y*py); |
n = n+1 |
end |
return 1 - n/i; |
end |
-- |
w, h = getpicturesize() |
rp,gp,bp = getcolor(getforecolor()) |
for y = 0, h - 1, 1 do |
for x = 0, w - 1, 1 do |
ox = x / w; |
oy = y / h; |
f = pattern(ox,oy,frac,0,iter); |
c = matchcolor(rp*f,gp*f,bp*f) |
putpicturepixel(x, y, c); |
end |
updatescreen() |
if (waitbreak(0)==1) then |
return |
end |
end |
/data/common/media/grafx2/scripts/samples_2.4/demo/SierpinskyTriangle.lua |
---|
0,0 → 1,57 |
--PICTURE: Pattern - Sierpinsky triangle v1.0 |
--by Richard Fhager |
--http://hem.fyristorg.com/dawnbringer/ |
-- Email: dawnbringer@hem.utfors.se |
-- MSN: annassar@hotmail.com |
-- |
-- Copyright 2010 Richard Fhager |
-- |
-- 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; version 2 |
-- of the License. See <http://www.gnu.org/licenses/> |
-- This script was adopted from Evalion, a Javascript codecrafting/imageprocessing project |
-- http://goto.glocalnet.net/richard_fhager/evalion/evalion.html |
-- |
frac = {{1,1},{1,0}} |
iter = 15 |
-- |
function pattern(x,y,p,n,i) -- Fractal Pattern V1.0 by Richard Fhager (mod allows for wrapping) |
py = #p |
px = #p[1] |
while ((p[1+math.abs(math.floor(y*py))%py][1+math.abs(math.floor(x*px))%px]) == 1 and n<i) do |
x=x*px-math.floor(x*px); |
y=y*py-math.floor(y*py); |
n = n+1 |
end |
return 1 - n/i; |
end |
-- |
w, h = getpicturesize() |
rp,gp,bp = getcolor(getforecolor()) |
for y = 0, h - 1, 1 do |
for x = 0, w - 1, 1 do |
ox = x / w; |
oy = y / h; |
f = pattern(ox,oy,frac,0,iter); |
c = matchcolor(rp*f,gp*f,bp*f) |
putpicturepixel(x, y, c); |
end |
updatescreen() |
if (waitbreak(0)==1) then |
return |
end |
end |
/data/common/media/grafx2/scripts/samples_2.4/demo/Spritesheet.lua |
---|
0,0 → 1,46 |
--ANIM: Sprite Animator v0.15 |
--Spare page holds data - Plays on current |
--by Richard Fhager |
run("../libs/memory.lua") |
arg=memory.load({XS=16,YS=16,SPACE=1,FRAMES=8,XOFF=0,YOFF=0,FPS=10}) |
OK, XS, YS, SPACE, FRAMES, XOFF, YOFF, FPS = inputbox("Sprite-Sheet Animator", |
"Sprite X-size", arg.XS, 1, 256,0, |
"Sprite Y-size", arg.YS, 1, 256,0, |
"Spacing", arg.SPACE, 0, 32,0, |
"# of Frames", arg.FRAMES,2, 100,0, |
"X-offset", arg.XOFF, 0, 800,0, |
"Y-offset", arg.YOFF, 0, 800,0, |
"Play Speed (FPS)",arg.FPS, 1, 60,0 |
); |
if OK == true then |
memory.save({XS=XS,YS=YS,SPACE=SPACE,FRAMES=FRAMES,XOFF=XOFF,YOFF=YOFF,FPS=FPS}) |
MAXPLAYS = 100 |
w,h = getpicturesize() |
OX = w / 2 - XS/2 |
OY = h / 2 - YS/2 |
for play = 1, MAXPLAYS, 1 do |
for f = 0, FRAMES-1, 1 do |
for y = 0, YS-1, 1 do |
for x = 0, XS-1, 1 do |
sx = x + XOFF + f * (XS + SPACE) |
sy = y + YOFF |
putpicturepixel(OX+x, OY+y, getsparepicturepixel(sx, sy)) |
end |
end |
updatescreen(); if (waitbreak(1/FPS)==1) then return; end |
end |
end -- plays |
end --OK |
/data/common/media/grafx2/scripts/samples_2.4/demo/brush/Amigaball.lua |
---|
0,0 → 1,57 |
--BRUSH Scene: Amigaball 1.0 |
-- |
--Draws the famous 'Amiga ball' in the brush. |
-- |
--by Richard Fhager |
--http://hem.fyristorg.com/dawnbringer/ |
-- Copyright 2010 Richard Fhager |
-- |
-- 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; version 2 |
-- of the License. See <http://www.gnu.org/licenses/> |
-- This script was adopted from Evalion, a Javascript codecrafting/imageprocessing project |
--http://goto.glocalnet.net/richard_fhager/evalion/evalion.html |
w, h = getbrushsize() |
if (w<64 or h<64) then |
setbrushsize(64,64) |
w=64 |
h=64 |
end |
for y = 0, h - 1, 1 do |
for x = 0, w - 1, 1 do |
-- Fractionalize image dimensions |
ox = x / w; |
oy = y / h; |
-- Ball |
Xr = ox-0.5; Yr = oy-0.5; |
W = (1 - 2*math.sqrt(Xr*Xr + Yr*Yr)); |
-- 'FishEye' distortion / Fake 3D |
F = (math.cos((ox-0.5)*math.pi)*math.cos((oy-0.5)*math.pi))*0.65; |
ox = ox - (ox-0.5)*F; |
oy = oy - (oy-0.5)*F; |
-- Checkers |
V = ((math.floor(0.25+ox*10)+math.floor(1+oy*10)) % 2) * 255 * W; |
-- Specularities |
SPEC1 = math.max(0,(1-5*math.sqrt((ox-0.45)*(ox-0.45)+(oy-0.45)*(oy-0.45)))*112); |
SPEC2 = math.max(0,(1-15*math.sqrt((ox-0.49)*(ox-0.49)+(oy-0.48)*(oy-0.48)))*255); |
r = W * 255 + SPEC1 + SPEC2 |
g = V + SPEC1 + SPEC2 |
b = V + SPEC1 + SPEC2 |
putbrushpixel(x, y, matchcolor(r,g,b)); |
end |
end |
/data/common/media/grafx2/scripts/samples_2.4/demo/brush/ColorSphere.lua |
---|
0,0 → 1,38 |
--BRUSH Scene: Sphere of pencolor v1.0 |
--by Richard Fhager |
--http://hem.fyristorg.com/dawnbringer/ |
-- Copyright 2010 Richard Fhager |
-- |
-- 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; version 2 |
-- of the License. See <http://www.gnu.org/licenses/> |
-- This script was adopted from Evalion, a Javascript codecrafting/imageprocessing project |
--http://goto.glocalnet.net/richard_fhager/evalion/evalion.html |
w, h = getbrushsize() |
rp,gp,bp = getcolor(getforecolor()) |
for y = 0, h - 1, 1 do |
for x = 0, w - 1, 1 do |
-- Fractionalize image dimensions |
ox = x / w; |
oy = y / h; |
-- Sphere |
X = 0.5; Y = 0.5; Rd = 0.5 |
a = math.sqrt(math.max(0,Rd*Rd - ((X-ox)*(X-ox)+(Y-oy)*(Y-oy)))) * 1/Rd |
r = rp * a |
g = gp * a |
b = bp * a |
putbrushpixel(x, y, matchcolor(r,g,b)); |
end |
end |
/data/common/media/grafx2/scripts/samples_2.4/demo/brush/FindAA.lua |
---|
0,0 → 1,100 |
--BRUSH: Find AA-colors from pencolors |
--by Richard Fhager |
--http://hem.fyristorg.com/dawnbringer/ |
-- Copyright 2010 Richard Fhager |
-- |
-- 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; version 2 |
-- of the License. See <http://www.gnu.org/licenses/> |
cellw = 8 |
cellh = 4 |
colors = 256 |
setbrushsize(cellw * 3, cellh * 3) |
-- |
function makePalList(cols) |
pal = {} |
for n = 0, cols-1, 1 do |
r,g,b = getcolor(n) |
pal[n+1] = {r,g,b} |
end |
return pal |
end |
-- |
-- |
function getBestPalMatchHYBRID(rgb,pal,briweight) |
local diff,diffC,diffB,best,bestcol,cols,n,c,r,g,b,p,obri,pbri |
cols = #pal |
bestcol = 0 |
best = 9e99 |
r = rgb[1] |
g = rgb[2] |
b = rgb[3] |
obri = math.pow(r*9,2)+math.pow(g*16,2)+math.pow(b*8,2) |
for n=0, cols-1, 1 do |
p = pal[n+1] |
pbri = math.pow(p[1]*9,2)+math.pow(p[2]*16,2)+math.pow(p[3]*8,2) |
diffB = math.abs(obri - pbri) |
diffC = (math.pow(r-p[1],2)+math.pow(g-p[2],2)+math.pow(b-p[3],2)) * 400 |
--diff = diffB + diffC |
diff = briweight * (diffB - diffC) + diffC |
if diff <= best then bestcol = n; best = diff; end |
end |
return bestcol |
end |
-- |
-- |
function drawRectangle(x1,y1,w,h,c) |
for y = y1, y1+h, 1 do |
for x = x1, x1+w, 1 do |
putbrushpixel(x,y,c); |
end |
end |
end |
-- |
palList = makePalList(colors) |
cf = getforecolor() |
cb = getbackcolor() |
rf,gf,bf = getcolor(cf) |
rb,gb,bb = getcolor(cb) |
ra = (rf + rb) / 2 |
ga = (gf + gb) / 2 |
ba = (bf + bb) / 2 |
rgb1 = {ra,ga,ba} |
c1 = getBestPalMatchHYBRID(rgb1,palList,0.0) |
c2 = getBestPalMatchHYBRID(rgb1,palList,0.75) |
c3 = getBestPalMatchHYBRID(rgb1,palList,0.99) |
q = {{cf,c1,cb}, |
{cf,c2,cb}, |
{cf,c3,cb}} |
for y = 0, #q-1, 1 do |
for x = 0, #q[1]-1, 1 do |
drawRectangle(x*cellw,y*cellh,cellw,cellh,q[y+1][x+1]) |
end |
end |
/data/common/media/grafx2/scripts/samples_2.4/demo/brush/Mandelbrot.lua |
---|
0,0 → 1,64 |
--BRUSH Scene: Mandelbrot fractal v0.5 |
-- |
--Draws a Mandelbrot fractal in the current brush. |
-- |
--by Richard Fhager |
--http://hem.fyristorg.com/dawnbringer/ |
-- Copyright 2010 Richard Fhager |
-- |
-- 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; version 2 |
-- of the License. See <http://www.gnu.org/licenses/> |
-- This script was adopted from Evalion, a Javascript codecrafting/imageprocessing project |
--http://goto.glocalnet.net/richard_fhager/evalion/evalion.html |
colors = 64 |
x0 = -1.7 |
x1 = 0.7 |
ym = 0 |
iter = 64 |
ok, x0, x1, ym, iter = inputbox("Fractal data", |
"X0", x0, -2, 2,4, |
"X1", x1, -2, 2,4, |
"midY", ym, -2, 2,4, |
"Iter", iter, 1, 2048,0 |
); |
-- -0.831116819,-0.831116815,0.2292112435,192 |
function mandel(x,y,l,r,o,i) -- pos. as fraction of 1, left coord, right coord, y coord, iterations |
local w,s,a,p,q,n,v,w |
s=math.abs(r-l); |
a = l + s*x; |
p = a; |
b = o - s*(y-0.5); |
q = b; |
n = 1; |
v = 0; |
w = 0; |
while (v+w<4 and n<i) do n=n+1; v=p*p; w=q*q; q=2*p*q+b; p=v-w+a; end; |
return n |
end |
w, h = getbrushsize() |
for x = 0, w - 1, 1 do |
for y = 0, h - 1, 1 do |
q = mandel(x/w,y/h,x0,x1,ym,iter) % colors; |
putbrushpixel(x, y, q); |
end |
end |
/data/common/media/grafx2/scripts/samples_2.4/libs/dawnbringer_lib.lua |
---|
0,0 → 1,3720 |
--DawnBringer function library v1.14 (some drawing replaced) |
--** THIS IS NOT A RUNNABLE SCRIPT! ** |
--by Richard Fhager |
-- http://hem.fyristorg.com/dawnbringer/ |
-- Email: dawnbringer@hem.utfors.se |
-- MSN: annassar@hotmail.com |
-- |
-- Many functions in here was adopted from Evalion, a Javascript codecrafting/imageprocessing project |
-- http://goto.glocalnet.net/richard_fhager/evalion/evalion.html |
-- |
-- |
-- You may access these functions in your own scripts by loading this library, |
-- just add the follwing line as one of the first instructions: |
-- |
-- run("dawnbringer_lib") |
-- |
-- or |
-- |
-- run("../libs/dawnbringer_lib.lua") |
-- |
-- |
-- Note that the functions must be called with the full library object-name, "db.function_name..." |
-- |
-- Global library object |
db = {} |
-- ************************************* |
-- *** Text & Conversions *** |
-- ************************************* |
-- |
-- |
function db.rgb2HEX(r,g,b,prefix) |
local c,n,s,t,z |
c = {r,g,b} |
z = {"0",""} |
t = "" |
for n = 1, 3, 1 do |
s = string.upper(string.format("%x",c[n])) |
t = t..z[#s]..s |
--s = tonumber(c[n],16) |
--t = t..s |
end |
return prefix..t |
end |
-- |
-- ... eof Text & Conversions ... |
-- |
-- ************************************* |
-- *** Custom Math Functions *** |
-- ************************************* |
-- |
-- |
function db.sign(v) |
local s |
s = 0 |
if v > 0 then s = 1; end |
if v < 0 then s = -1; end |
return s |
end |
-- |
function db.distance(ax,ay,bx,by) return math.sqrt((ax-bx)^2 + (ay-by)^2); end |
-- |
function db.rotation (rot_ang,hub_x,hub_y,x,y) -- Rotate coordinates x & y relative hub |
local new_ang,dist,m,xd,yd,v; m = math |
xd=hub_x-x; |
yd=hub_y-y; |
if (not(xd==0 and yd==0)) then |
v = -90; if xd < 0 then v = 90; end |
new_ang = m.atan(yd/xd) - (v+rot_ang) * m.pi/180; |
dist = m.sqrt(xd*xd+yd*yd); |
x = hub_x - m.sin(new_ang)*dist; |
y = hub_y + m.cos(new_ang)*dist; |
end |
return math.floor(x),math.floor(y) -- For drawing purposes |
end |
-- |
-- |
function db.recursiveSum(div,rlev) -- divisons per recursion,recursion levels |
local s,i,m |
s,m = 1,1 |
for i = 1, rlev, 1 do |
m = m*div |
s = s + m |
end |
return s |
end |
-- |
-- |
-- ... eof Custom Math Functions ... |
-- |
-- ************************************* |
-- *** Fractional Scenery *** |
-- ************************************* |
-- |
function db.setSceneryPalette() |
db.colorCigarr(10,28,true) -- 250 colors |
setcolor(250, 208,48,48) |
setcolor(251, 48,208,48) |
setcolor(252, 48,48,208) |
setcolor(253, 224,224,64) |
setcolor(254, 224,64,224) |
setcolor(255, 64,224,224) |
end |
-- |
-- |
function db.star(xf,yf,sx,sy,rgb,haz,out,lum) |
local n,c,dist; c={} |
dist = haz + out * math.sqrt((xf-sx)^2+(yf-sy)^2); |
for n = 1, 3, 1 do c[n] = (rgb[n] * lum) / dist; end |
return c; |
end |
-- |
-- |
function db.zoom(xf,yf,zoom,panx,pany) -- Zoom and Pan in a fractional coord-system |
xf = (xf-0.5)/zoom + 0.5 + panx; |
yf = (yf-0.5)/zoom + 0.5 + pany; |
return xf,yf |
end |
-- |
-- |
function db.rotationFrac(rot_ang,hub_x,hub_y,x,y) -- Rotate coordinates x & y relative hub |
local new_ang,dist,m,xd,yd,v; m = math |
xd=hub_x-x; |
yd=hub_y-y; |
if (not(xd==0 and yd==0)) then |
v = -90; if xd < 0 then v = 90; end |
new_ang = m.atan(yd/xd) - (v+rot_ang) * m.pi/180; |
dist = m.sqrt(xd*xd+yd*yd); |
x = hub_x - m.sin(new_ang)*dist; |
y = hub_y + m.cos(new_ang)*dist; |
end |
return x,y |
end |
-- |
-- |
function db.twirl(x,y,arms,trot,tpow,tang) |
local b,ang,vx,vy,vr,m,deg,tw |
m=math; deg=math.pi/180; tw=.5; |
if (not(x==.5 and y==.5)) then |
ang = m.atan((.5-y)/(.5-x)); |
b = 0; if (x>.5) then b = m.pi; end |
vx = .5-x; vy = .5-y; vr = m.pow(m.sqrt(vx*vx+vy*vy),tpow); |
tw = .5+m.sin(-tang*deg+vr*trot+(ang + b)*arms)*.5; |
end |
return tw; |
end |
-- |
--- Alpha filters |
-- |
function db.alpha1(x,y,amp) -- Coord, Amplify: 0..n |
local p,a,xh,yh,m |
xh=0.5-x; yh=0.5-y; m = math |
p = m.pow(xh*xh+yh*yh,0.7); |
a = m.cos(32*m.pi*p)*m.sin(8*m.pi*(xh+yh)); |
return 1 + (a * amp) |
end |
-- |
-- |
-- ... eof Fractional Scenery ... |
-- |
-- ************************************* |
-- *** Custom Array Functions *** |
-- ************************************* |
-- |
-- Ok, I don't know Lua that well (still unsure about some scopes & refs etc.) |
-- And some features may not be active in Grafx2. So, some of the follwing functions |
-- may exist in Lua/Grafx2...but since I'm not sure if and how they work - I'll prefer |
-- to add a set of my own of known performance. |
-- |
function db.newArrayInit(xs,val) |
local x,ary; ary = {} |
for x = 1, xs, 1 do |
ary[x] = val |
end |
return ary |
end |
-- |
-- |
function db.newArrayInit2Dim(xs,ys,val) |
local x,y,ary; ary = {} |
for y = 1, ys, 1 do |
ary[y] = {} |
for x = 1, xs, 1 do |
ary[y][x] = val |
end |
end |
return ary |
end |
-- |
-- |
-- Merge two arrays into a NEW one: array_c = db.newArrayMerge(array_b,array_b) |
-- |
function db.newArrayMerge(a,b) |
local n,ary; ary = {} |
for n = 1, #a, 1 do |
ary[n] = a[n] |
end |
for n = 1, #b, 1 do |
ary[n+#a] = b[n] |
end |
return ary |
end |
-- |
-- |
-- Generate a copy of an array with a new value added Last |
-- |
function db.newArrayInsertLast(a,val) |
local n,ary; ary = {} |
for n = 1, #a, 1 do |
ary[n] = a[n] |
end |
ary[#a+1] = val |
return ary |
end |
-- |
-- |
-- Generate a copy of an array with a new value added First |
-- |
function db.newArrayInsertFirst(a,val) |
local n,ary; ary = {} |
ary[1] = val |
for n = 2, #a+1, 1 do |
ary[n] = a[n-1] |
end |
return ary |
end |
-- |
-- |
function db.ary2txt(ary) -- One & two dimensions supported [a,b] -> "a,b". [[a,b],[c,d]] -> "a-b, c-d" |
local t,n,m,v |
t = "" |
for n = 1, #ary, 1 do |
if type(ary[n]) == "table" then |
t = t..ary[n][1] |
for m = 2, #ary[n], 1 do |
t = t.."-"..ary[n][m] |
end |
else t = t..ary[n]; |
end |
t = t..", " |
end |
return t |
end |
-- |
-- |
-- *** Array data manipulation *** |
-- |
-- |
-- InsertionSort Array, this is chaos...I'm confused and stomped...don't understand how Lua works... |
-- ...sorting seem be to ok but this code is ugly... |
-- Sort LO-HI |
-- |
-- Screwed up or confused thing here I think, perhaps lo-hi/hi-lo. This is working lo-hi but the code |
-- looks like hi-lo...edit this some day |
-- |
function db.sorti(d,idx) |
local a,j,tmp,l,e |
l = #d |
for a=2, l, 1 do |
tmp = d[a]; |
e = a |
for j=a, 2, -1 do |
e = j |
if d[j-1][idx] > tmp[idx] then d[j] = d[j-1]; e = j-1; else break; end; |
end; |
d[e] = tmp; -- WHY THE F**K CAN'T YOU READ j HERE!?! STUPID ASSUCKING LANGUAGE |
end; |
--return d |
end |
-- |
-- |
function db.shuffle(list) |
local i,n,t |
for n = #list, 2, -1 do |
i = 1+math.floor(math.random() * n) |
t = list[n]; list[n] = list[i]; list[i] = t |
end |
end |
-- |
-- |
-- ... eof Custom Array Functions ... |
-- |
-- ************************************* |
-- *** Misc. Logical Operations *** |
-- ************************************* |
-- |
-- palList [r,g,b,palindex] is expected only to contain unique colors |
-- index = -1 --> index of list |
-- |
function db.makeIndexList(list,index) |
local n,ilist |
ilist = {} |
for n = 1, #list, 1 do |
if (index > 0) then ilist[n] = list[n][index]; end |
if (index == -1) then ilist[n] = n; end |
end |
return ilist |
end |
-- |
-- |
-- Return a list of all possible (non-same) pairs from the entries in a list |
-- [a,b,c] --> [[a,b],[a,c],[b,c]] |
-- (All entries are treated as unique. i.e it's only the INDEX that counts) |
-- mode = 0: Only unique pairs (m = (n^2 - n)/2), [a,b] --> [[a,b]] |
-- mode = 1: All pairs, i.e mirror versions as well. (m = n^2 - n), [a,b] --> [[a,b], [b,a]] |
-- |
function db.pairsFromList(list,mode) |
local a,b,l,n,pairs |
pairs = {} |
l = #list |
n = 1 |
for a = 1, l, 1 do |
for b = a+1, l, 1 do |
pairs[n] = {list[a],list[b]}; n = n + 1 |
if mode == 1 then pairs[n] = {list[b],list[a]}; n = n + 1; end |
end |
end |
return pairs |
end |
-- |
function db.valueInArray(ary,val) |
local n,res |
res = false |
for n = 1, #ary, 1 do |
if ary[n] == val then res = true; break; end |
end |
return res |
end |
-- RAMP specific |
-- Remove initial pair (palList) colors from pallist |
function db.initiateRamp(pair,pallist,pal_index) |
local n,found,plist |
plist = {} |
found = 1 |
for n = 1, #pallist, 1 do |
if db.valueInArray(pair,pallist[n]) == false then |
plist[found] = pallist[n]; found = found + 1; |
end |
end |
pair[pal_index] = plist -- ex: ["pal"] |
return pair -- Is now a 2 color RAMP |
end |
-- |
-- Remove new col entry from ramp's pallist and add it to the ramp, returns an updated ramp |
-- RampList = [1,2] ["pal"] = palList = [3,4,5], addindex = 3 |
-- --> [1,2,3] palList = [4,5] |
function db.updateRamp(ramp,addindex,pal_index) |
local n,found,pallist,plist,newramp |
plist = {} |
pallist = ramp[pal_index] |
-- New palList without added color to IndexList |
found = 1 |
for n = 1, #pallist, 1 do |
if pallist[n] ~= addindex then |
plist[found] = pallist[n]; found = found + 1; |
end |
end |
newramp = db.newArrayInsertLast(ramplist,addindex) |
newramp[pal_index] = plist |
return rlist |
end |
-- |
-- Returns a list of all inital ramps from color pairs |
-- |
-- Weeds out bad pairs, attaches remaining palette colors and the first rgb-vector |
-- |
-- |
function db.initiateRampList(pairs,pallist,pal_index,vec_index,min,maxmult,rw,gw,bw) |
local n,ramplist,newpairs,accept,dist,c1,c2,max,rD,gD,bD |
ramplist = {} |
max = min + (142 / math.sqrt(#pallist)) * maxmult -- min ex: 8-12 |
accept = 0 |
for n = 1, #pairs, 1 do |
c1 = pallist[pairs[n][1]] |
c2 = pallist[pairs[n][2]] |
rD = c2[1] - c1[1] |
gD = c2[2] - c1[2] |
bD = c2[3] - c1[3] |
dist = math.sqrt( (rw*rD)^2 + (gw*gD)^2 + (bw*bD)^2 ) |
if dist >= min and dist <= max then |
accept = accept + 1; ramplist[accept] = db.initiateRamp(pairs[n],pallist,pal_index); |
ramplist[accept][vec_index] = {rD, gD, bD, dist}; -- Add first color vector, ONLY KEEP DISTANCE? |
end |
end |
return ramplist |
end |
function db.findRampExpansionColors(ramp) |
local clist |
clist = {} |
-- Calculate vectors here? |
return clist |
end |
function db.findRAMPS(min_len, max_len) |
local i,n,c,pallist,ramp,ramplist,pairs,spairs,palindex,vecindex,found,donelist,newlist,dones |
local colorlist |
palindex = "pal" |
vecindex = "vector" |
pallist = db.fixPalette(db.makePalList(256), 0) |
pairs = db.pairsFromList(db.makeIndexList(pallist,-1), 0) |
ramplist = db.initiateRampList(pairs,pallist,palindex,vecindex, 8,0.75, 0.26,0.55,0.19) |
-- MIN_LEN = 5 |
-- MAX_LEN = 10 |
-- Split Ramp-build into two parts: |
-- 1. Build ramps >= MIN_LEN, NONE added to 'Done' |
-- 2. Run til no more ramps can be expanded or reaches MAX_LEN, ALL ramps added to 'Done' |
for i = 1, (min_len - 2), 1 do -- Assuming 2 for inital pairs (2 color ramps) |
newlist = {} |
found = 0 |
for n = 1, #ramplist, 1 do |
ramp = ramplist[n] |
colorlist = db.findRampExpansionColors(ramp) -- Colors that can split the current ramp into new expanded ramps |
for c = 1, #colorlist, 1 do |
found = found + 1; newlist[found] = db.updateRamp(ramp,colorlist[c],palindex); -- Ramp is expanded by 1 color |
end |
end |
ramplist = newlist |
end |
donelist = {}; dones = 0 |
repeat |
newlist = {} |
found = 0 |
for n = 1, #ramplist, 1 do |
ramp = ramplist[n] |
if true == false then |
found = found + 1; newlist[found] = db.updateRamp(ramp,color,palindex); |
else |
dones = dones + 1; donelist[dones] = ramp; |
end |
end |
--ramplist = newlist |
until found == 0 |
return #pairs.." - "..#ramplist |
end |
-- |
-- ... eof Misc. Logical Operations ... |
-- |
-- *************************************** |
-- *** General RGB-Color Modifications *** |
-- *************************************** |
-- |
function db.makeComplementaryColor(r,g,b,brikeeplev) -- Lev: 0 = Normal, 1 = Loose, 2 = Strict |
local bri_o,bri_n,bdiff |
function cap(v) return math.max(0,math.min(v,255)); end |
bri_o = db.getBrightness(r,g,b) |
r,g,b = db.shiftHUE(r,g,b,180) |
if brikeeplev > 0 then |
for n = 0, brikeeplev*3-1, 1 do -- Must iterate to reduce brightness error |
bri_n = db.getBrightness(r,g,b) |
bdiff = (bri_o - bri_n) / 2 * brikeeplev |
r = cap(r + bdiff) |
g = cap(g + bdiff) |
b = cap(b + bdiff) |
end |
end |
return r,g,b |
end |
-- |
-- *** Color balance *** |
-- |
-- bri_flag: Preserve brightness |
-- loose_flag: Loose preservation restrictions for brightness and balance |
-- |
-- Jeez, was this a tricky sucker; color-balance is just adding and capping... |
-- but trying color-balance with preserved perceptual brightness is a different monster... |
-- ...so bad I could only solve it by iterative error correction. |
-- |
function db.ColorBalance(r,g,b,rd,gd,bd,bri_flag,loose_flag) -- preserve brightness |
local rw,gw,bw,ri,gi,bi,itot,rni,gni,bni,ro,go,bo,ovscale,lev,count,rt,gt,bt,rf,gf,bf,bri |
-- Dawn 3.0, [0.26,0.55,0.19], 0-255 bri-colorscale adjust = 1.56905 |
rw,gw,bw = 0.26, 0.55, 0.19 |
function cap(v) return math.min(255,math.max(v,0)); end |
bri = db.getBrightness(r,g,b) |
-- Loose brightness & balance preservation, a good compromise. |
if bri_flag == true and loose_flag == true then |
lev = (rd + gd + bd) / 3 |
rd = rd - lev |
gd = gd - lev |
bd = bd - lev |
brin = db.getBrightness(cap(r+rd),cap(g+gd),cap(b+bd)) |
itot = brin - bri |
rd = rd - itot |
gd = gd - itot |
bd = bd - itot |
end |
if bri_flag == true and loose_flag == false then |
itot = 255 |
count = 0 |
-- Normalize (Yup, it's right only to normalize once first..cont.norm. will have some counter-effect) |
lev = (rd + gd + bd) / 3 |
rd = rd - lev |
gd = gd - lev |
bd = bd - lev |
repeat |
--messagebox("Norm:"..rd..", "..gd..", "..bd) |
-- Calculate total brightness change |
-- Note: Perceptual Brightness is exponential, and can't be delta-adjusted for anything other than greyscales. |
-- Although the formula for the new brightness corrected normalization level can can be derived... |
-- ...it doesn't do much good since the bigger problem is overflow outside the 0-255 boundary. |
-- As for now, I see no other means to solve this issue than with iterative error-correction. |
rt = r+rd |
gt = g+gd |
bt = b+bd |
itot = 9e99 |
rni = rd |
gni = gd |
bni = bd |
-- We can get brightness of negative values etc. So bri-correction is put on hold until values are scaled down |
if (rt>=0 and gt>=0 and bt>=0) and (rt<256 and gt<256 and bt<256) then |
brin = db.getBrightness(rt,gt,bt) |
itot = brin - bri |
--messagebox("Bri Diff: "..itot) |
-- Brightness adjusted balance |
rni = rd - itot |
gni = gd - itot |
bni = bd - itot |
end |
--messagebox("Bri Adj Bal:"..rni..", "..gni..", "..bni) |
-- Apply balance to find overflow (as fraction of the channel change) |
ro = math.max( math.max((r + rni)-255,0), math.abs(math.min((r + rni),0)) ) / math.max(math.abs(rni),1) |
go = math.max( math.max((g + gni)-255,0), math.abs(math.min((g + gni),0)) ) / math.max(math.abs(gni),1) |
bo = math.max( math.max((b + bni)-255,0), math.abs(math.min((b + bni),0)) ) / math.max(math.abs(bni),1) |
ovscale = 1 - math.max(ro,go,bo) |
-- Scaling balances might be logically incorrect (as they can be seen as constant differences) |
-- But scaling DOWN is quite harmless and I don't see how it could be done otherwise... |
-- ex: +10 red, +5 blue: Scale x2 = +20 red, +10 blue -> More red over blue than ordered, a contrast behaviour. |
-- +10 red, +5 blue: Scale x0.5 = +5 red, +2.5 blue -> Less of everything, but a part of the order. Harmless? |
-- |
rd = rni * ovscale |
gd = gni * ovscale |
bd = bni * ovscale |
count = count + 1 |
--messagebox("Final bal:"..rd..", "..gd..", "..bd) |
until math.abs(itot) < 1 or count > 5 |
end |
rf = r + rd |
gf = g + gd |
bf = b + bd |
--messagebox("Result color:"..rf..", "..gf..", "..bf) |
return rf,gf,bf |
end |
-- |
-- |
-- bri_flag: Preserve brightness |
-- cap_flag: Cap new color at 0-255, has a desaturating effect for large values. |
-- |
function db.ColorBalanceXXX(r,g,b,rd,gd,bd,bri_flag,cap_flag) -- preserve brightness |
local rf,gf,bf |
if cap_flag == true then |
rd = math.min(255,math.max(0, r+rd)) - r |
gd = math.min(255,math.max(0, g+gd)) - g |
bd = math.min(255,math.max(0, b+bd)) - b |
end |
local rw,gw,bw,ri,gi,bi,itot,rni,gni,bni,ro,go,bo,ovscale |
-- Dawn 3.0, [0.26,0.55,0.19], 0-255 bri-colorscale adjust = 1.56905 |
rw,gw,bw = 0.26, 0.55, 0.19 |
if bri_flag == true then |
-- Calculate total brightness change |
--ri = rd * rw |
--gi = gd * gw |
--bi = bd * bw |
--itot = math.sqrt(ri^2 + gi^2 + bi^2) |
bri = db.getBrightness(r,g,b) |
brin = db.getBrightness(r+rd,g+gd,b+bd) |
itot = brin - bri |
-- Normalized and Brightness adjusted balance |
rni = rd - itot |
gni = gd - itot |
bni = bd - itot |
-- Apply balance to find overflow (as fraction of the channel change) |
ro = math.max( math.max((r + rni)-255,0), math.abs(math.min((r + rni),0)) ) / math.max(math.abs(rni),1) |
go = math.max( math.max((g + gni)-255,0), math.abs(math.min((g + gni),0)) ) / math.max(math.abs(gni),1) |
bo = math.max( math.max((b + bni)-255,0), math.abs(math.min((b + bni),0)) ) / math.max(math.abs(bni),1) |
ovscale = 1 - math.max(ro,go,bo) |
rd = rni * ovscale |
gd = gni * ovscale |
bd = bni * ovscale |
end |
rf = r + rd |
gf = g + gd |
bf = b + bd |
return rf,gf,bf |
end |
-- |
-- |
function db.getContrast(ch) -- Channel, returns fraction -1..0..1, negative for ch < 127.5 |
--return math.abs((ch / 127.5) - 1) |
return (ch / 127.5) - 1 |
end |
-- |
-- |
function db.getAvgContrast(r,g,b) |
return (math.abs(db.getContrast(r)) + math.abs(db.getContrast(g)) + math.abs(db.getContrast(b))) / 3 |
end |
-- |
-- |
-- Mode = 0: Proportional - all colors reach max contrast at 100% |
-- |
-- Mode = 1: Linear - percentage simply added |
-- |
function db.changeContrastOLD(r,g,b,prc,mode) |
local m,rd,gd,bd,rv,gv,bv,rc,gc,bc,base,sign |
base = 1; sign = 1 |
if prc < 0 then base = 0; sign = -1; end -- decontrast |
m = prc / 100 * sign |
-- mode 0 |
rc = db.getContrast(r) |
rd = (base - math.abs(rc)) * m * db.sign(rc) |
rv = (rc+rd+1) * 127.5 |
gc = db.getContrast(g) |
gd = (base - math.abs(gc)) * m * db.sign(gc) |
gv = (gc+gd+1) * 127.5 |
bc = db.getContrast(b) |
bd = (base - math.abs(bc)) * m * db.sign(bc) |
bv = (bc+bd+1) * 127.5 |
return rv,gv,bv |
end |
-- |
function db.changeContrast(r,g,b,prc) -- Photoshop style |
local m,rd,gd,bd,rv,gv,bv,rc,gc,bc |
m = 1 + math.pow((255 / 100 * prc),3) / (255*255) |
-- decontrast |
if prc < 0 then |
m = 1 - math.abs(prc)/100 |
end |
rc = db.getContrast(r) |
rd = rc * m |
rv = (rd+1) * 127.5 |
gc = db.getContrast(g) |
gd = gc * m |
gv = (gd+1) * 127.5 |
bc = db.getContrast(b) |
bd = bc * m |
bv = (bd+1) * 127.5 |
return rv,gv,bv |
end |
-- |
function db.getBrightness(r,g,b) -- 0-255 |
local bri |
--bri = (r+g+b)/3 |
--bri = r*0.3 + g*0.59 + b*0.11 -- Luma Y'601 |
--bri = math.sqrt((r*0.3)^2 + (g*0.59)^2 + (b*0.11)^2) -- Luma Y'601 |
--bri = r*0.245 + g*0.575 + b*0.18 -- Dawn 2.0 |
bri = math.sqrt((r*0.26)^2 + (g*0.55)^2 + (b*0.19)^2) * 1.56905 -- Dawn 3.0 |
return bri |
end |
-- |
-- |
-- Note on desaturation: These functions are all junk, the only way to desaturate |
-- is to fade a color into it's corresponding greyscale. |
-- |
-- |
function db.desaturate(percent,r,g,b) -- V1.0 by Richard Fhager |
local a,p |
p = percent / 100 |
a = (math.min(math.max(r,g,b),255) + math.max(math.min(r,g,b),0)) * 0.5 * p |
r = r + (a-r*p) -- a+r*(1-p) |
g = g + (a-g*p) |
b = b + (a-b*p) |
return r,g,b |
end |
-- |
-- |
function db.desaturateA(percent,c) -- array version |
local r,g,b,a |
r = c[1] |
g = c[2] |
b = c[3] |
p = percent / 100 |
a = (math.min(math.max(r,g,b),255) + math.max(math.min(r,g,b),0)) * 0.5 * p |
r = r + (a-r*p) |
g = g + (a-g*p) |
b = b + (a-b*p) |
return {r,g,b} |
end |
-- |
-- |
function db.desatAVG(desat,c) -- Desaturation, simpe average |
r = c[1] |
g = c[2] |
b = c[3] |
p = desat / 100 |
a = (r+g+b)/3 |
r = r + p*(a-r) |
g = g + p*(a-g) |
b = b + p*(a-b) |
return {r,g,b} |
end |
-- |
-- |
function db.getSaturation(r,g,b) -- HSL |
local M,m,c,s,l |
M = math.max(r,g,b) |
m = math.min(r,g,b) |
c = (M - m)/255 |
s = 0 |
if c ~= 0 then |
--l = (0.3*r + 0.59*g + 0.11*b)/255 -- HSLuma: Y'601 |
l = (M+m)/510 -- This produces a quite "correct looking" divison of saturation |
if l <= 0.5 then s = c / (2*l); end |
if l > 0.5 then s = c / (2-2*l); end |
end |
return math.min(255,s * 255) |
end |
-- |
-- |
function db.getTrueSaturationX(r,g,b) -- Distance from grayscale axis. Not HSV/HSL |
local sat,bri |
bri = (r+g+b) / 3 |
sat = math.min(255, math.sqrt((r-bri)^2 + (g-bri)^2 + (b-bri)^2) * 1.224744875) |
return sat |
end |
-- |
-- WIP. Trying to find a more natural model for estimating Saturation |
-- Current: (HSL + True) / 2 |
function db.getAppSaturation(r,g,b) |
return math.min(255, (db.getSaturation(r,g,b) + db.getTrueSaturationX(r,g,b)) / 2) |
end |
-- |
-- |
function db.saturate(percent,r,g,b) |
local a,m,p,mc |
a = (math.min(math.max(r,g,b),255) + math.max(math.min(r,g,b),0)) * 0.5 |
m = math.min(255-math.max(r,g,b), math.min(r,g,b)) |
p = percent * (m / 100) |
mc = math.max((r-a),(g-a),(b-a)) -- Can this be derived elsewhere? |
if mc ~= 0 then |
r = r + (r-a) * p / mc |
g = g + (g-a) * p / mc |
b = b + (b-a) * p / mc |
end |
return r,g,b |
end |
-- |
-- |
-- Super Saturate: Better than Photoshop etc. |
-- |
-- Higher than 100% power is ok |
-- |
function db.saturateAdv(percent,r,g,b,brikeeplev,greydamp) -- brikeep = 0 - 2 |
local a,m,p,mc,bri_o,bri_n,bdiff,mx,mi,adj,q,n |
function cap(v) return math.max(0,math.min(v,255)); end |
mx = math.max(r,g,b) |
mi = math.min(r,g,b) |
bri_o = db.getBrightness(r,g,b) |
a = (math.min(mx,255) + math.max(mi,0)) * 0.5 |
m = math.min(255-mx, mi) |
p = percent * (m / 100) |
mc = math.max((r-a),(g-a),(b-a)) -- Can this be derived elsewhere? |
if mc ~= 0 and m ~= 0 then |
adj = math.min(1,(mx - mi) / m) -- Reduce effect on low saturation |
if greydamp == false then adj = 1; end |
q = p / mc * adj |
r = cap( r + (r-a) * q ) |
g = cap( g + (g-a) * q ) |
b = cap( b + (b-a) * q ) |
end |
for n = 0, brikeeplev*2, 1 do -- Must iterate to reduce brightness error |
bri_n = db.getBrightness(r,g,b) |
bdiff = (bri_o - bri_n) / 2 * brikeeplev |
r = cap(r + bdiff) |
g = cap(g + bdiff) |
b = cap(b + bdiff) |
end |
return r,g,b |
end |
-- |
-- |
-- Lightness: Darken / Brighten color (Argument and returnvalue is a rgb-list) |
-- Rate of change is inversely proportional to the distance of the max/min. |
-- i.e. all colors/channels will reach max/min at the same time (at 0 or 100 %) |
-- (As opposed to 'Brightness' where all channels are changed by a constant value) |
-- |
function db.lightness(percent,c) |
local v,r,g,b,p |
r = c[1] |
g = c[2] |
b = c[3] |
p = math.abs(percent/100) |
v = 255 |
if percent < 0 then v = 0; end |
r = r + (v - r)*p |
g = g + (v - g)*p |
b = b + (v - b)*p |
return {r,g,b} |
end |
-- |
-- |
function db.changeLightness(r,g,b,percent) |
local v |
v = db.lightness(percent,{r,g,b}) |
return v[1],v[2],v[3] |
end |
-- |
-- |
function db.getLightness(r,g,b) -- HSL bi-hexcone |
return (math.max(r,g,b) + math.min(r,g,b)) / 2 |
end |
-- |
-- |
function db.shiftHUE(r,g,b,deg) -- V1.3 R.Fhager 2007, (Heavily derived code, hehe...) |
local c,h,mi,mx,d,s,p,i,f,q,t |
c = {g,b,r} |
mi = math.min(r,g,b) |
mx = math.max(r,g,b); v = mx; |
d = mx - mi; |
s = 0; if mx ~= 0 then s = d/mx; end |
p = 1; if g ~= mx then p = 2; if b ~= mx then p = 0; end; end |
if s~=0 then |
h=(deg/60+(6+p*2+(c[1+p]-c[1+(p+1)%3])/d))%6; |
i=math.floor(h); |
f=h-i; |
p=v*(1-s); |
q=v*(1-s*f); |
t=v*(1-s*(1-f)); |
c={v,q,p,p,t,v} |
r = c[1+i] |
g = c[1+(i+4)%6] |
b = c[1+(i+2)%6] |
end |
return r,g,b |
end |
-- |
-- |
function db.getHUE(r,g,b,greytol) -- 0-6 (6.5 = Greyscale), mult. with 60 for degrees |
-- 1 Color diff is roughly detected by Tolerance = 0.0078125 (Tol. incr. with lightness etc.) |
local c,h,mi,mx,d,s,p,i,f,q,t |
c = {g,b,r} |
mi = math.min(r,g,b) |
mx = math.max(r,g,b); v = mx; |
d = mx - mi; |
s = 0; if mx ~= 0 then s = d/mx; end |
p = 1; if g ~= mx then p = 2; if b ~= mx then p = 0; end; end |
h = 6.5 -- for custom graphical purposes |
if s>greytol then -- can't use >= |
h=(6+p*2+(c[1+p]-c[1+(p+1)%3])/d)%6; |
end |
return h |
end |
-- |
-- |
-- ... eof RGB color modifications ... |
-- |
-- **************************************** |
-- *** Custom Color / Palette functions *** |
-- **************************************** |
--# of Unique colors in palette: |
--#db.fixPalette(db.makePalList(256)) |
--# of Colors in Image: |
--#db.makePalListFromHistogram(db.makeHistogram()) |
--# of Unique colors in Image: |
--#db.fixPalette(db.makePalListFromHistogram(db.makeHistogram())) |
-- |
function db.rgbcap(r,g,b,mx,mi) |
local m = math |
return m.max(mi,m.min(r,mx)), m.max(mi,m.min(g,mx)), m.max(mi,m.min(b,mx)) |
end |
-- |
-- |
function db.rgbcapInt(r,g,b,mx,mi) |
local m = math |
return m.floor(m.max(mi,m.min(r,mx))), m.floor(m.max(mi,m.min(g,mx))), m.floor(m.max(mi,m.min(b,mx))) |
end |
-- |
-- |
function db.makePalList(cols) |
local pal,n,r,g,b |
pal = {} |
for n = 0, cols-1, 1 do |
r,g,b = getcolor(n) |
pal[n+1] = {r,g,b,n} |
end |
return pal |
end |
-- |
-- |
function db.makeSparePalList(cols) |
local pal,n,r,g,b |
pal = {} |
for n = 0, cols-1, 1 do |
r,g,b = getsparecolor(n) |
pal[n+1] = {r,g,b,n} |
end |
return pal |
end |
-- |
-- |
-- Use to remove the black colors (marks unused colors) from palette-list |
-- if it's known that no black color exists in the image. |
function db.stripBlackFromPalList(pallist) |
local i,u,c,dummy; i = 257 -- Do 'nothing' If using a full 256 col palette with no blacks |
for u = 1, #pallist, 1 do |
c = pallist[u] |
if (c[1]+c[2]+c[3]) == 0 then i = u; end |
end |
dummy = table.remove(pallist,i) |
return pallist |
end |
-- |
-- |
function db.stripIndexFromPalList(pallist,colindex) |
local i,u,c,dummy |
for u = 1, #pallist, 1 do |
c = pallist[u] |
if c[4] == colindex then i = u; end |
end |
dummy = table.remove(pallist,i) |
return pallist |
end |
-- |
-- |
function db.addHSBtoPalette(pallist) |
local n,hue,sat,rgb |
for n=1, #pallist, 1 do |
rgb = pallist[n] |
pallist[n][5] = db.getHUE(rgb[1],rgb[2],rgb[3],0) |
pallist[n][6] = db.getSaturation(rgb[1],rgb[2],rgb[3]) |
pallist[n][7] = db.getBrightness(rgb[1],rgb[2],rgb[3]) |
end |
return pallist -- {r,g,b,n,bri,hue,sat} |
end |
-- |
-- |
function db.makePalListRange(start,ends) |
local pal,n,r,g,b,a |
pal = {} |
a = 1 |
for n = start, ends, 1 do |
r,g,b = getcolor(n) |
pal[a] = {r,g,b,n}; a = a + 1; |
end |
return pal |
end |
-- |
-- |
function db.makePalListShade(cols,sha) -- Convert colors to less bits, colorcube operations etc. |
local pal,n,r,g,b,mf,div |
mf = math.floor |
div = 256 / sha |
pal = {} |
for n = 0, cols-1, 1 do |
r,g,b = getcolor(n) |
pal[n+1] = {mf(r/div),mf(g/div),mf(b/div),n} |
end |
return pal |
end |
-- |
-- |
function db.makePalListShadeSPARE(cols,sha) -- Convert colors to less bits, colorcube operations etc. |
local pal,n,r,g,b,mf,div |
mf = math.floor |
div = 256 / sha |
pal = {} |
for n = 0, cols-1, 1 do |
r,g,b = getsparecolor(n) |
pal[n+1] = {mf(r/div),mf(g/div),mf(b/div),n} |
end |
return pal |
end |
-- |
-- |
function db.getColorDistance_weight(r1,g1,b1,r2,g2,b2,rw,gw,bw) |
return math.sqrt( (rw*(r1-r2))^2 + (gw*(g1-g2))^2 + (bw*(b1-b2))^2 ) |
end |
-- |
-- |
-- Since brightness is exponential, each channel may work as a "star" drowning the color |
-- of a lesser channel. This algorithm is an approximation to adjust distances for this phenomenon. |
-- Ex: Adding 32 red to black is visually obvious, but adding 64 red to full green is almost |
-- impossible to detect by the naked eye. |
-- |
-- However this isn't a complete solution so we may weigh in brightness as well... |
-- |
-- If cv = 0 (0..1) then prox acts as ordinary perceptual colordistance |
-- if bri = 1 (0..1) then distance is only that of brightness |
function db.getColorDistanceProx(r1,g1,b1,r2,g2,b2,rw,gw,bw,normalizer, cv,briweight) |
local rp1,gp1,bp1,rp2,gp2,bp2,v,m1,m2,prox,bdiff; v = 2*255*255 |
m1 = math.max(r1,g1,b1) |
m2 = math.max(r2,g2,b2) |
rp1 = 1 - math.sqrt((r1-m1)^2 / v) * cv |
gp1 = 1 - math.sqrt((g1-m1)^2 / v) * cv |
bp1 = 1 - math.sqrt((b1-m1)^2 / v) * cv |
rp2 = 1 - math.sqrt((r2-m2)^2 / v) * cv |
gp2 = 1 - math.sqrt((g2-m2)^2 / v) * cv |
bp2 = 1 - math.sqrt((b2-m2)^2 / v) * cv |
bdiff = math.abs(db.getBrightness(r1,g1,b1) - db.getBrightness(r2,g2,b2)) -- weights are hardcoded in function |
prox = math.sqrt( (rw*(r1*rp1-r2*rp2))^2 + (gw*(g1*gp1-g2*gp2))^2 + (bw*(b1*bp1-b2*bp2))^2 ) * normalizer |
return prox * (1-briweight) + bdiff * briweight |
end |
-- |
-- |
function db.getBestPalMatch(r,g,b,pal,index_flag) -- pal = [r,g,b,palindex], index_flag -> return palindex if pal is sorted or reduced |
local diff,best,bestcol,cols,n,c,p |
cols = #pal |
bestcol = -1 |
best = 9e99 |
for n=1, cols, 1 do |
p = pal[n] |
diff = db.getColorDistance_weight(r,g,b,p[1],p[2],p[3],0.26,0.55,0.19) * 1.569 |
if diff < best then bestcol = n; best = diff; end |
end |
if index_flag == true then |
bestcol = pal[bestcol][4] + 1 |
end |
return bestcol-1 -- palList index start at 1, image-palette at 0 |
end |
-- |
-- Normally this function will return the (image)palette index of best color |
-- ...but if the palette has been sorted with 'fixPalette' it will return the index |
-- of the custom palList, setting index_flag will convert this value to image-palette index |
-- |
-- HYBRID means the colormatch is a combo of color and (perceptual)brightness |
-- |
-- |
function db.getBestPalMatchHYBRID(rgb,pal,briweight,index_flag) -- Now correctly balanced |
local diff,diffC,diffB,best,bestcol,cols,n,c,r,g,b,p,obri,pbri |
cols = #pal |
bestcol = -1 |
best = 9e99 |
--messagebox(briweight) |
-- Note: Not secured against negative values (this algorithm is SLOW, we cannot afford it) |
r = rgb[1] |
g = rgb[2] |
b = rgb[3] |
obri = db.getBrightness(r,g,b) -- 0-255 |
for n=1, cols, 1 do |
p = pal[n] |
pbri = db.getBrightness(p[1],p[2],p[3]) |
diffB = math.abs(obri - pbri) |
-- we need to normalize the distance by the weights |
diffC = db.getColorDistance_weight(r,g,b,p[1],p[2],p[3],0.26,0.55,0.19) * 1.569 |
diff = briweight * (diffB - diffC) + diffC |
if diff < best then bestcol = n; best = diff; end |
end |
if index_flag == true then |
bestcol = pal[bestcol][4] + 1 -- Since we detract 1 on return, God Lua is stupid |
end |
return bestcol-1 -- palList index start at 1, image-palette at 0 |
end |
-- |
-- |
-- Special version of Hybrid-remapping for mixPalette list |
-- |
-- mixpal: {score,col#1,col#2,dist,rm,gm,bm, c1_r,c1_g,c1_b, c2_r,c2_g,c2_b} |
-- |
-- returns: {col#1,col#2} (index of palette) |
-- |
function db.getBestPalMatchHybridMIX(rgb,mixpal,briweight,mixreduction) |
local diff,diffC,diffB,best,bestcol,cols,n,c,r,g,b,p,obri,pbri, distmult |
cols = #mixpal |
bestcol = -1 |
best = 9e99 |
-- We will simply add the the distance to the mix with the distance between the mixcolors and |
-- employ a user tolerance to much the latter will matter. |
--distmult = 255 / 9.56 / 100 * mixreduction -- 16 shades |
distmult = 1.56902 / 100 * mixreduction -- 24-bit, Dawn3.0 colormodel |
-- Note: Not secured against negative values (this algorithm is SLOW, we cannot afford it) |
r = rgb[1] |
g = rgb[2] |
b = rgb[3] |
obri = db.getBrightness(r,g,b) -- 0-255 |
for n=1, cols, 1 do |
p = mixpal[n] |
--pbri = db.getBrightness(p[5],p[6],p[7]) |
-- *** DawnBringer's exponetial color brightness dither resolution phenomena theorem *** |
-- Bri = color value ^ 2 |
-- Two adjacent pixels displayed with "normal high resolution" will NOT have the perceptual |
-- brightness of the resulting mixcolor. The brightness lies closer to that of the brightest pixel. |
-- Bri[(C1+C2)/2] = SQRT( (C1bri^2 + C2bri^2) / 2 ) |
-- (Brightness according to Dawn-model: bri = SQRT( (r*.26)^2 + (g*.55)^2 + (b*.19)^2 ) ) |
pbri = math.sqrt((db.getBrightness(p[8],p[9],p[10])^2 + db.getBrightness(p[11],p[12],p[13])^2) / 2) |
diffB = math.abs(obri - pbri) |
-- we need to normalize the distance by the weights |
diffC = db.getColorDistance_weight(r,g,b,p[5],p[6],p[7],0.26,0.55,0.19) * 1.569 + p[4]*distmult |
diff = briweight * (diffB - diffC) + diffC |
if diff <= best then bestcol = n; best = diff; end |
end |
return {mixpal[bestcol][2], mixpal[bestcol][3]} |
--return {mixpal[bestcol][2], 0} |
end |
-- |
-- |
function db.matchcolorHSB(h,s,b,pallist,index_flag) |
-- |
-- why don't we just convert HSB-diagram to RGB and do normal colormatching? |
-- Not the same... |
-- |
local n,c,best,bestcol,pb,ph,ps,diff,huediff,huecorr,hue_adj,sat_adj,bri_adj |
bestcol = -1 |
best = 9e99 |
-- higher adjust means more impact (higher hue gives more interpolation ) |
hue_adj = 4 |
sat_adj = 0.075 |
bri_adj = 2 |
huecorr = 255 / 6 -- Our Hue goes from 0.0 - 5.999 |
for n=1, #pallist, 1 do |
c = pallist[n] |
ph = c[5] |
ps = c[6] |
pb = c[7] |
huediff = math.abs(h-ph*huecorr) |
if huediff > 127 then huediff = huediff - (huediff % 127) * 2; end |
--if ph == 6.5 then huediff = 0; end |
-- With less saturation, exact hue becomes less important and brightness more usefull |
-- This allows for greyscales and low saturation colors to work smoothly. |
huediff = huediff * (ps /255) |
diff = hue_adj*huediff^2 + (s-ps)^2 * sat_adj + (b-pb)^2 * bri_adj |
if diff <= best then bestcol = n; best = diff; end |
end |
if index_flag == true then |
bestcol = pallist[bestcol][4] + 1 -- Since we detract 1 on return, God Lua is stupid |
end |
return bestcol-1 |
end |
-- |
-- |
-- Used by PaletteAnalysis.lua, FindRamps(), MixColors() etc. |
-- Assigns is used by ApplySpare script |
-- |
function db.fixPalette(pal,sortflag) -- Arrange palette & only keep unique colors |
local n,l,rgb,i,unique,bri,hue,sat,ulist,indexpal,newpal,dtot |
ulist = {} |
indexpal = {} |
newpal = {} |
local doubles,assign |
doubles = {}; assign = {} |
l = #pal |
unique = 1 -- ok, see how stupid lua is |
dtot = 0 |
for n=1, l, 1 do |
rgb = pal[n]; -- actually rgbn |
i = 1 + rgb[1] * 65536 + rgb[2] * 256 + rgb[3]; |
bri = db.getBrightness(rgb[1],rgb[2],rgb[3]) |
if indexpal[i] == nil then |
indexpal[i] = rgb; ulist[unique] = {i,bri}; unique = unique+1; |
assign[rgb[4]+1] = rgb[4] -- really n, but can we be sure? |
else |
doubles[rgb[4]] = true; -- Mark as double (This is wrong; starts at 0...but col 0 cannot be a double so...) |
dtot = dtot + 1 |
assign[rgb[4]+1] = indexpal[i][4] -- Reassign removed color |
end |
end |
-- sort ulist |
if sortflag == 1 then db.sorti(ulist,2); end -- sort by brightness |
l = #ulist |
for n=1, l, 1 do |
newpal[n] = indexpal[ulist[n][1]] |
end |
newpal["assigns"] = assign -- Complete list of image color assigns (removed cols will point to 1st occurence) |
newpal["doubles"] = doubles |
newpal.double_total = dtot |
--messagebox("unique colors", unique-1) |
return newpal |
end |
-- |
-- |
function db.drawColorspace12bit(x,y,cols,size) |
local r,g,b,c,rows,row,col,s16,rx,ry,xx,yy |
s16 = size*16 |
rows = math.floor(16/cols) |
for g = 0, 15, 1 do |
col = g % cols |
row = math.floor(g / cols) |
for r = 0, 15, 1 do |
for b = 0, 15, 1 do |
c = matchcolor(r*17,g*17,b*17) |
xx = x+col*s16+r*size |
yy = y+row*s16+b*size |
for ry = 0, size-1, 1 do |
for rx = 0, size-1, 1 do |
putpicturepixel(xx+rx,yy+ry,c) |
end;end |
end |
end |
end |
end |
-- |
-- |
function db.drawHSBdiagram(pallist,posx,posy,width,height,size,sat) |
--db.addHSBtoPalette(palList) |
local x,y,c |
for y = 0, height-1, 1 do |
for x = 0, width-1, 1 do |
hue = 255/width * x |
bri = 255/height * y |
c = db.matchcolorHSB(hue,sat,bri,pallist,true) |
db.drawRectangle(posx + x*size, posy + y*size,size,size, c) |
end |
end |
end |
-- |
-- |
function db.polarHSBdiagram(ox,oy,radius,pol,brilev,huelev,saturation,dark2bright_flag) |
local pal,bstep,bstep2,hstep,hstep2,bri,hue,sx,sy,cx,cy,x,y,p1,p2,c |
pal = db.addHSBtoPalette(db.fixPalette(db.makePalList(256))) |
bstep = radius / (brilev + pol) |
bstep2 = bstep / 2 |
hstep = -360 / huelev |
hstep2 = hstep / 2 |
c = 255; if dark2bright_flag then c = 0; end |
drawdisk(ox,oy,math.ceil(pol*bstep),matchcolor(c,c,c)) |
for y=pol, brilev+pol-1,1 do |
bri = (brilev - y + pol) * (256 / brilev) |
if dark2bright_flag then |
bri = (brilev - (brilev - y + pol)) * (256 / brilev) |
end |
for x=0, huelev-1,1 do |
hue = x * (360 / huelev) * 255/360 |
c = db.matchcolorHSB(hue,saturation,bri,pal,true) |
sx = ox |
sy = oy - y*bstep |
cx,cy = db.rotationFrac(x*hstep,ox,oy,sx,sy) |
x1,y1 = db.rotation(x*hstep-hstep2,ox,oy,ox, sy-bstep2) |
x2,y2 = db.rotation(x*hstep+hstep2,ox,oy,ox, sy-bstep2) |
x3,y3 = db.rotation(x*hstep-hstep2,ox,oy,ox, sy+bstep2) |
x4,y4 = db.rotation(x*hstep+hstep2,ox,oy,ox, sy+bstep2) |
p1 = {{x1,y1},{x2,y2},{x3,y3}} |
p2 = {{x3,y3},{x4,y4},{x2,y2}} |
db.fillTriangle(p1,c,0,true,false) -- triangle, fillcol, linecol, fill, wire |
db.fillTriangle(p2,c,0,true,false) |
end |
updatescreen(); if (waitbreak(0)==1) then return; end |
end |
end -- polarHSB |
-- |
-- |
-- Histograms, remapping etc. |
-- |
-- |
function db.makeHistogram() |
local n,y,x,c,w,h,list; list = {} |
w, h = getpicturesize() |
for n = 1, 256, 1 do list[n] = 0; end |
for y = 0, h - 1, 1 do |
for x = 0, w - 1, 1 do |
c = getpicturepixel(x,y) |
list[c+1] = list[c+1] + 1 |
end |
end |
return list |
end |
-- |
-- |
function db.makeHistogramIndexed() -- With color index so it can be sorted etc. |
local n,y,x,c,w,h,r,g,b,list; list = {} |
w, h = getpicturesize() |
for n = 1, 256, 1 do |
r,g,b = getcolor(n-1) |
list[n] = {0,n-1,r,g,b}; |
end |
for y = 0, h - 1, 1 do |
for x = 0, w - 1, 1 do |
c = getpicturepixel(x,y) |
list[c+1][1] = list[c+1][1] + 1 |
end |
end |
return list |
end |
-- |
-- |
function db.makeSpareHistogram() |
local n,y,x,c,w,h,list; list = {} |
w, h = getsparepicturesize() |
--w,h = 512,360 |
for n = 1, 256, 1 do list[n] = 0; end |
for y = 0, h - 1, 1 do |
for x = 0, w - 1, 1 do |
c = getsparepicturepixel(x,y) |
list[c+1] = list[c+1] + 1 |
end |
end |
return list |
end |
-- |
-- |
-- Makes a palette-list from only the colors (histogram) that occurs in the image |
-- Assumes image/palette has not changed since histogram was created |
function db.makePalListFromHistogram(hist) |
local n,r,g,b,list,count |
list = {} |
count = 1 |
for n = 1, #hist, 1 do |
if hist[n] > 0 then |
r,g,b = getcolor(n-1) |
list[count] = {r,g,b,n-1} |
count = count + 1 |
end |
end |
return list |
end |
-- |
function db.makePalListFromSpareHistogram(hist) |
local n,r,g,b,list,count |
list = {} |
count = 1 |
for n = 1, #hist, 1 do |
if hist[n] > 0 then |
r,g,b = getsparecolor(n-1) |
list[count] = {r,g,b,n-1} |
count = count + 1 |
end |
end |
return list |
end |
-- |
-- |
function db.remap(org) -- Working with a remap-list there's no need of reading backuppixel |
--messagebox("Remapping") |
local x,y,c,i,w,h,s,f,col |
f = getpicturepixel |
s = false |
w, h = getpicturesize() |
for y = 0, h - 1, 1 do |
for x = 0, w - 1, 1 do |
c = f(x,y) |
i = org[c+1] |
if i == null then i = matchcolor(getbackupcolor(getbackuppixel(x,y))); s = true; col = c; end -- Find color for a removed double |
putpicturepixel(x,y,i) |
end |
end |
if s then messagebox("Remapping: Not all image colors were found in remap-list (re-assign), probably due to duplicate removal. Matchcolor was used, ex: col# "..col); |
end |
end |
-- |
-- |
-- Same as db.remap but no comments |
-- |
function db.remapImage(colassignlist) -- assignment list is optional |
local x,y,c,w,i,h,assign |
assign = false |
if colassignlist ~= null then assign = true; end |
w,h = getpicturesize() |
for y = 0, h-1, 1 do |
for x = 0, w-1, 1 do |
c = getbackuppixel(x,y) |
i = null; if assign then i = colassignlist[c+1]; end |
if not assign or i == null then |
i = matchcolor(getbackupcolor(c)) |
end |
putpicturepixel(x,y,i) |
end |
end |
end |
-- |
-- |
-- Palette DeCluster: Color-reduction by fusing similar colors into new ones, using a desired tolerance. |
-- This is a method similar to Median-Cut, but more surgical. |
-- |
-- pallist: Palette list {r,g,b,palette_index} |
-- hist: Histogram {color 0 pixels, color 1 pixels...etc} always a full 256 color list |
-- crad: Cluster radius treshold in % of distance between black & white |
-- A value of 0 will only remove identical colors |
-- A value of 3-4 will usally fuse redundant colors without causing notice |
-- prot_pow: (0..10) Protect common colors in histogram. Distances are increased by ocurrence. |
-- Also gives protection to fused colors even if not using histogram (combined nominal weights) |
-- pixels: Pixels in image (so protection can be calculated) |
-- rw,gw,bw: Color weights (rw+gw+bw = 1, 0.33,0.33,0.33 is nominal) |
-- |
-- Returns: |
-- a new (c)palette list {r,g,b,{original palette_indices},fused flag, histogram_weight} |
-- a remap list (org) [image color + 1] = remap color (in the new palette) |
function db.deCluster(pallist, hist, crad, prot_pow, pixels, rw,gw,bw) |
--messagebox(pixels) |
local u,c,a,i,o,j,n,c1,c2,r,g,b,r1,g1,b1,r2,g2,b2,wt,rt,gt,bt,tot,pd |
local worst,wtot,maxdist,maxDist,distfrac,clusterExists,clustVal,count,crad1 |
local cList,cPalList,clusterList,fuseCol,orgcols,newPalList,org |
maxdist = math.sqrt(rw*rw*65025 + gw*gw*65025 + bw*bw*65025) |
distfrac = 100 / maxdist |
-- Let's just make a slightly more suitable format of the pallist (List for original color(s)) |
cPalList = {} |
for u = 1, #pallist, 1 do |
c = pallist[u] |
cPalList[u] = {c[1],c[2],c[3],{c[4]},false,hist[c[4]+1]} -- r,g,b,{original colors},fuse_marker,histogram_weight |
end |
--table.insert(cPalList,{255,255,0,{257},false,1}) |
clusterExists = true |
while clusterExists do |
clusterExists = false |
clusterList = {} |
crad1 = crad + 1 -- avoid divison by zero |
worst = 9999 |
for a = 1, #cPalList, 1 do |
c1 = cPalList[a] |
r1,g1,b1 = c1[1],c1[2],c1[3] |
wtot = c1[6] |
cList = {a} |
maxDist = 0 |
for b = 1, #cPalList, 1 do |
if (b ~= a) then |
c2 = cPalList[b] |
r2,g2,b2 = c2[1],c2[2],c2[3] |
wt = c2[6] |
pd = math.pow((1 + wt / pixels), prot_pow) -- Protection, increase distance |
dist = db.getColorDistance_weight(r1,g1,b1,r2,g2,b2,rw,gw,bw) * distfrac * pd |
if dist <= crad then |
wtot = wtot + wt |
table.insert(cList,b) |
maxDist = math.max(dist,maxDist) |
end |
end |
end -- b |
if #cList > 1 then |
clustVal = maxDist / (crad1 * #cList) * (wtot / #cList) |
if clustVal < worst then |
worst = clustVal |
clusterList = cList |
end |
end |
end -- a |
--t = db.ary2txt(clusterList) |
--messagebox("Worst cluster is "..t) |
-- Fuse |
if #clusterList > 1 then |
clusterExists = true -- Run another iteration and look for more clusters |
fuseCol = {0,0,0,{}} |
rt,gt,bt,tot = 0,0,0,0 |
for n = 1, #clusterList, 1 do |
i = clusterList[n] |
c = cPalList[i] |
--o = c[4][1] -- Original color (always #1 in list since fused colors can't re-fuse) |
o = c[4] -- Original color list |
--if c[5] == true then messagebox("Re-Fusing..."); end |
r,g,b = c[1],c[2],c[3] |
--wt = hist[o+1] -- Org. colors are 0-255 |
wt = c[6] |
rt = rt + r * wt |
gt = gt + g * wt |
bt = bt + b * wt |
tot = tot + wt |
cPalList[i] = -1 -- Erase color |
--table.insert(fuseCol[4],o) |
orgcols = fuseCol[4] |
for j = 1, #o, 1 do |
table.insert(orgcols,o[j]) |
end |
fuseCol[4] = orgcols |
end |
rt = rt / tot |
gt = gt / tot |
bt = bt / tot |
fuseCol[1] = rt |
fuseCol[2] = gt |
fuseCol[3] = bt |
fuseCol[5] = true -- fusecol marker |
fuseCol[6] = tot |
table.insert(cPalList,fuseCol) |
--messagebox(#clusterList.." Colors was fused, resulting in "..rt..", "..gt..", "..bt) |
newPalList = {} |
for n = 1, #cPalList, 1 do |
if cPalList[n] ~= -1 then |
table.insert(newPalList,cPalList[n]) |
--newPalList = db.newArrayInsertLast(newPalList,cPalList[n]) |
end |
end |
cPalList = newPalList |
--messagebox("Pal length: "..#cPalList) |
statusmessage("DC - Image colors: "..#cPalList.." "); waitbreak(0) |
end -- fuse |
end -- while |
-- Create remap-list |
org = {} |
count = 0 |
for u = 1, #cPalList, 1 do |
c = cPalList[u] |
for n = 1, #c[4], 1 do |
i = c[4][n] |
org[i+1] = count -- quick way to remap without matchcolor |
end |
count = count + 1 |
end |
return org,cPalList |
end; -- decluster |
-- ------------- MEDIAN CUT V1.0 ------------ |
-- |
-- 256 color Palette Lua-version (converted from Evalion JS-script) |
-- |
-- by Richard 'DawnBringer' Fhager |
-- |
-- |
-- pal: [[r,g,b,i]] Pallist |
-- cnum: Target number of colors in reduced palette |
-- (step:) 1.. Pixel picks for processing, 1 = all pixels in image, best and slowest. 2 = 25% of pixels |
-- qual: Flag Qualitative color selection (Normal mode) |
-- quant: Flag Quantative color/pixel selection (Histogram) 100% mean that it count as much as quality |
-- (One of or both qual/quant must be selected) |
-- rgbw: [3] RGB-weights []. Weigh the color channels. ex: [1,1.333,0.75] |
-- bits: 1-8 Bits used for each color channel in palette |
-- quantpow: 0..1 |
-- |
-- return: A palette! A list of [r,g,b] values |
-- |
-- NOTE: Quantity will act as a counterforce to altered colorspace (weights)... |
-- Ex: if Green is considered bigger, it will be split into more blocks |
-- but each blocks will have less colors and thus less quantity. |
-- |
-- Perceptual colorspace (rgb-weights) will generally produce the best quality of palettes, but if |
-- It's desirable to preserve stronger colors, esp. in small palettes, |
-- it can be good to just use nominal space: 1,1,1 |
-- |
-- Histogram may be useful to assign more colors to an object that already covers most of the image, |
-- however; if the object of interest is small in relation to a large (unimportant) background, it's |
-- usually best not to have any histogram at all. Histogram will dampen strong infrequent colors. |
function db.medianCut(pal,cnum,qual,quant,rgbw,bits,quantpow) |
local n,x,y,xs,ys,rgb,blocklist,blocks |
local len,res,chan,diff,maxdiff,maxblock,split |
local qualnorm, quantnorm |
-- Normalize 256 for quality/quantity relationship |
qualnorm = 1 / math.sqrt(rgbw[1]^2 + rgbw[2]^2 + rgbw[3]^2) |
quantnorm = 256 / #pal |
blocklist = {} |
blocklist[1] = {}; blocks = 1 |
for n=1, #pal, 1 do |
blocklist[1][n] = pal[n]; |
end |
analyzeBlock(blocklist[1],qual,quant,rgbw,qualnorm,quantnorm,quantpow) |
failsafe = 0 |
while (blocks < cnum and failsafe < 256) do |
failsafe = failsafe + 1 |
maxdiff = -1 |
maxblock = -1 |
for n=1, blocks, 1 do |
diff = blocklist[n].diff |
if (diff > maxdiff) then maxdiff = diff; maxblock = n; end -- maxchan is stored as .chan in block |
end |
split = splitBlock(blocklist,maxblock,qual,quant,rgbw,qualnorm,quantnorm,quantpow) |
--if (split == false){ alert("Only found " + blocks + " (24-bit) colors!"); break; } |
blocks = #blocklist |
--status.value = "MC: " +blocks |
end -- while |
return blocks2Palette(blocklist,bits) |
end |
-- |
-- |
function blocks2Palette(blocklist,bits) |
local n,r,g,b,c,pal,block,rgb,blen,M,dB,cB,rf,gf,bf |
M = math |
pal = {} |
--bits = 1 |
dB = M.pow(2,8-bits) |
cB = M.ceil(255 / (M.pow(2,bits) - 1)) |
for n=1, #blocklist, 1 do |
block = blocklist[n] |
r,g,b = 0,0,0 |
blen = #block |
for c=1, blen, 1 do |
rgb = block[c] |
r = r + rgb[1] |
g = g + rgb[2] |
b = b + rgb[3] |
end |
rf = M.floor(M.min(255,M.max(0,M.floor(r/blen))) / dB) * cB |
gf = M.floor(M.min(255,M.max(0,M.floor(g/blen))) / dB) * cB |
bf = M.floor(M.min(255,M.max(0,M.floor(b/blen))) / dB) * cB |
pal[n] = {rf, gf, bf, 0} -- col is avg. of all colors in block (index is set (to 0) for compatibility) |
end -- blocklist |
return pal |
end |
-- |
-- |
function analyzeBlock(block,qual,quant,rgbw,qualnorm,quantnorm,quantpow) |
local r,g,b,n,rmin,gmin,bmin,rmax,gmax,bmax,rdif,gdif,bdif,chan,d,median,diff |
local len,Mm,Mx,rgb,kv,qu |
Mx,Mm = math.max, math.min |
len = #block |
rmin,gmin,bmin = 255,255,255 |
rmax,gmax,bmax = 0,0,0 |
for n=1, len, 1 do |
rgb = block[n] |
r = rgb[1] * rgbw[1] |
g = rgb[2] * rgbw[2] |
b = rgb[3] * rgbw[3] |
--if (!isNaN(r) and !isNaN(g) and !isNaN(b)) then -- Ignore any erroneous data |
rmin = Mm(rmin,r) |
gmin = Mm(gmin,g) |
bmin = Mm(bmin,b) |
rmax = Mx(rmax,r) |
gmax = Mx(gmax,g) |
bmax = Mx(bmax,b) |
--end |
end |
rdif = (rmax - rmin) -- * rgbw[1] |
gdif = (gmax - gmin) -- * rgbw[2] |
bdif = (bmax - bmin) -- * rgbw[3] |
d = {{rmin,rdif,rmax},{gmin,gdif,gmax},{bmin,bdif,bmax}} |
chan = 1 -- Widest channel |
if (gdif > rdif) then chan = 2; end |
if (bdif > rdif and bdif > gdif) then chan = 3; end |
-- Ok, this is the average of the max/min value rather than an actual median |
-- I guess this will fill the colorspace more uniformly and perhaps select extremes to a greater extent? |
-- Which is better? |
--median = d[chan][1] + d[chan][2] / 2 -- OLD same as median with nominal weights |
median = (d[chan][1] + d[chan][3]) / 2 |
-- quantity and quality are normalized to 256 (256 is the total of colors in the set for quantity) |
-- Note that, regardless of forumla, quality (distance) must always be greater in any block than quantity (colors/pixels) |
-- Coz a block may contain many of only 1 unique color, thus rendering it impossible to split if selected. |
kv = 1 |
qu = 1 |
if (quant) then kv = 1 + len*quantnorm*quantpow; end |
if (qual) then qu = d[chan][2] * qualnorm; end |
diff = qu + qu*kv^2.5 |
block.chan = chan |
block.diff = diff |
block.median = median |
return {chan,diff,median,len} |
end |
-- |
function splitBlock(blocklist,maxblock,qual,quant,rgbw,qualnorm,quantnorm,quantpow) |
local n,cmax,median,blockA,blockB,len,cB,block,rgb,res |
blockA,blockB = {},{} |
block = blocklist[maxblock] |
res = true |
chan = block.chan |
median = block.median |
cB = blocklist[maxblock] -- maxblock starts at 1 when called so it should not hava a +1 |
len = #cB |
for n=1, len, 1 do |
rgb = cB[n] |
--if (rgb[chan] >= median) then blockA.push(rgb); end |
--if (rgb[chan] < median) then blockB.push(rgb); end |
if (rgb[chan]*rgbw[chan] >= median) then table.insert(blockA,rgb); end |
if (rgb[chan]*rgbw[chan] < median) then table.insert(blockB,rgb); end |
end |
blocklist[maxblock] = blockA -- Can't be empty right? |
analyzeBlock(blocklist[maxblock],qual,quant,rgbw,qualnorm,quantnorm,quantpow) |
if (#blockB > 0) then |
table.insert(blocklist,blockB) |
analyzeBlock(blocklist[#blocklist],qual,quant,rgbw,qualnorm,quantnorm,quantpow) -- no -1 on blocklist |
else |
res = false |
end |
return res -- false = no split |
end |
------------ eof MEDIAN CUT -------------------------- |
-- ------------- MEDIAN REDUX V1.0 ------------ |
-- |
-- Divide space by greatest distance of any two colors (rather than MC-method of any given channel) |
-- Basically it allows colorspace to be sliced at any angles rather than the "boxing" of MC. |
-- |
-- |
-- by Richard 'DawnBringer' Fhager |
-- |
-- |
-- pal: [[r,g,b,i,h]] Pallist (h = histogram/pixelcount) |
-- cnum: Target number of colors in reduced palette |
-- (step:) 1.. Pixel picks for processing, 1 = all pixels in image, best and slowest. 2 = 25% of pixels |
-- qual: Flag Qualitative color selection (Normal mode) |
-- quant: Flag Quantative color/pixel selection (Histogram) 100% mean that it count as much as quality |
-- (One of or both qual/quant must be selected) |
-- rgbw: [3] RGB-weights []. Weigh the color channels. ex: [0.26, 0.55, 0.19] |
-- bits: 1-8 Bits used for each color channel in palette |
-- quantpow: 0..1 Quantity vs Quality (put weight into histogram/pixelcount) |
-- briweight: 0..1 Brightness distance weight in colordistance |
-- proxweight: 0..1 Primary Proximity distance weight in colordistance (ColorTheory-WIP: compensate for brightness of individual channels, the "extra power" of primary colors) |
-- |
-- return: A palette! A list of [r,g,b] values |
-- |
-- NOTE: Quantity will act as a counterforce to altered colorspace (weights)... |
-- Ex: if Green is considered bigger, it will be split into more blocks |
-- but each blocks will have less colors and thus less quantity. |
-- |
-- Perceptual colorspace (rgb-weights) will generally produce the best quality of palettes, but if |
-- It's desirable to preserve stronger colors, esp. in small palettes, |
-- it can be good to just use nominal space: 0.33, 0.33, 0.33 |
-- |
-- Histogram may be useful to assign more colors to an object that already covers most of the image, |
-- however; if the object of interest is small in relation to a large (unimportant) background, it's |
-- usually best not to have any histogram at all. Histogram will dampen strong infrequent colors. |
function db.medianRedux(pal,cnum,qual,quant,rgbw,bits,quantpow, briweight, proxweight) -- pal[r,g,b,i,pixelcount] |
local n,x,y,xs,ys,rgb,blocklist,blocks |
local len,res,chan,diff,maxdiff,maxblock,split |
local qualnorm, quantnorm,count |
blocklist = {} |
blocklist[1] = {}; blocks = 1 |
count = 0 |
for n=1, #pal, 1 do |
blocklist[1][n] = pal[n]; |
count = count + pal[n][5] |
end |
-- Normalize 256 for quality/quantity relationship |
qualnorm = 1 / math.sqrt(rgbw[1]^2 + rgbw[2]^2 + rgbw[3]^2) |
quantnorm = 256 / count |
-- Dist table |
statusmessage("MR: Making Distance Table..."); updatescreen(); if (waitbreak(0)==1) then return; end |
local dy,c,r1,g1,b1,i1,i2 |
dt = {} |
for n=1, #pal, 1 do |
c = pal[n] |
r1,g1,b1,i1 = c[1],c[2],c[3],c[4] |
dt[i1+1] = {} |
for m=1, #pal, 1 do |
dt[i1+1][pal[m][4]+1] = db.getColorDistanceProx(r1,g1,b1,pal[m][1],pal[m][2],pal[m][3],rgbw[1],rgbw[2],rgbw[3],qualnorm, proxweight, briweight) -- pri/bri |
end |
end |
-- |
statusmessage("MR: Analyzing Block 1..."); updatescreen(); if (waitbreak(0)==1) then return; end |
r_analyzeBlock(dt,blocklist[1],qual,quant,rgbw,qualnorm,quantnorm,quantpow) |
statusmessage("MR: Analyzing Blocks..."); updatescreen(); if (waitbreak(0)==1) then return; end |
failsafe = 0 |
while (blocks < cnum and failsafe < 256) do |
failsafe = failsafe + 1 |
maxdiff = -1 |
maxblock = -1 |
for n=1, blocks, 1 do |
diff = blocklist[n].diff |
if (diff > maxdiff) then maxdiff = diff; maxblock = n; end -- maxchan is stored as .chan in block |
end |
split = r_splitBlock(dt,blocklist,maxblock,qual,quant,rgbw,qualnorm,quantnorm,quantpow) |
if (split == false) then messagebox("Only found "..blocks.." (24-bit) colors!"); break; end |
blocks = #blocklist |
statusmessage("MR: "..blocks); updatescreen(); if (waitbreak(0)==1) then return; end |
end -- while |
return r_blocks2Palette(blocklist,bits) |
end |
-- |
-- |
function r_blocks2Palette(blocklist,bits) |
local n,r,g,b,c,pal,block,rgb,blen,M,dB,cB,rf,gf,bf |
M = math |
pal = {} |
--bits = 1 |
dB = M.pow(2,8-bits) |
cB = M.ceil(255 / (M.pow(2,bits) - 1)) |
for n=1, #blocklist, 1 do |
block = blocklist[n] |
r,g,b = 0,0,0 |
blen = #block |
for c=1, blen, 1 do |
rgb = block[c] |
r = r + rgb[1] |
g = g + rgb[2] |
b = b + rgb[3] |
end |
rf = M.floor(M.min(255,M.max(0,M.floor(r/blen))) / dB) * cB |
gf = M.floor(M.min(255,M.max(0,M.floor(g/blen))) / dB) * cB |
bf = M.floor(M.min(255,M.max(0,M.floor(b/blen))) / dB) * cB |
pal[n] = {rf, gf, bf} -- col is avg. of all colors in block |
end -- blocklist |
return pal |
end |
-- |
-- |
function r_analyzeBlock(dt,block,qual,quant,rgbw,qualnorm,quantnorm,quantpow) |
local r,g,b,n,m,rmin,gmin,bmin,rmax,gmax,bmax,rdif,gdif,bdif,chan,d,median,diff |
local len,Mm,Mx,rgb,kv,qu |
local maxdist,dist,r1,g1,b1,r2,g2,b2,c1,c2,count |
Mx,Mm = math.max, math.min |
len = #block |
rmin,gmin,bmin = 255,255,255 |
rmax,gmax,bmax = 0,0,0 |
maxdist,c1,c2,count = 0,-1,-1,0 |
for n=1, len, 1 do |
rgb1 = block[n] |
count = count + rgb1[5] -- pixelcount for color |
for m=n+1, len, 1 do |
rgb2 = block[m] |
--dist = db.getColorDistanceProx(r1,g1,b1,r2,g2,b2,0.26,0.55,0.19,1.569, 0.1, 0.25) -- pri/bri |
dist = dt[rgb1[4]+1][rgb2[4]+1] |
if dist > maxdist then |
maxdist = dist |
c1 = rgb1[4]+1 |
c2 = rgb2[4]+1 |
end |
end |
end |
-- quantity and quality are normalized to 256 (256 is the total of colors in the set for quantity) |
-- Note that, regardless of forumla, quality (distance) must always be greater in any block than quantity (colors/pixels) |
-- Coz a block may contain many of only 1 unique color, thus rendering it impossible to split if selected. |
kv = 1 |
qu = 1 |
if (quant) then kv = math.pow(1 + count*quantnorm*quantpow, 0.5); end |
if (qual) then qu = maxdist * qualnorm; end |
diff = qu*(1-quantpow) + qu*kv |
block.chan = -1 |
block.diff = diff |
block.median = -1 |
block.c1 = c1 |
block.c2 = c2 |
return {diff,len} |
end |
-- |
function r_splitBlock(dt,blocklist,maxblock,qual,quant,rgbw,qualnorm,quantnorm,quantpow) |
local n,cmax,median,blockA,blockB,len,cB,block,rgb,res |
local c1,c2,dist1,dist2,medr,medg,medb,r1,g1,b1,r2,g2,b2,rgb1,rgb2 |
blockA,blockB = {},{} |
block = blocklist[maxblock] |
res = true |
--chan = block.chan |
--median = block.median |
c1 = block.c1 |
c2 = block.c2 |
--rgb1 = block[c1] |
--r1,g1,b1 = rgb1[1],rgb1[2],rgb1[3] |
--rgb2 = block[c2] |
--r2,g2,b2 = rgb2[1],rgb2[2],rgb2[3] |
--medr = (r1+r2)/2 |
--medg = (g1+g2)/2 |
--medb = (b1+b2)/2 |
cB = blocklist[maxblock] -- maxblock starts at 1 when called so it should not hava a +1 |
len = #cB |
if len < 2 then return false; end |
for n=1, len, 1 do |
rgb = cB[n] |
dist1 = dt[rgb[4]+1][c1] |
dist2 = dt[rgb[4]+1][c2] |
if (dist1 <= dist2) |
then table.insert(blockA,rgb); |
end |
if (dist1 > dist2) then |
table.insert(blockB,rgb); |
end |
end |
blocklist[maxblock] = blockA -- Can't be empty right? |
r_analyzeBlock(dt,blocklist[maxblock],qual,quant,rgbw,qualnorm,quantnorm,quantpow) |
if (#blockB > 0) then |
table.insert(blocklist,blockB) |
r_analyzeBlock(dt,blocklist[#blocklist],qual,quant,rgbw,qualnorm,quantnorm,quantpow) -- no -1 on blocklist |
else |
res = false |
end |
return res -- false = no split |
end |
------------ eof MEDIAN REDUX -------------------------- |
-- |
-- ... eof Custom Color / Palette functions ... |
-- |
-- ***************************** |
-- *** Custom Draw functions *** |
-- ***************************** |
-- |
function db.line(x1,y1,x2,y2,c) -- Coords should be integers or broken lines are possible |
local n,st,m,xd,yd; m = math |
st = m.max(1,m.abs(x2-x1),m.abs(y2-y1)); |
xd = (x2-x1) / st |
yd = (y2-y1) / st |
for n = 0, st, 1 do |
putpicturepixel(m.floor(x1 + n*xd), m.floor(y1 + n*yd), c ); |
end |
end |
-- |
-- |
function db.lineTransp(x1,y1,x2,y2,c,amt) -- amt: 0-1, 1 = Full color |
local n,st,m,x,y,r,g,b,r1,g1,b1,c2,org; m = math |
org = 1 - amt |
st = m.max(1,m.abs(x2-x1),m.abs(y2-y1)); |
for n = 0, st, 1 do |
x = m.floor(x1+n*(x2-x1)/st) |
y = m.floor(y1+n*(y2-y1)/st) |
r,g,b = getcolor(getpicturepixel(x,y)) |
r1,g1,b1 = getcolor(c) |
c2 = matchcolor(r1*amt+r*org, g1*amt+g*org, b1*amt+b*org) |
putpicturepixel(x, y, c2 ); |
end |
end |
-- |
-- |
function db.drawBrushRectangle(x1,y1,w,h,c) |
local x,y |
for y = y1, y1+h-1, 1 do |
for x = x1, x1+w-1, 1 do |
putbrushpixel(x,y,c); |
end |
end |
end |
-- |
-- |
function db.drawRectangle(x1,y1,w,h,c) |
local x,y |
for y = y1, y1+h-1, 1 do |
for x = x1, x1+w-1, 1 do |
putpicturepixel(x,y,c); |
end |
end |
end |
-- |
-- |
function db.drawRectangleNeg(x1,y1,w,h,c) |
local x,y,xs,ys |
xs = db.sign(w) |
ys = db.sign(h) |
if xs == 0 then xs = 1; end |
if ys == 0 then ys = 1; end |
for y = y1, y1+h-1, ys do |
for x = x1, x1+w-1, xs do |
putpicturepixel(x,y,c); |
end |
end |
end |
-- |
-- |
function db.drawRectangleLine(x,y,w,h,c) |
w = w-1 |
h = h-1 |
db.line(x,y,x+w,y,c) |
db.line(x,y,x,y+h,c) |
db.line(x,y+h,x+w,y+h,c) |
db.line(x+w,y,x+w,y+h,c) |
end |
-- |
-- |
function db.drawRectangleMix(x1,y1,w,h,c1,c2) |
local x,y,c,n |
c = {c1,c2} |
n = 0 |
for y = y1, y1+h-1, 1 do |
n = n + 1 |
for x = x1, x1+w-1, 1 do |
n = n + 1 |
putpicturepixel(x,y,c[n%2+1]); |
end |
end |
end |
-- |
-- |
function db.drawCircle(x1,y1,r,c) -- ok, lottsa weird adjustments here, can probably be optimized... |
local x,y,d,r5,r25,r2,xr5,yr5 |
r5,r25,r2,xr5,yr5 = r+0.5,r-0.25,r*2, x1-r-0.5, y1-r-0.5 |
for y = 0, r2, 1 do |
for x = 0, r2, 1 do |
d = math.sqrt((x-r5)^2 + (y-r5)^2) |
if d < r25 then putpicturepixel(x + xr5, y + yr5,c); end |
end |
end |
end |
-- |
-- |
function db.drawBrushCircle(x1,y1,r,c) -- ok, lottsa weird adjustments here, can probably be optimized... |
local x,y,d |
for y = 0, r*2, 1 do |
for x = 0, r*2, 1 do |
d = math.sqrt((x-r-0.5)^2 + (y-r-0.5)^2) |
if d < r-0.25 then putbrushpixel(x1+x-r-0.5,y1+y-r-0.5,c); end |
end |
end |
end |
-- |
-- |
-- Rotation in degrees |
-- Step is # of line segments (more is "better") |
-- a & b are axis-radius |
function db.ellipse2(x,y,a,b,stp,rot,col) |
local n,m=math,rad,al,sa,ca,sb,cb,ox,oy,x1,y1,ast |
m = math; rad = m.pi/180; ast = rad * 360/stp; |
sb = m.sin(-rot * rad); cb = m.cos(-rot * rad) |
for n = 0, stp, 1 do |
ox = x1; oy = y1; |
sa = m.sin(ast*n) * b; ca = m.cos(ast*n) * a |
x1 = x + ca * cb - sa * sb |
y1 = y + ca * sb + sa * cb |
--if (n > 0) then db.line(ox,oy,x1,y1,col); end |
if (n > 0) then drawline(ox,oy,x1,y1,col); end |
end |
end |
-- |
--[[ |
var ER = 0.3 |
var DR = 0.15 |
ellipse(0.5*xx,0.5*yy,DR*xx,6,Math.PI*0) |
function ellipse(x,y,r,stp,rot){ |
var n,deg=360,m=Math,rad=Math.PI/180,rn |
var ox,oy,x1,y1,x2,y2,d1,r1 = ER * xx |
for (n=0; n<=deg; n+=stp){ |
ox = x2; oy = y2, rn = rad * n |
d1 = rn - rot |
x1 = x + m.sin(d1) * r |
y1 = y + m.cos(d1) * r |
x2 = x1 + m.sin(-rn) * r1 |
y2 = y1 + m.cos(-rn) * r1 |
if (n > 0){ line_rgb(MX,[0,0,0],0,ox,oy,x2,y2) } |
} |
} |
} |
ellipse2(0.5*xx,0.5*yy,15,8,200,22,[0,0,0],0.5) |
function ellipse2(x,y,a,b,stp,rot,rgb,transp){ |
var n,m=Math,rad=m.PI/180,al,sa,ca,sb,cb,ox,oy,x1,y1 |
sb = m.sin(-rot * rad); cb = m.cos(-rot * rad) |
for (n=0; n<=stp; n++){ |
ox = x1; oy = y1; al = rad * 360/stp * n |
sa = m.sin(al) * b; ca = m.cos(al) * a |
x1 = x + ca * cb - sa * sb |
y1 = y + ca * sb + sa * cb |
if (n > 0){ line_rgb(MX,rgb,transp,ox,oy,x1,y1) } |
} |
} |
]] |
function db.obliqueCube(side,x,y,r,g,b,bri,cols) |
local n,c,depth,x1,y1,x2,y2,f |
asscols = false |
if cols >= 0 and cols<250 then |
asscols = true |
c = cols; setcolor(cols,r,g,b); cols = cols + 1 |
cP50 = cols; q = bri*0.5; setcolor(cols,r+q,g+q,b+q); cols = cols + 1; |
cP75 = cols; q = bri*0.75; setcolor(cols,r+q,g+q,b+q); cols = cols + 1; |
cM50 = cols; q = -bri*0.5; setcolor(cols,r+q,g+q,b+q); cols = cols + 1; |
cM100= cols; q = -bri; setcolor(cols,r+q,g+q,b+q); cols = cols + 1; |
end |
f = matchcolor |
if asscols == false then |
c = f(r,g,b) |
cP50 = f(r+bri*0.5,g+bri*0.5,b+bri*0.5) |
cP75 = f(r+bri*0.75,g+bri*0.75,b+bri*0.75) |
cM50 = f(r-bri*0.5,g-bri*0.5,b-bri*0.5) |
cM100 = f(r-bri,g-bri,b-bri) |
end |
depth = math.floor(side / 2) |
for n = 0, depth-1, 1 do |
db.line(x+side+n,y-1-n,x+side+n,y+side-n-1,cM50) |
--drawline(x+side+n,y-1-n,x+side+n,y+side-n-1,cM50) |
end |
for n = 0, depth-1, 1 do |
db.line(x+n,y-1-n,x+side+n-1,y-1-n,cP50) |
--drawline(x+n,y-1-n,x+side+n-1,y-1-n,cP50) |
end |
-- / |
-- |
--db.line(x+side,y-1,x+side+depth-1,y-depth,c) |
-- Smoothing & Shade |
-- |
-- / |
--db.line(x+side,y+side-1,x+side+depth-1,y+side-depth,cM100) |
--db.line(x,y,x+side-2,y,cP75) |
--db.line(x,y,x,y+side-2,cP75) |
db.drawRectangle(x,y,side,side,c) |
return cols |
end |
function db.obliqueCubeBRI(side,x,y,r,g,b,bri,pallist,briweight,index_flag) |
local n,c,depth,x1,y1,x2,y2 |
--f = db.getBestPalMatchHYBRID |
c = db.getBestPalMatchHYBRID({r,g,b}, pallist, briweight, index_flag) |
cP50 = db.getBestPalMatchHYBRID({r+bri*0.5,g+bri*0.5,b+bri*0.5}, pallist, briweight, index_flag) |
cP75 = db.getBestPalMatchHYBRID({r+bri*0.75,g+bri*0.75,b+bri*0.75}, pallist, briweight, index_flag) |
cM50 = db.getBestPalMatchHYBRID({r-bri*0.5,g-bri*0.5,b-bri*0.5}, pallist, briweight, index_flag) |
cM100 = db.getBestPalMatchHYBRID({r-bri,g-bri,b-bri}, pallist, briweight, index_flag) |
depth = math.floor(side / 2) |
db.drawRectangle(x,y,side,side,c) |
for n = 0, depth-1, 1 do |
db.line(x+side+n,y-1-n,x+side+n,y+side-n-1,cM50) |
--drawline(x+side+n,y-1-n,x+side+n,y+side-n-1,cM50) |
end |
for n = 0, depth-1, 1 do |
db.line(x+n,y-1-n,x+side+n-1,y-1-n,cP50) |
--drawline(x+n,y-1-n,x+side+n-1,y-1-n,cP50) |
end |
-- / |
-- |
db.line(x+side,y-1,x+side+depth-1,y-depth,c) |
--drawline(x+side,y-1,x+side+depth-1,y-depth,c) |
-- Smoothing & Shade |
-- |
-- / |
--db.line(x+side,y+side-1,x+side+depth-1,y+side-depth,cM100) |
--db.line(x,y,x+side-2,y,cP75) |
--db.line(x,y,x,y+side-2,cP75) |
end |
-- |
function db.fillTriangle(p,fcol,lcol,fill,wire) -- p = list of 3 points |
local n,x,y,x1,x2,y1,y2,xf,yf,len,mr |
mr = math.floor |
-- Convert to screen/matrix-coordinates |
--if (mode == 'percent') then xf = xx / 100; yf = yy / 100; end |
--if (mode == 'fraction') then xf = xx; yf = yy; end |
--if (mode ~= 'absolute') then screenilizeTriangle(p,xf,yf); end |
if (fill) then |
local Ax,Ay,Bx,By,Cx,Cy,xd,a,b,yc,ABdy,BCdy,ABix,BCix,ACix |
xd = {} |
--sort(p,1) -- Find top and middle y-point |
db.sorti(p,2) |
Ay = p[1][2]; Ax = p[1][1] |
By = p[2][2]; Bx = p[2][1] |
Cy = p[3][2]; Cx = p[3][1] |
ABdy = By - Ay |
BCdy = Cy - By |
ABix = (Bx - Ax) / ABdy |
BCix = (Cx - Bx) / BCdy |
ACix = (Cx - Ax) / (Cy - Ay) |
a=1; b=2; |
if (ACix < ABix) then a=2; b=1; end |
for y = 0, ABdy-1, 1 do -- Upper -1 |
xd[a] = mr(Ax + ABix * y) |
xd[b] = mr(Ax + ACix * y) |
yc = y+Ay; |
for x=xd[1], xd[2], 1 do |
putpicturepixel(x,yc,fcol) |
end |
end |
a=1; b=2; |
if (BCix < ACix) then a=2; b=1; end |
for y = 0, BCdy, 1 do -- Lower |
xd[a] = mr(Cx - BCix * y); |
xd[b] = mr(Cx - ACix * y) |
yc = Cy-y; |
for x = xd[1], xd[2], 1 do |
putpicturepixel(x,yc,fcol) |
end |
end |
end -- eof fill |
if (wire) then |
for n = 0, 2, 1 do -- Outline |
x1 = p[n+1][1]; y1 = p[n+1][2] |
x2 = p[1 + (n+1) % 3][1]; y2 = p[1 + (n+1) % 3][2] |
--db.line(x1,y1,x2,y2,lcol) |
drawline(x1,y1,x2,y2,lcol) |
end |
end |
end -- eof fillTriangle |
-- |
-- |
-- ... eof Custom Draw functions ... |
-- |
-- ****************************** |
-- *** Filters & Convolutions *** |
-- ****************************** |
function db.applyConvolution2Pic(convmx,divisor,bias,neg,amt) |
local r,g,b,mx,my,cx,cy,mxh,myh,mp,rb,gb,bb,xx,yy,x,y,w,h,div,n1,n2,amtr,ro,go,bo |
n1 = 1 |
n2 = bias |
if neg == 1 then |
n1 = -1 |
n2 = 255 + bias |
end |
amtr = 1 - amt |
w, h = getpicturesize() |
cy = #convmx |
cx = #convmx[1] |
mxh = math.floor(cx / 2) + 1 |
myh = math.floor(cy / 2) + 1 |
for y = 0, h-1, 1 do |
for x = 0, w-1, 1 do |
r,g,b = 0,0,0 |
ro,go,bo = getcolor(getbackuppixel(x,y)) |
div = divisor |
for my = 1, cy, 1 do |
for mx = 1, cx, 1 do |
xp = mx-mxh |
yp = my-myh |
mp = convmx[my][mx] |
xx = x + xp |
yy = y + yp |
if yy>=0 and yy<h and xx>=0 and xx<w then |
rb,gb,bb = getcolor(getbackuppixel(xx,yy)) |
r = r + rb * mp |
g = g + gb * mp |
b = b + bb * mp |
else div = div - mp -- Assumes divisor is the sum of the convolution matrix |
end |
end |
end |
r = ro*amtr + (n2 + (n1 * r) / div)*amt -- +bias |
g = go*amtr + (n2 + (n1 * g) / div)*amt |
b = bo*amtr + (n2 + (n1 * b) / div)*amt |
putpicturepixel(x,y,matchcolor(r,g,b)) |
end; |
updatescreen(); if (waitbreak(0)==1) then return; end |
end; |
end |
-- |
-- ... eof Filters & Convolutions ... |
-- |
-- ***************************** |
-- *** Fractals etc. *** |
-- ***************************** |
-- Fractal Pattern V1.0 by Richard Fhager (mod allows for wrapping) |
-- |
-- Pattern matrix example: {{1,1,1},{1,0,1},{1,1,1}} |
-- |
function db.pattern(x,y,p,n,i) -- coord as fraction of 1, pattern, offset(0), iterations (1-15) |
local px,py |
py = #p |
px = #p[1] |
while ((p[1+math.abs(math.floor(y*py))%py][1+math.abs(math.floor(x*px))%px]) > 0 and n<i) do |
x=x*px-math.floor(x*px); |
y=y*py-math.floor(y*py); |
n = n+1 |
end |
return 1 - n/i; |
end |
-- |
-- |
function db.patternDec(x,y,p,n,i) -- coord as fraction of 1, pattern, offset(0), iterations (1-15) |
local px,py,spfrac,nfrac,fx,fy |
spfrac = 1 |
nfrac = 0 |
py = #p |
px = #p[1] |
while (spfrac > 0 and n<i) do |
fy = math.floor(math.abs(y*py))%py |
fx = math.floor(math.abs(x*px))%px |
spfrac = p[fy+1][fx+1] |
if (spfrac>0) then |
x = x*px - fx |
y = y*py - fy |
nfrac = nfrac + spfrac |
end |
n = n+1 |
end |
--return 1 - n/i; |
return 1 - nfrac/i |
end |
-- |
-- |
function db.mandel(x,y,l,r,o,i) -- pos. as fraction of 1, left coord, right coord, y coord, iterations |
local w,s,a,p,q,n,v,w |
s=math.abs(r-l); |
a = l + s*x; |
p = a; |
b = o - s*(y-0.5); |
q = b; |
n = 1; |
v = 0; |
w = 0; |
while (v+w<4 and n<i) do n=n+1; v=p*p; w=q*q; q=2*p*q+b; p=v-w+a; end; |
return n |
end |
-- |
-- |
-- ... eof Fractals etc. ... |
-- |
-- ******************************************** |
-- *** Color Cube / Space, Custom Functions *** |
-- ******************************************** |
-- |
-- SHADES (sha): 24bit colors is too complex so we operate with less shades/bits/colors. |
-- 16 shades = 12bit = 16*16*16 = 4096 colors (or cubic-elements) |
-- 32 shades = 15bit = 32*32*32 = 32768 colors |
-- |
-- data: {color available flag, 0 (gravity/distance, calculated, init as zero)} |
-- |
function db.initColorCube(sha,data) |
local ary,z,y,x,n |
ary = {} |
for z = 0, sha-1, 1 do |
ary[z+1] = {} |
for y = 0, sha-1, 1 do |
ary[z+1][y+1] = {} |
if data ~= nil then |
for x = 0, sha-1, 1 do |
-- This is silly stupid, if you know how to assign one array to another (no ref), plz help! |
-- i.e. how to: data = {false,0}; myArray[z][y][x] = data. |
ary[z+1][y+1][x+1] = {} |
for n = 1, #data, 1 do |
ary[z+1][y+1][x+1][n] = data[n] |
end |
end |
end |
end |
end |
return ary |
end |
-- |
-- |
function db.findVoid(cube,sha) -- void is point with longest distance to closest color |
local weakest,weak_i,x,y,z,c,w |
weakest = -1 |
weak_i = {-1,-1,-1} |
for z = 0, sha-1, 1 do |
for y = 0, sha-1, 1 do |
for x = 0, sha-1, 1 do |
c = cube[z+1][y+1][x+1] |
if c[1] == true then |
w = c[2] |
if w > weakest then weakest = w; weak_i = {z,y,x}; end |
end |
end;end;end |
return weak_i[1],weak_i[2],weak_i[3] |
end |
-- |
-- |
-- |
-- Nearest color version: void is selected by the point that has the greatest distance |
-- to the nearest color. Higher value means greater void. |
-- |
function db.addColor2Cube(cube,sha,r,g,b,rw,gw,bw) |
local star,x,y,z,d,rd,gd,bd,cu1,cu2 |
star = 0 |
cube[r+1][g+1][b+1] = {false, star} |
for z = 0, sha-1, 1 do |
rd = (rw*(z-r))^2 |
cu2 = cube[z+1] |
for y = 0, sha-1, 1 do |
gd = (gw*(y-g))^2 |
cu1 = cu2[y+1] |
for x = 0, sha-1, 1 do |
d = rd + gd + (bw*(x-b))^2 |
--cube[z+1][y+1][x+1][2] = math.min(d, cube[z+1][y+1][x+1][2]) -- Don't add, use nearest color |
cu1[x+1][2] = math.min(d, cu1[x+1][2]) |
end;end;end |
end |
-- |
-- Should be same as original, but not 100% verified. Using a rgb+1 trick to speed up handling |
-- |
function db.addColor2Cube_test(cube,sha,r,g,b,rw,gw,bw) |
local star,x,y,z,d,rd,gd,bd,cu1,cu2 |
star = 0 |
r = r+1; g = g+1; b = b+1 |
cube[r][g][b] = {false, star} |
for z = 1, sha, 1 do |
rd = (rw*(z-r))^2 |
cu2 = cube[z] |
for y = 1, sha, 1 do |
gd = (gw*(y-g))^2 |
cu1 = cu2[y] |
for x = 1, sha, 1 do |
cu1[x][2] = math.min(rd+gd+(bw*(x-b))^2, cu1[x][2]) |
end;end;end |
end |
-- |
-- Create new allowed colorlines in colorspace (ramps from which colors can be picked) |
function db.enableRangeColorsInCube(cube,sha,r1,g1,b1,r2,g2,b2) |
local div,r,g,b,n,rs,gs,bs |
div = 256 / sha |
rs = (r2 - r1) / sha / div |
gs = (g2 - g1) / sha / div |
bs = (b2 - b1) / sha / div |
for n = 0, sha-1, 1 do |
r = math.floor(r1/div + rs * n) |
g = math.floor(g1/div + gs * n) |
b = math.floor(b1/div + bs * n) |
cube[r+1][g+1][b+1][1] = true |
end |
end |
-- |
function db.colorCigarr(shades,radius,fill_flag) |
local s,rad,radsq,step,shalf,bas,cols,found,x,y,z,bri,con,d,n |
radius = radius / 100 |
step = math.floor(255 / (shades-1)) |
shalf = math.floor(shades / 2) |
s = shades - 1 |
rad = math.floor(shades / 2 * radius) |
radsq = rad^2 |
bas = 0 |
cols = {} |
found = 0 |
for z = 0, s, 1 do |
for y = 0, s, 1 do |
for x = 0, s, 1 do |
--0.26,0.55,0.19 |
bri = (x + y + z ) / 3 |
--bri = math.sqrt(((x*0.26)^2 + (y*0.55)^2 + (z*0.19)^2)) * 1.5609 |
con = math.floor((shades - math.abs(bri - shalf)*2) * radius) |
d = math.floor(math.sqrt((bri-x)^2 + (bri-y)^2 + (bri-z)^2)) |
--d = math.floor(math.sqrt(((bri-x)*0.26)^2 + ((bri-y)*0.55)^2 + ((bri-z)*0.19)^2)) * 1.5609 |
-- Filled cigarr: Less or Equal, cigarr shell: Equal |
if d == con or (d < con and fill_flag) then |
found = found + 1 |
r = bas + x * step |
g = bas + y * step |
b = bas + z * step |
cols[found] = {r,g,b} |
end |
end; end; end |
--messagebox("Colors found: "..found.."\n\n".."Run AnalyzePalette to examine") |
for n = 0, 255, 1 do |
if n < found then |
c = cols[n+1] |
setcolor(n,c[1],c[2],c[3]) |
else |
setcolor(n,0,0,0) |
end |
end |
end -- eof colorcigarr |
-- |
-- ... eof Color Cube ... |
-- |
-- COLORMIX -- |
-- |
-- Returns a list of mixcolors palette entries, that are ranked by by quality & usefulness |
-- |
-- This whole junk my partly locked on 16 shades (4096 colors/ 12bit palette precision) so don't use anything else... |
-- |
-- |
function db.colormixAnalysis(sha,spare_flag,cust_dist) -- Interface |
local shades,pallist,ilist,custom_max_distance |
shades = sha -- 16 is good |
--messagebox(shades) |
custom_max_distance = -1 |
if cust_dist ~= null then |
custom_max_distance = cust_dist -- in % |
end |
if spare_flag == true then -- No shades here for now |
--pallist = db.makePalListShadeSPARE(256,shades) -- 16 shades so Colorcube processes is possible |
pallist = db.makeSparePalList(256) |
pallist = db.fixPalette(pallist,0) -- Remove doubles, No need to sort? |
ilist = db.makeIndexList(pallist, -1) -- -1, use list order as index |
else |
pallist = db.makePalListShade(256,shades) -- 16 shades so Colorcube processes is possible |
pallist = db.fixPalette(pallist,0) -- Remove doubles, No need to sort? |
ilist = db.makeIndexList(pallist, -1) -- -1, use list order as index |
end |
if shades > 0 then |
return db.colormixAnalysisEXT(shades,pallist,ilist,custom_max_distance) -- max distance in % |
end |
if shades == -1 then |
return db.colormixAnalysisEXTnoshade(pallist,ilist,custom_max_distance) -- max distance in % |
end |
end |
-- |
-- |
function db.colormixAnalysisEXT(SHADES,pallist,ilist,custom_max_distance) -- Shades, most number of mixes returned |
local n,m,c1,c2,pairs,cube,rm,gm,bm |
local mix,total,found,dist,void,ideal,mini,maxi,bestmix,bestscore |
--messagebox("will now make pairs") |
pairs = db.pairsFromList(ilist,0) -- 0 for unique pairs only, pairs are entries in pallist |
--messagebox(#pairs.." will now add colors to cube") |
cube = db.initColorCube(SHADES,{true,9999}) |
for n = 1, #pallist, 1 do |
c1 = pallist[n] |
db.addColor2Cube_test(cube,SHADES,c1[1],c1[2],c1[3],0.26,0.55,0.19) |
end |
-- these values are adjusted for a 12bit palette (0-15) and perceptual weight where r+g+b = 1.0 |
-- Ideal distance = 2.5 Green steps = 1.375 |
-- Minimum distance = 1 Green step = 0.55 |
--messagebox("colorcube done") |
VACT = 1 |
DACT = 1 |
total = 9.56 -- Max distance possible with 16 shades |
ideal = 0.45 -- 1 step = 0.637 |
mini = 0.35 |
maxi = ideal + (total - ideal) / math.max(1, #pallist / 16) |
if custom_max_distance ~= -1 then |
maxi = total * (custom_max_distance / 100) |
end |
mix = {} |
--mix[1] = {9e99,0,0,9e99,0,0,0} |
bestmix = -1 |
bestscore = 9e99 |
found = 0 |
for n = 1, #pairs, 1 do |
c1 = pallist[pairs[n][1]] |
c2 = pallist[pairs[n][2]] |
--0.26,0.55,0.19 |
dist = db.getColorDistance_weight(c1[1],c1[2],c1[3],c2[1],c2[2],c2[3],0.26,0.55,0.19) -- Not normalized |
rm = math.floor((c1[1]+c2[1])/2) |
gm = math.floor((c1[2]+c2[2])/2) |
bm = math.floor((c1[3]+c2[3])/2) |
-- Mix color adjustment (perhaps less than perfect, but probably good enough) |
mixbri = db.getBrightness(rm,gm,bm) |
truebri = math.sqrt((db.getBrightness(c1[1],c1[2],c1[3])^2 + db.getBrightness(c2[1],c2[2],c2[3])^2) / 2) |
diff = truebri - mixbri |
rm = math.max(0,math.min(15,math.floor(rm + diff))) |
gm = math.max(0,math.min(15,math.floor(gm + diff))) |
bm = math.max(0,math.min(15,math.floor(bm + diff))) |
newbri = db.getBrightness(rm,gm,bm) |
delta = math.abs(newbri - truebri) |
--if delta > 0.9 then |
-- messagebox(pallist[pairs[n][1]][4]..", "..pallist[pairs[n][2]][4].." delta = "..delta) |
--end |
-- |
--rm = math.floor(math.sqrt((c1[1]^2 + c2[1]^2) / 2)) |
--gm = math.floor(math.sqrt((c1[2]^2 + c2[2]^2) / 2)) |
--bm = math.floor(math.sqrt((c1[3]^2 + c2[3]^2) / 2)) |
void = cube[rm+1][gm+1][bm+1][2] |
if dist >= mini and dist <= maxi then |
found = found + 1 |
score = ((1+DACT*(dist - ideal)^2) / (1+void*VACT)) -- Lowest is best |
mix[found] = {score,pallist[pairs[n][1]][4],pallist[pairs[n][2]][4],dist,rm*SHADES,gm*SHADES,bm*SHADES,c1[1]*SHADES,c1[2]*SHADES,c1[3]*SHADES,c2[1]*SHADES,c2[2]*SHADES,c2[3]*SHADES} -- mix holds palette entry |
if score < bestscore then bestscore = score; bestmix = found; end |
end |
end |
if true == false then |
-- 2nd pass, add bestmix to colorspace. This reduces many similar mixes. |
m = mix[bestmix] |
db.addColor2Cube(cube,SHADES,m[5],m[6],m[7],0.26,0.55,0.19) |
for n = 1, #mix, 1 do |
if n ~= bestmix then |
m = mix[n] |
dist = m[4] |
void = cube[m[5]+1][m[6]+1][m[7]+1][2] |
score = ((1+DACT*(dist - ideal)^2) / (1+void*VACT)) |
m[1] = score |
end |
end |
end |
c1,c2 = -1,-1 |
if found > 0 then |
db.sorti(mix,1) |
best = mix[1] |
c1 = best[2] |
c2 = best[3] |
end |
--return found,c1,c2 |
return mix,found,c1,c2 |
end |
-- |
-- |
-- Mixcolor without colorcube - no scoring or sorting, 24bit colors, faster... |
-- |
function db.colormixAnalysisEXTnoshade(pallist,ilist,custom_max_distance) |
local n,m,c1,c2,pairs,cube,rm,gm,bm |
local mix,total,found,dist,void,ideal,mini,maxi,bestmix,bestscore |
pairs = db.pairsFromList(ilist,0) -- 0 for unique pairs only, pairs are entries in pallist |
total = 162.53 -- Max distance possible with 24-bit palette ad Dawn3.0 color weights 162.53 |
ideal = 0 |
mini = 0 |
maxi = ideal + (total - ideal) / math.max(1, #pallist / 16) |
if custom_max_distance ~= -1 then |
maxi = total * (custom_max_distance / 100) |
end |
statusmessage("Mixcol Analysis ("..#pairs.." pairs) "); |
updatescreen(); if (waitbreak(0)==1) then return; end |
mix = {} |
found = 0 |
for n = 1, #pairs, 1 do |
c1 = pallist[pairs[n][1]] |
c2 = pallist[pairs[n][2]] |
--0.26,0.55,0.19 |
dist = db.getColorDistance_weight(c1[1],c1[2],c1[3],c2[1],c2[2],c2[3],0.26,0.55,0.19) -- Not normalized |
rm = math.floor((c1[1]+c2[1])/2) |
gm = math.floor((c1[2]+c2[2])/2) |
bm = math.floor((c1[3]+c2[3])/2) |
-- Mix color adjustment |
mixbri = db.getBrightness(rm,gm,bm) |
truebri = math.sqrt((db.getBrightness(c1[1],c1[2],c1[3])^2 + db.getBrightness(c2[1],c2[2],c2[3])^2) / 2) |
diff = truebri - mixbri |
rm = math.max(0,math.min(255,math.floor(rm + diff))) |
gm = math.max(0,math.min(255,math.floor(gm + diff))) |
bm = math.max(0,math.min(255,math.floor(bm + diff))) |
newbri = db.getBrightness(rm,gm,bm) |
delta = math.abs(newbri - truebri) |
--if delta > 0.9 then |
-- messagebox(pallist[pairs[n][1]][4]..", "..pallist[pairs[n][2]][4].." delta = "..delta) |
--end |
-- |
if dist >= mini and dist <= maxi then |
found = found + 1 |
score = 1 |
mix[found] = {score,pallist[pairs[n][1]][4],pallist[pairs[n][2]][4],dist,rm,gm,bm,c1[1],c1[2],c1[3],c2[1],c2[2],c2[3]} -- mix holds palette entry |
end |
end |
--messagebox(#mix) |
return mix,found,-1,-1 |
end |
-- |
-- Fuse a palettelist into an extended mix-anlysis list |
function db.fusePALandMIX(pal,mix,max_score,max_dist) |
local n,c,mixlist,tot,score,dist,c1,c2,rm,gm,bm |
mixlist = {} |
tot = 0 |
-- {r,g,b,n} |
for n = 1, #pal, 1 do |
tot = tot + 1 |
c = pal[n] |
mixlist[tot] = {0,c[4],c[4],0,c[1],c[2],c[3],c[1],c[2],c[3],c[1],c[2],c[3]} |
end |
-- {score,col#1,col#2,dist,rm,gm,bm} low score is best |
for n = 1, #mix, 1 do |
score = mix[n][1] |
dist = mix[n][4] |
if score <= max_score and dist <= max_dist then |
tot = tot + 1 |
mixlist[tot] = mix[n] |
end |
end |
return mixlist |
end |
-- |
-- ******************************************** |
-- *** L-system (fractal curves & "plants") *** |
-- ******************************************** |
-- |
-- |
function db.Lsys_makeData(a) |
local n,i; i = {} |
for n = 1, #a, 1 do i[a[n][2]] = a[n]; end |
return i |
end |
-- |
-- |
function db.Lsys_makeSet(seed,iter,data) |
local s,n,i,nset,set |
set = seed |
for n = 1, iter, 1 do |
nset = '' |
for i = 1, #set, 1 do |
s = string.sub(set,i,i) |
nset = nset..data[s][3] |
end |
set = nset |
end |
return set |
end |
-- |
function db.Lsys_draw(set,data,cx,cy,size,rot,rgb,rng,transp, speed) |
local p,M,DEG,l,n,d,i,v,q,c,tx,ty,posx,posy,dval,col,w,h,s,cl,count |
if speed == nil then speed = 50; end -- speed is drawing operations per update |
function ang(d) return (d % 360 + 360) * DEG; end |
w,h = getpicturesize() |
p = 0 |
M = math |
DEG = math.pi/180 |
l = #set |
posx={}; posy={}; dval={} |
if (rgb == null) then rgb = {0,0,0}; end |
if (transp == null) then transp = 0; end |
col = db.newArrayMerge(rgb,{}) |
q = 255 / l |
count = 0 |
for n = 1, l, 1 do |
s = string.sub(set,n,n) |
d = data[s] |
i = d[1] |
v = d[4] |
--messagebox(i) |
if (i == 'Left') then rot = rot - v; end |
if (i == 'Right') then rot = rot + v; end |
if (i == 'Save') then p=p+1; posx[p] = cx; posy[p] = cy; dval[p] = rot; end |
if (i == 'Load') then cx = posx[p]; cy = posy[p]; rot = dval[p]; p=p-1; end |
if (i == 'Draw') then |
tx = cx + M.sin(ang(rot)) * size |
ty = cy + -M.cos(ang(rot)) * size |
for c = 1, 3, 1 do |
if (rng[c] > 0) then col[c] = rgb[c] + (n * q) * rng[c]; end |
if (rng[c] < 0) then col[c] = rgb[c] + (n * q) * rng[c]; end |
end |
cl = matchcolor(col[1],col[2],col[3]) |
--putpicturepixel(cx*w,cy*h,cl); |
--db.line(cx*w,cy*h,tx*w,ty*h,cl) |
db.lineTransp(cx*w,cy*h,tx*w,ty*h,cl,transp) |
cx = tx; cy = ty |
end |
count = count + 1 |
if count == speed then count = 0; updatescreen(); if (waitbreak(0)==1) then return end; end |
end |
return {cx,cy,rot} |
end -- draw |
-- |
-- eof L-system |
-- |
--------------------------------------------------------------------------------------- |
-- ******************************************** |
-- *** COMPLEX SPECIAL FUNCTIONS *** |
-- ******************************************** |
-- |
--------------------------------------------------------------------------------------- |
-- |
-- Render engine for mathscenes (Full Floyd-Steinberg dither etc) |
-- |
function db.fsrender(f,pal,ditherprc,xdith,ydith,percep,xonly, ord_bri,ord_hue,bri_change,hue_change,BRIWEIGHT, wd,ht,ofx,ofy) -- f is function |
local w,h,i,j,c,x,y,r,g,b,d,fl,v,v1,v2,vt,vt1,vt2,dither,m,mathfunc,dpow,fsdiv,ord,d1a,d1b,briweight |
local d1,d2,o1,o2,ox,oy |
-- percep is no longer used, matchcolor2 is always active, but the code is kept if there's ever a need to |
-- study the effect of perceptual colorspaces versus matchcolor |
if ord_bri == null then ord_bri = 0; end |
if ord_hue == null then ord_hue = 0; end |
if bri_change == null then bri_change = 0; end |
if hue_change == null then hue_change = 0; end |
if BRIWEIGHT == null then BRIWEIGHT = 0; end |
briweight = BRIWEIGHT / 100 |
ord = {{0,4,1,5}, |
{6,2,7,3}, |
{1,5,0,4}, |
{7,3,6,2}} |
--i = ((ord[y % 4 + 1][x % 4 + 1])*28.444 - 99.55556)/100 * 16 |
function hue(r,g,b,deg) |
local i,brin,diff,brio,r2,g2,b2 |
r2,g2,b2 = db.shiftHUE(r,g,b,deg) |
brio = db.getBrightness(r,g,b) |
for i = 0, 5, 1 do -- 6 iterations, fairly strict brightness preservation |
brin = db.getBrightness(r2,g2,b2) |
diff = brin - brio |
r2,g2,b2 = db.rgbcap(r2-diff, g2-diff, b2-diff, 255,0) |
end |
return r2,g2,b2 |
end |
fsdiv = 16 |
if xonly == 1 then fsdiv = 7; end -- Only horizontal dither |
dither = 0; if ditherprc > 0 then dither = 1; end |
-- When using standard error-diffusion brightness-matching is not really compatible |
--matchfunc = matchcolor2 |
--if dither == 1 then matchfunc = matchcolor; end |
dpow = ditherprc / 100 |
if wd == null then |
w,h = getpicturesize() |
else w = wd; h = ht |
end |
if ofx == null then |
ox,oy = 0,0 |
else ox = ofx; oy = ofy |
end |
function cap(v) |
return math.min(255,math.max(0,v)) |
end |
-- |
fl = {} |
fl[1] = {} |
fl[2] = {} |
i = 1 |
j = 2 |
-- |
-- Read the first 2 lines |
v1 = ydith/2 + 0%2 * -ydith |
v2 = ydith/2 + 1%2 * -ydith |
for x = 0, w - 1, 1 do |
d1a,d1b = 0,0 |
if ord_bri > 0 then |
o1 = ord[0 % 4 + 1][x % 4 + 1] |
d1a = (o1*28.444 - 99.55556)/100 * ord_bri |
o2 = ord[1 % 4 + 1][(x+2) % 4 + 1] -- +2 To get it in right sequence for some reason |
d1b = (o2*28.444 - 99.55556)/100 * ord_bri |
end |
-- We skip Hue-ordering for now |
vt1 = v1 + xdith/2 + (x+math.floor(0/2))%2 * -xdith + d1a |
vt2 = v2 + xdith/2 + (x+math.floor(1))%2 * -xdith + d1b -- Ok, not sure why 1/2 doesn't make for a nice pattern so we just use 1 |
r,g,b = f(x, 0, w, h) |
fl[i][x] = {cap(r+vt1),cap(g+vt1),cap(b+vt1)} |
r,g,b = f(x, 1, w, h) |
fl[j][x] = {cap(r+vt2),cap(g+vt2),cap(b+vt2)} |
end |
for y = 0, h-1, 1 do |
for x = 0, w-1, 1 do |
o = fl[i][x] |
r = o[1] + bri_change |
g = o[2] + bri_change |
b = o[3] + bri_change |
if hue_change ~= 0 then |
r,g,b = hue(r,g,b,hue_change) |
end |
--if percep == 0 then c = matchfunc(r,g,b); end |
--if percep == 1 then |
-- --c = db.getBestPalMatchHYBRID({r,g,b},pal,0,true) |
--c = matchcolor2(r,g,b,briweight) |
--end |
c = matchcolor2(r,g,b,briweight) |
putpicturepixel(x+ox,y+oy,c) |
if dither == 1 then |
if x>1 and x<w-1 and y<h-1 then |
rn,gn,bn = getcolor(c) |
re = ((r - rn) / fsdiv) * dpow |
ge = ((g - gn) / fsdiv) * dpow |
be = ((b - bn) / fsdiv) * dpow |
o = fl[i][x+1]; r,g,b = o[1],o[2],o[3] |
fl[i][x+1] = {cap(r+re*7), cap(g+ge*7), cap(b+be*7)} |
if xonly ~= 1 then |
o = fl[j][x]; r,g,b = o[1],o[2],o[3] |
fl[j][x] = {cap(r+re*5), cap(g+ge*5), cap(b+be*5)} |
o = fl[j][x-1]; r,g,b = o[1],o[2],o[3] |
fl[j][x-1] = {cap(r+re*3), cap(g+ge*3), cap(b+be*3)} |
o = fl[j][x+1]; r,g,b = o[1],o[2],o[3] |
fl[j][x+1] = {cap(r+re), cap(g+ge), cap(b+be)} |
end |
end |
end |
end |
vt = 0 |
v = ydith/2 + y%2 * -ydith |
-- Flip ED lines and read the nextline |
i,j = j,i |
for x = 0, w - 1, 1 do |
d1,d2 = 0,0 |
if ord_bri > 0 then |
o = ord[y % 4 + 1][x % 4 + 1] |
d1 = (o*28.444 - 99.55556)/100 * ord_bri |
end |
vt = v + xdith/2 + (x+math.floor(y/2))%2 * -xdith + d1 |
r,g,b = f(x, y+2, w, h) |
if ord_hue > 0 then |
o = ord[y % 4 + 1][x % 4 + 1] |
d2 = (((o + 3.5) % 7) / 7 - 0.5) * ord_hue |
r,g,b = hue(r,g,b,d2) |
end |
fl[j][x] = {cap(r+vt),cap(g+vt),cap(b+vt)} |
end |
updatescreen(); if (waitbreak(0)==1) then return; end |
end |
end |
------------------------------------------------------------------------------- |
-- |
-- ROTATE Image or Brush |
-- |
-- target: 1 = Brush, 2 = Picture, 3 = Brush-to-Picture |
-- rot: Rotation in degrees |
-- mode: 1 = Simple, 2 = Cosine Interpolation, 2 = BiLinear Interpolation |
-- spritemode: 0 = Off, 1 = On (Only match adjacent colors, use with Bilinear-Ip. for good result) |
-- resize: 0 = No, 1 = Yes (Resize Image/Brush to fit all gfx, otherwise clip) |
-- update: 0 = No, 1 = Yes (Update screen while drawing) |
-- xoffset: For use with Brush-to-Picture operations |
-- yoffset: For use with Brush-to-Picture operations |
-- |
function db.doRotation(target,rot,mode,spritemode,resize,update, xoffset,yoffset) |
local trg,f,w,h,x,y,r,g,b,c,hub_x,hub_y,x1,y1,x2,y2,x3,y3,x4,y4,dX,dY,dXs,dYs,ox,oy,mx,my,xp,yp,pal,func |
function donothing(n) |
end |
func = { |
{getsize=getbrushsize, setsize=setbrushsize, clear=donothing, get=getbrushbackuppixel, put=putbrushpixel}, |
{getsize=getpicturesize, setsize=setpicturesize, clear=clearpicture, get=getbackuppixel, put=putpicturepixel}, |
{getsize=getbrushsize, setsize=donothing, clear=donothing, get=getbrushbackuppixel, put=putpicturepixel} |
} |
trg = func[target] |
-- |
function bilinear(ox,oy,w,h,func,mode) |
local xp1,xp2,yp1,yp2,r1,r2,r3,r4,g1,g2,g3,g4,b1,b2,b3,b4,r,g,b, c1,c2,c3,c4,pal,adjx,adjy |
xp2 = ox - math.floor(ox) |
yp2 = oy - math.floor(oy) |
if mode == 1 then -- Cosinus curve (rather than linear), slightly sharper result (probably same as Photoshop) |
xp2 = 1 - (math.cos(xp2 * math.pi) + 1)/2 |
yp2 = 1 - (math.cos(yp2 * math.pi) + 1)/2 |
end |
xp1 = 1 - xp2 |
yp1 = 1 - yp2 |
c1 = func(math.floor(ox),math.floor(oy)); |
c2 = func(math.ceil(ox),math.floor(oy)); |
c3 = func(math.floor(ox),math.ceil(oy)); |
c4 = func(math.ceil(ox),math.ceil(oy)); |
r1,g1,b1 = getcolor(c1); |
r2,g2,b2 = getcolor(c2); |
r3,g3,b3 = getcolor(c3); |
r4,g4,b4 = getcolor(c4); |
pal = {{r1,g1,b1,c1},{r2,g2,b2,c2},{r3,g3,b3,c3},{r4,g4,b4,c4}} -- for SpriteMode ColorMatching |
r = (r1*xp1 + r2*xp2)*yp1 + (r3*xp1 + r4*xp2)*yp2; |
g = (g1*xp1 + g2*xp2)*yp1 + (g3*xp1 + g4*xp2)*yp2; |
b = (b1*xp1 + b2*xp2)*yp1 + (b3*xp1 + b4*xp2)*yp2; |
return r,g,b, pal |
end |
-- |
f = db.rotationFrac |
w,h = trg.getsize() |
hub_x = w / 2 - 0.5 -- Rotates 90,180 perfectly, not 45 |
hub_y = h / 2 - 0.5 |
--hub_x = w / 2 |
--hub_y = h / 2 |
x1,y1 = f (-rot,hub_x,hub_y,0,0) -- Rot is negative coz we read destination and write to source |
x2,y2 = f (-rot,hub_x,hub_y,w-1,0) |
x3,y3 = f (-rot,hub_x,hub_y,0,h-1) |
x4,y4 = f (-rot,hub_x,hub_y,w-1,h-1) |
dX = (x2 - x1) / w |
dY = (y2 - y1) / w |
dXs = (x4 - x2) / h |
dYs = (y3 - y1) / h |
adjx,adjy = 0,0 |
ox,oy = 0,0 |
if resize == 1 then |
mx = math.ceil(math.max(math.abs(x1-hub_x),math.abs(x3-hub_x))) * 2 + 2 |
my = math.ceil(math.max(math.abs(y1-hub_y),math.abs(y3-hub_y))) * 2 + 2 |
if target == 3 then -- Center gfx at Brush-to-Picture |
adjx = -mx/2 |
adjy = -my/2 |
end |
ox = (mx - w) / 2 |
oy = (my - h) / 2 |
trg.setsize(mx,my) |
end |
trg.clear(0) |
for y = -oy, h-1+oy, 1 do |
RE,GE,BE = 0,0,0 |
for x = -ox, w-1+ox, 1 do |
xp = x1 + dX * x + dXs * y |
yp = y1 + dY * x + dYs * y |
if mode == 2 or mode == 3 then |
r,g,b,pal = bilinear(xp,yp,w,h,trg.get, mode_co) |
if spritemode == 1 then |
c = db.getBestPalMatchHYBRID({r+RE,g+GE,b+BE},pal,0.65,true) -- Brightness do very little in general with 4 set colors |
else c = matchcolor2(r+RE,g+GE,b+BE) |
end |
else c = trg.get(xp,yp) |
end |
--rn,gn,bn = getcolor(c) |
--RE = (r - rn)*0.5 |
--GE = (g - gn)*0.5 |
--BE = (b - bn)*0.5 |
trg.put(x+ox+xoffset+adjx,y+oy+yoffset+adjy, c) |
end |
if update == 1 then |
statusmessage("Working... %"..math.floor(((y+oy) / (h-1+2*oy))*100)) |
updatescreen(); if (waitbreak(0)==1) then return; end |
end |
end |
end; -- doRotation |
------------------------------------------------------------------------------- |
-- |
-- PARTICLE v1.0 |
-- |
-- Draw Sphere or Disc to any target with gradients that may fade to background |
-- |
-- type: "sphere" - volmetric planet-like disc |
-- "disc" - plain disc |
-- mode: "blend" - mix graphics with background color |
-- "add" - add graphics to background color |
-- wd,ht: - Max Width/Height of drawing area, i.e. screen size (needed if drawing to an array-buffer) |
-- sx,sy: - drawing coordinates (center) |
-- xrad,yrad: - x & y radii |
-- rgba1: - rgb+alpha array of center color: {r,g,b,a}, alpha is 0..1 where 1 is no transparency, Extreme rgb-values allowed |
-- rgba2: - rgb+alpha array of edge color: {r,g,b,a}, alpha is 0..1 where 1 is no transparency, Extreme rgb-values allowed |
-- update_flag: - Display rendering option (and add break feature) |
-- f_get: - Get pixel function: use getpicturepixel if reading from image (set null for image default) |
-- f_put: - Put pixel function: use putpicturepixel if drawing to image (set null for image default) |
-- f_recur: - Optional custom control-function for recursion (set null if not used) |
-- recur_count - Recursion depth counter, for use in combination with a custom function (f_recur), 0 as default |
-- |
-- Ex: particle("sphere","add", w,h, w/2,h/2, 40,40, {500,400,255, 0.8},{0,-150,-175, 0.0}, true, null, null, null, 0) |
-- |
function db.particle(type,mode,wd,ht,sx,sy,xrad,yrad,rgba1,rgba2, update_flag, f_get, f_put, f_recur, recur_count) |
local x,y,rev,dix,diy,r3,g3,b3,px,py,alpha,ralpha,add,q,rgb,rgb1,rgb2,rgb3,n,def_get,def_put |
function def_get(x,y) |
local r,g,b |
r,g,b = getcolor(getpicturepixel(x,y)); |
return {r,g,b} |
end |
function def_put(x,y,r,g,b) putpicturepixel(x,y, matchcolor2(r,g,b,0.65)); end |
if f_get == null then f_get = def_get; end |
if f_put == null then f_put = def_put; end |
q = {[true] = 1, [false] = 0} |
rgb,rgb1,rgb2 = {},{},{} |
if mode == 'blend' then |
add = 1 |
end |
if mode == 'add' then |
add = 0 |
end |
dix = xrad*2 |
diy = yrad*2 |
for y = 0, diy, 1 do |
py = sy+y-yrad; oy = y / diy; |
if (py >= 0 and py < ht) then |
for x = 0, dix, 1 do |
px = sx+x-xrad; ox = x / dix; |
if (px >= 0 and px < wd) then |
if type == 'sphere' then -- Sphere |
a = math.sqrt(math.max(0,0.25 - ((0.5-ox)^2+(0.5-oy)^2))) * 2 |
end |
if type == 'disc' then -- Disc |
a = 1-math.sqrt((0.5-ox)^2+(0.5-oy)^2)*2 |
end |
if a>0 then |
rev = 1-a |
rgb3 = f_get(px,py) |
alpha = rgba1[4] * a + rgba2[4] * rev |
ralpha = 1 - alpha * add |
for n = 1, 3, 1 do |
rgb1[n] = q[rgba1[n]==-1]*rgb3[n] + q[rgba1[n]~=-1]*rgba1[n] -- Fade from background? |
rgb2[n] = q[rgba2[n]==-1]*rgb3[n] + q[rgba2[n]~=-1]*rgba2[n] -- Fade to background? |
rgb[n] = (rgb1[n] * a + rgb2[n] * rev) * alpha + rgb3[n] * ralpha |
end |
f_put(px, py, rgb[1],rgb[2],rgb[3]); |
end |
end -- if x is good |
end -- x |
if update_flag then updatescreen(); if (waitbreak(0)==1) then return; end; end |
end -- if y is good |
end -- y |
if f_recur ~= null then -- recursion |
f_recur(type,mode,wd,ht,sx,sy,xrad,yrad,rgba1,rgba2, update_flag, f_get, f_put, f_recur, recur_count); |
updatescreen(); if (waitbreak(0)==1) then return; end; |
end |
end |
-- eof PARTICLE |
-- |
-- MedianCut a larger palette-list from a MathScene to produce a high-quality BriSorted palette for the final render/colormatching |
-- |
function db.makeSamplePal(w,h,colors,frend) |
local n,x,y,r,g,b,pal |
n,pal = 0,{} |
for y = 0, h, math.ceil(h/63) do |
for x = 0, w, math.ceil(w/63) do |
r,g,b = frend(x,y,w,h) |
n = n+1 |
r,g,b = db.rgbcapInt(r,g,b,255,0) |
pal[n] = {r,g,b,0} |
end;end |
return db.fixPalette(db.medianCut(pal, colors, true, false, {0.26,0.55,0.19}, 8, 0),1) -- pal, cols, qual, quant, weights, bits, quantpower |
end |
-- |
-- |
-- Backdrop/Gradient Render (May be written to a matrix for rendering with db.fsrender) |
-- |
function db.backdrop(p0,p1,p2,p3,fput,ip_mode) -- points:{x,y,r,g,b}, IpMode "linear" is default |
local x,y,ox,oy,xr,yr,r,g,b,ax,ay,w,h |
ax,ay = p0[1],p0[2] |
w = p1[1] - p0[1] |
h = p2[2] - p0[2] |
for y = 0, h, 1 do -- +1 to fill screen with FS-render |
oy = y/h |
if ip_mode == "cosine" then oy = 1 - (math.cos(oy * math.pi) + 1)/2; end |
yr = 1 - oy |
for x = 0, w, 1 do |
ox = x/w |
if ip_mode == "cosine" then ox = 1 - (math.cos(ox * math.pi) + 1)/2; end |
xr = 1 - ox |
r = (p0[3]*xr + p1[3]*ox)*yr + (p2[3]*xr + p3[3]*ox)*oy; |
g = (p0[4]*xr + p1[4]*ox)*yr + (p2[4]*xr + p3[4]*ox)*oy; |
b = (p0[5]*xr + p1[5]*ox)*yr + (p2[5]*xr + p3[5]*ox)*oy; |
fput(x+ax,y+ay,r,g,b) |
end;end |
end |
-- eof backdrop |
-- |
-- SPLINES -- |
-- |
function db.splinePoint(x0,y0,x1,y1,x2,y2,points,point) |
local x,y,sx1,sy1,sx2,sy2,f |
f = point * 1 / points |
sx1 = x0*(1-f) + x1*f |
sy1 = y0*(1-f) + y1*f |
sx2 = x1*(1-f) + x2*f |
sy2 = y1*(1-f) + y2*f |
x = sx1 * (1-f) + sx2 * f |
y = sy1 * (1-f) + sy2 * f |
return x,y |
end |
-- |
-- zx = 2*x1 - (x0+x2)/2 |
-- |
function db.drawSplineSegment(x0,y0,x1,y1,x2,y2,x3,y3,points,col) -- Does spline segment p1-p2 |
local n,x,y,sx1,sy1,sx2,sy2,mid,zx1,zy1,zx2,zy2,fx,fy |
mid = math.floor(points / 2) |
-- Extended Bezier points |
zx1 = 2*x1 - (x0+x2)/2 |
zy1 = 2*y1 - (y0+y2)/2 |
zx2 = 2*x2 - (x1+x3)/2 |
zy2 = 2*y2 - (y1+y3)/2 |
fx,fy = x1,y1 -- Segment to be drawn (0),1 - 2,(3) |
for n = 0, mid, 1 do |
f = n * 1 / points * 2 |
sx1,sy1 = db.splinePoint(x0,y0,zx1,zy1,x2,y2,mid*2, mid + n) |
sx2,sy2 = db.splinePoint(x1,y1,zx2,zy2,x3,y3,mid*2, n) |
x = sx1 * (1-f) + sx2 * f |
y = sy1 * (1-f) + sy2 * f |
--putpicturepixel(x,y,col) |
db.line(fx,fy,x,y,col) |
fx,fy = x,y |
end |
end |
-- |
-- eof Splines |
/data/common/media/grafx2/scripts/samples_2.4/libs/memory.lua |
---|
0,0 → 1,138 |
-- Persistence library: |
-- Memorize data for current function |
-- memory.save(tab) and tab=memory.load() |
-- |
-- The data will be stored in file called |
-- <calling_function_name>.dat |
-- in the lua directory |
-- |
-- Example 1: |
-- |
-- -- Load initial values or set defaults |
-- arg = memory.load({picX=320,picY=200,scale=0}) |
-- -- Run an inputbox |
-- OK,arg.picX,arg.picY,arg.scale = inputbox("Image Size")", |
-- "Width", arg.picX, 1,2048,0, |
-- "Height", arg.picY, 1,2048,0, |
-- "Scale", arg.scale, 0,1,0); |
-- if OK == true then |
-- -- Save the selected values |
-- memory.save(arg) |
-- end |
-- Example 2: |
-- |
-- -- Load initial values or set defaults |
-- arg = memory.load({x=320,y=200,scale=0}) |
-- picX=arg.x |
-- picY=arg.y |
-- scale=arg.scale |
-- -- Run an inputbox |
-- OK,picX,picY,scale = inputbox("Image Size")", |
-- "Width", picX, 1,2048,0, |
-- "Height", picY, 1,2048,0, |
-- "Scale", scale, 0,1,0); |
-- if OK == true then |
-- -- Save the selected values |
-- memory.save({x=picX,y=picY,scale=scale}) |
-- end |
memory = |
{ |
serialize = function(o) |
if type(o) == "number" then |
return tostring(o) |
elseif type(o) == "string" then |
return string.format("%q", o) |
--elseif type(o) == "table" then |
-- io.write("{\n") |
-- for k,v in pairs(o) do |
-- io.write(" ", k, " = ") |
-- memory.serialize(v) |
-- io.write(",\n") |
-- end |
-- io.write("}\n") |
else |
error("cannot serialize a " .. type(o)) |
end |
end; |
-- Return a string identifying the calling function. |
-- Pass 1 for parent, 2 for grandparent etc. |
callername = function(level) |
local w |
local last_slash |
local info = debug.getinfo(level+1,"Sn") |
local caller=tostring(info.name) |
-- Function name if possible |
if (caller~="nil") then |
return caller |
end |
-- Otherwise, get file name, without extension |
-- Get part after directory name |
last_slash=0 |
while true do |
local pos = string.find(info.source, "/", last_slash+1) |
if (pos==nil) then break end |
last_slash=pos |
end |
while true do |
local pos = string.find(info.source, "\\", last_slash+1) |
if (pos==nil) then break end |
last_slash=pos |
end |
caller=string.sub(info.source, last_slash+1) |
-- Remove file extension |
if (string.sub(caller,-4, -1)==".lua") then |
caller=string.sub(caller, 1, -5) |
end |
return caller |
end; |
-- Memorize some parameters. |
save = function(o) |
local caller=memory.callername(2) |
--for k, v in pairs(o) do |
-- messagebox(tostring(k)) |
-- messagebox(tostring(v)) |
--end |
local f, e = io.open(caller..".dat", "w"); |
if (f ~= nil) then |
f:write("Entry {\n") |
for k, v in pairs(o) do |
if (type(v)=="number") then |
f:write(" "..k.."="..memory["serialize"](v)..",\n") |
end |
end |
f:write("}\n") |
f:close() |
end |
end; |
-- Recover some saved parameters. |
load = function(o) |
local caller=memory.callername(2) |
local i |
function Entry (b) |
-- Adds (or replaces) values in arg with those from b |
for k, v in pairs(b) do |
o[k]=v |
end |
end |
local f = (loadfile(caller..".dat")) |
if (f ~= nil) then |
f() |
end |
return o |
end; |
} |
return memory |
/data/common/media/grafx2/scripts/samples_2.4/palette/Desaturate.lua |
---|
0,0 → 1,40 |
--PALETTE Adjust: Desaturate v1.1 |
--by Richard Fhager |
--http://hem.fyristorg.com/dawnbringer/ |
-- Copyright 2010 Richard Fhager |
-- |
-- 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; version 2 |
-- of the License. See <http://www.gnu.org/licenses/> |
-- This script was adopted from Evalion, a Javascript codecrafting/imageprocessing project |
-- http://goto.glocalnet.net/richard_fhager/evalion/evalion.html |
-- Note: Negative values will work as INCREASED saturation, but I'm not sure if this function is 100% correct |
--percent = 25 |
OK,percent = inputbox("Desaturate Palette","Percent %", 25, 0,100,0); |
-- |
function desaturate(percent,r,g,b) -- V1.0 by Richard Fhager |
p = percent / 100 |
a = (math.min(math.max(r,g,b),255) + math.max(math.min(r,g,b),0)) * 0.5 * p |
r = r + (a-r*p) |
g = g + (a-g*p) |
b = b + (a-b*p) |
return r,g,b |
end |
-- |
if OK == true then |
for c = 0, 255, 1 do |
setcolor(c, desaturate(percent,getcolor(c))) |
end |
end |
/data/common/media/grafx2/scripts/samples_2.4/palette/ExpandColors.lua |
---|
0,0 → 1,171 |
--PALETTE: Expand Colors v1.0 |
--by Richard Fhager |
--http://hem.fyristorg.com/dawnbringer/ |
-- Email: dawnbringer@hem.utfors.se |
-- MSN: annassar@hotmail.com |
-- |
-- Copyright 2010 Richard Fhager |
-- |
-- 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; version 2 |
-- of the License. See <http://www.gnu.org/licenses/> |
-- Continously fill the greatest void in the area of the color-cube enclosed by (or along ramps of) initial colors |
-- This algorithm will create lines of allowed colors (all ranges) in 3d colorspace and the pick |
-- new colors from the most void areas (on any line). Almost like a Median-cut in reverse. |
-- |
-- Rather than filling the colorcube symmetrically it adds intermediate colors to the existing ones. |
-- |
-- Running this script on the C64 16-color palette might be educational |
-- |
-- |
-- Source cols#, Expand to #, |
-- Ex: 15-31 means that palette colors 0-15 is expanded to 16 new colors placed at slots 16-31 |
-- |
-- Spread mode: OFF - New colors will conform to the contrast & saturation of original colors |
-- (new colors will stay on the ramps possible from the original colors) |
-- |
-- ON - New colors will expand their variance by each new addition (mostly notable when adding many new colors) |
-- Will add range lines/ramps to all new colors from old ones, but keep within max/min values of the |
-- original colors. 15-bit mode will dampen the spread towards extreme colors (if starting with low contrast) |
-- |
-- 15-bit colors: Higher color-resolution, 32768 possible colors rather than the 4096 of 12bit. Slower but perhaps better. |
-- |
SHADES = 16 -- Going 24bit will probably be too slow and steal too much memory, so start with 12bit (4096 colors) for now |
ini = 0 |
exp = 255 |
OK,ini,exp,linemode,fbit = inputbox("Expand Colors (0-255):", |
"Source Cols #: 1-254", 15, 1,254,0, |
"Expand to #: 2-255", 31, 2,255,0, |
"Spread mode", 0, 0,1,0, |
"15-bit colors (slow)", 0, 0,1,0 |
); |
if (fbit == 1) then SHADES = 32; end |
function initColorCube(sha) |
ary = {} |
for z = 0, sha-1, 1 do |
ary[z+1] = {} |
for y = 0, sha-1, 1 do |
ary[z+1][y+1] = {} |
for x = 0, sha-1, 1 do |
ary[z+1][y+1][x+1] = {false,0} |
end |
end |
end |
return ary |
end |
-- Gravity model (think of colors as stars of equal mass/brightness in a 3d space) |
function addColor2Cube(cube,sha,r,g,b) |
star = 1000000 |
fade = 1000 |
cube[r+1][g+1][b+1] = {false,star} |
for z = 0, sha-1, 1 do |
for y = 0, sha-1, 1 do |
for x = 0, sha-1, 1 do |
d = fade / ( (x-b)^2 + (y-g)^2 + (z-r)^2 ) |
cube[z+1][y+1][x+1][2] = cube[z+1][y+1][x+1][2] + d |
end;end;end |
end |
-- Create new allowed colorlines in colorspace (ramps from which colors can be picked) |
function enableRangeColorsInCube(cube,sha,r1,g1,b1,r2,g2,b2) |
local div,r,g,b |
div = 256 / sha |
rs = (r2 - r1) / sha / div |
gs = (g2 - g1) / sha / div |
bs = (b2 - b1) / sha / div |
for n = 0, sha-1, 1 do |
r = math.floor(r1/div + rs * n) |
g = math.floor(g1/div + gs * n) |
b = math.floor(b1/div + bs * n) |
cube[r+1][g+1][b+1][1] = true |
end |
end |
function findVoid(cube,sha) |
weakest = 999999999999 |
weak_i = {-1,-1,-1} |
for z = 0, sha-1, 1 do |
for y = 0, sha-1, 1 do |
for x = 0, sha-1, 1 do |
c = cube[z+1][y+1][x+1] |
if c[1] == true then |
w = c[2] |
if w <= weakest then weakest = w; weak_i = {z,y,x}; end |
end |
end;end;end |
return weak_i[1],weak_i[2],weak_i[3] |
end |
-- |
if OK == true then |
cube = initColorCube(SHADES) |
-- Define allowed colorspace |
for y = 0, ini-1, 1 do |
r1,g1,b1 = getcolor(y) |
for x = y+1, ini, 1 do |
r2,g2,b2 = getcolor(x) |
enableRangeColorsInCube(cube,SHADES,r1,g1,b1,r2,g2,b2) |
end |
end |
div = 256 / SHADES |
-- Fill cube with initial colors |
for n = 0, ini, 1 do |
r,g,b = getcolor(n) |
addColor2Cube(cube,SHADES,math.floor(r/div),math.floor(g/div),math.floor(b/div)) |
end |
for n = ini+1, exp, 1 do |
r,g,b = findVoid(cube,SHADES) |
if (r == -1) then messagebox("Report:","No more colors can be found, exit at "..n); break; end |
mult = 255 / (SHADES - 1) |
setcolor(n, r*mult,g*mult,b*mult) |
if linemode == 1 then |
-- Add lines from new color to all old |
for x = 0, n-1, 1 do |
r2,g2,b2 = getcolor(x) |
enableRangeColorsInCube(cube,SHADES,r*mult,g*mult,b*mult,r2,g2,b2) -- uses 24bit values rgb |
end |
end |
addColor2Cube(cube,SHADES,r,g,b) -- rgb is in 'shade' format here |
end |
end |
/data/common/media/grafx2/scripts/samples_2.4/palette/FillColorCube.lua |
---|
0,0 → 1,105 |
--PALETTE: Fill ColorCube voids v1.0 |
--by Richard Fhager |
--http://hem.fyristorg.com/dawnbringer/ |
-- Email: dawnbringer@hem.utfors.se |
-- MSN: annassar@hotmail.com |
-- |
-- Copyright 2010 Richard Fhager |
-- |
-- 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; version 2 |
-- of the License. See <http://www.gnu.org/licenses/> |
-- |
-- Create a palette by continously filling the greatest void in the RGB color-cube |
-- |
SHADES = 16 -- Going 24bit will probably be too slow and steal too much memory, so we're 12bit (4096 colors) for now |
ini = 0 |
exp = 255 |
OK,ini,exp = inputbox("Fill Palette Color voids", |
"From/Keep #: 0-254", 0, 0,254,0, |
"Replace to #: 1-255", 31, 1,255,0 |
); |
function initColorCube(sha) |
ary = {} |
for z = 0, sha-1, 1 do |
ary[z+1] = {} |
for y = 0, sha-1, 1 do |
ary[z+1][y+1] = {} |
end |
end |
return ary |
end |
function addColor2Cube(cube,sha,r,g,b) -- Gravity model |
star = 1000000 |
fade = 1000 |
cube[r+1][g+1][b+1] = star |
for z = 0, sha-1, 1 do |
for y = 0, sha-1, 1 do |
for x = 0, sha-1, 1 do |
d = fade / ( (x-b)^2 + (y-g)^2 + (z-r)^2 ) |
if cube[z+1][y+1][x+1] ~= nil then |
cube[z+1][y+1][x+1] = cube[z+1][y+1][x+1] + d |
else |
cube[z+1][y+1][x+1] = d |
end |
end;end;end |
end |
function findVoid(cube,sha) |
weakest = 999999999999 |
weak_i = {-1,-1,-1} |
for z = 0, sha-1, 1 do |
for y = 0, sha-1, 1 do |
for x = 0, sha-1, 1 do |
w = cube[z+1][y+1][x+1] |
if w <= weakest then weakest = w; weak_i = {z,y,x}; end |
end;end;end |
return weak_i[1],weak_i[2],weak_i[3] |
end |
-- |
if OK == true then |
cube = initColorCube(SHADES) |
-- Fill cube with initial colors |
for n = 0, ini-1, 1 do |
r,g,b = getcolor(n) |
div = SHADES |
addColor2Cube(cube,SHADES,math.floor(r/div),math.floor(g/div),math.floor(b/div)) |
end |
if ini == 0 then -- With no inital color, some inital data must be added to the colorcube. |
addColor2Cube(cube,SHADES,0,0,0) |
setcolor(0, 0,0,0) |
ini = ini + 1 |
end |
for n = ini, exp, 1 do |
r,g,b = findVoid(cube,SHADES) |
mult = 255 / (SHADES - 1) |
setcolor(n, r*mult,g*mult,b*mult) |
addColor2Cube(cube,SHADES,r,g,b) |
end |
end |
/data/common/media/grafx2/scripts/samples_2.4/palette/InvertedRGB.lua |
---|
0,0 → 1,27 |
--PALETTE Modify: Inverted RGB |
--by Richard Fhager |
--http://hem.fyristorg.com/dawnbringer/ |
-- Copyright 2010 Richard Fhager |
-- |
-- 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; version 2 |
-- of the License. See <http://www.gnu.org/licenses/> |
-- This script was adopted from Evalion, a Javascript codecrafting/imageprocessing project |
-- http://goto.glocalnet.net/richard_fhager/evalion/evalion.html |
for c = 0, 255, 1 do |
r,g,b = getcolor(c) |
r2 = (g+b)/2 |
g2 = (r+b)/2 |
b2 = (r+g)/2 |
setcolor(c, r2,g2,b2) |
end |
/data/common/media/grafx2/scripts/samples_2.4/palette/Set3bit.lua |
---|
0,0 → 1,39 |
--PALETTE Set: 3 Bit (8 Primaries) |
--by Richard Fhager |
--http://hem.fyristorg.com/dawnbringer/ |
-- Copyright 2010 Richard Fhager |
-- |
-- 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; version 2 |
-- of the License. See <http://www.gnu.org/licenses/> |
-- Generate palette of all colors possible with a given number of shades for each channel |
-- 2 shades = 1 bit / channel = 3 bit palette = 2^3 colors = 8 colors |
-- 4 shades = 2 bit / channel = 6 bit palette = 2^6 colors = 64 colors |
-- Channel shades (shades = 2 ^ bit-depth) |
shades = 2 |
mult = 255 / (shades-1) |
colors = {} |
col = 0 |
for r = 0, shades-1, 1 do |
for g = 0, shades-1, 1 do |
for b = 0, shades-1, 1 do |
col = col + 1 |
colors[col] = { r*mult, g*mult, b*mult } |
end |
end |
end |
for c = 1, #colors, 1 do |
setcolor(c-1,colors[c][1],colors[c][2],colors[c][3]) |
end |
/data/common/media/grafx2/scripts/samples_2.4/palette/Set6bit.lua |
---|
0,0 → 1,39 |
--PALETTE Set: Full 6 Bit (64 colors) |
--by Richard Fhager |
--http://hem.fyristorg.com/dawnbringer/ |
-- Copyright 2010 Richard Fhager |
-- |
-- 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; version 2 |
-- of the License. See <http://www.gnu.org/licenses/> |
-- Generate palette of all colors possible with a given number of shades for each channel |
-- 2 shades = 1 bit / channel = 3 bit palette = 2^3 colors = 8 colors |
-- 4 shades = 2 bit / channel = 6 bit palette = 2^6 colors = 64 colors |
-- Channel shades (shades = 2 ^ bit-depth) |
shades = 4 |
mult = 255 / (shades-1) |
colors = {} |
col = 0 |
for r = 0, shades-1, 1 do |
for g = 0, shades-1, 1 do |
for b = 0, shades-1, 1 do |
col = col + 1 |
colors[col] = { r*mult, g*mult, b*mult } |
end |
end |
end |
for c = 1, #colors, 1 do |
setcolor(c-1,colors[c][1],colors[c][2],colors[c][3]) |
end |
/data/common/media/grafx2/scripts/samples_2.4/palette/SetC64Palette.lua |
---|
0,0 → 1,50 |
--PALETTE Set: C64 Palette (16 colors) |
--by Richard Fhager |
--http://hem.fyristorg.com/dawnbringer/ |
-- Copyright 2010 Richard Fhager |
-- |
-- 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; version 2 |
-- of the License. See <http://www.gnu.org/licenses/> |
OK,clean = inputbox("C64 Palette:", "Remove old palette", 0, 0,1,0 |
); |
colors = {{0, 0, 0}, -- 0 Black |
{62, 49,162}, -- 1 D.Blue |
{87, 66, 0}, -- 2 Brown |
{140, 62, 52}, -- 3 D.Red |
{84, 84, 84}, -- 4 D.Grey |
{141, 72,179}, -- 5 Purple |
{144, 95, 37}, -- 6 Orange |
{124,112,218}, -- 7 B.Blue |
{128,128,128}, -- 8 Grey |
{104,169, 65}, -- 9 Green |
{187,119,109}, -- 10 B.Red |
{122,191,199}, -- 11 Cyan |
{171,171,171}, -- 12 B.Grey |
{208,220,113}, -- 13 Yellow |
{172,234,136}, -- 14 B.Green |
{255,255,255} -- 15 White |
} |
if OK == true then |
for c = 1, #colors, 1 do |
setcolor(c-1,colors[c][1],colors[c][2],colors[c][3]) |
end |
if clean == 1 then |
for c = #colors+1, 256, 1 do |
setcolor(c-1,0,0,0) |
end |
end |
end |
/data/common/media/grafx2/scripts/samples_2.4/palette/ShiftHue.lua |
---|
0,0 → 1,55 |
--PALETTE Adjust: Shift Hue v0.9 |
--by Richard Fhager |
--http://hem.fyristorg.com/dawnbringer/ |
-- Copyright 2010 Richard Fhager |
-- |
-- 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; version 2 |
-- of the License. See <http://www.gnu.org/licenses/> |
-- This script was adopted from Evalion, a Javascript codecrafting/imageprocessing project |
-- http://goto.glocalnet.net/richard_fhager/evalion/evalion.html |
--Shift_degrees = 45 |
OK,Shift_degrees = inputbox("Shift Hue v0.9","Degrees", 45, 0,360,3); |
-- |
function shiftHUE(r,g,b,deg) -- V1.3 R.Fhager 2007, adopted from Evalion |
local c,h,mi,mx,d,s,p,i,f,q,t |
c = {g,b,r} |
mi = math.min(r,g,b) |
mx = math.max(r,g,b); v = mx; |
d = mx - mi; |
s = 0; if mx ~= 0 then s = d/mx; end |
p = 1; if g ~= mx then p = 2; if b ~= mx then p = 0; end; end |
if s~=0 then |
h=(deg/60+(6+p*2+(c[1+p]-c[1+(p+1)%3])/d))%6; |
i=math.floor(h); |
f=h-i; |
p=v*(1-s); |
q=v*(1-s*f); |
t=v*(1-s*(1-f)); |
c={v,q,p,p,t,v} |
r = c[1+i] |
g = c[1+(i+4)%6] |
b = c[1+(i+2)%6] |
end |
return r,g,b |
end |
-- |
if OK == true then |
for c = 0, 255, 1 do |
r,g,b = getcolor(c) |
setcolor(c, shiftHUE(r,g,b,Shift_degrees)) |
end |
end |
/data/common/media/grafx2/scripts/samples_2.4/picture/CellColourReducer.lua |
---|
0,0 → 1,37 |
-- cell colour reducer - jan'11, from Paulo Silva, with help from people from GrafX2 google group (DawnBringer, Adrien Destugues (PulkoMandy), and Yves Rizoud) |
-- 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; version 2 of the License. See <http://www.gnu.org/licenses/> |
w,h=getpicturesize() |
ok,xcell,ycell=inputbox("Modify cell pixel size","xcell",8,1,16,4,"ycell",8,1,16,4); |
if ok==true then |
function grayscaleindexed(c) |
r,g,b=getcolor(c);return math.floor((b*11+r*30+g*59)/100);end |
celcnt={};for n=0,255,1 do celcnt[n+1]=0;end -- Arraycounter must have initial value |
for y1=0,h-1,ycell do |
for x1=0,w-1,xcell do |
for i=0,255,1 do |
celcnt[i+1]=0;end |
for y2=0,ycell-1,1 do |
for x2=0,xcell-1,1 do |
x=x1+x2;y=y1+y2;u=getpicturepixel(x,y) |
celcnt[u+1]=celcnt[u+1]+(1000*xcell*ycell)+math.random(0,950);end;end |
ikattr=0;paattr=0;ikcnt=0;pacnt=0 |
for i=0,255,1 do |
if ikcnt<celcnt[i+1] then ikcnt=celcnt[i+1];ikattr=i;end;end |
celcnt[ikattr+1]=0 |
for i=0,255,1 do |
if pacnt<celcnt[i+1] then pacnt=celcnt[i+1];paattr=i;end;end |
if grayscaleindexed(ikattr)>grayscaleindexed(paattr) then tmpr=ikattr;ikattr=paattr;paattr=tmpr;end |
wmid=math.floor((grayscaleindexed(paattr)+grayscaleindexed(ikattr))/2) |
for y2=0,ycell-1,1 do |
for x2=0,xcell-1,1 do |
x=x1+x2;y=y1+y2;u=getpicturepixel(x,y) |
if u==ikattr then |
idou=ikattr |
elseif u==paattr then |
idou=paattr |
else |
idou=ikattr |
if grayscaleindexed(u)>wmid then idou=paattr;end |
end |
putpicturepixel(x,y,idou) |
end;end;end;end;end |
/data/common/media/grafx2/scripts/samples_2.4/picture/DrawGridIsometric.lua |
---|
0,0 → 1,13 |
-- Draw isometric grid - Copyright 2010 Paulo Silva |
-- 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; version 2 of the License. See <http://www.gnu.org/licenses/> |
w,h=getpicturesize(); |
ok,gsiz,ik=inputbox("draw isometric grid","size",16,0,128,5,"colour",1,0,255,6); |
if ok==true then |
for y=0,h-1,gsiz do |
for x=0,w-1,1 do |
putpicturepixel(x,y+(x/2)%gsiz,ik); |
end;end |
for y=0,h-1,gsiz do |
for x=0,w-1,1 do |
putpicturepixel(x+((gsiz/2)-1),y+(gsiz-1)-((x/2)%gsiz),ik); |
end;end;end |
/data/common/media/grafx2/scripts/samples_2.4/picture/DrawGridOrthogonal_RGB.lua |
---|
0,0 → 1,14 |
-- draw grid - rgb (matchcolor) - Copyright 2010 Paulo Silva |
-- 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; version 2 of the License. See <http://www.gnu.org/licenses/> |
w,h=getpicturesize() |
ok,xsiz,ysiz,r,g,b=inputbox("draw grid - rgb (matchcolor)","x size",8,1,64,5,"y size",8,1,64,6,"r",128,0,255,6,"g",128,0,255,6,"b",128,0,255,6); |
if ok==true then |
c=matchcolor(r,g,b) |
for y=0,h-1,1 do |
for x=0,w-1,xsiz do |
putpicturepixel(x,y,c); |
end;end |
for y=0,h-1,ysiz do |
for x=0,w-1,1 do |
putpicturepixel(x,y,c); |
end;end;end |
/data/common/media/grafx2/scripts/samples_2.4/picture/DrawgridOrthogonal_Index.lua |
---|
0,0 → 1,11 |
-- draw grid - indexed colour - Copyright 2010 Paulo Silva |
-- 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; version 2 of the License. See <http://www.gnu.org/licenses/> |
w,h=getpicturesize(); |
ok,xsiz,ysiz,c=inputbox("draw grid - indexed colour)","x size",8,1,64,5,"y size",8,1,64,6,"colour id",0,0,255,6); |
if ok==true then |
for y=0,h-1,1 do |
for x=0,w-1,xsiz do |
putpicturepixel(x,y,c);end;end |
for y=0,h-1,ysiz do |
for x=0,w-1,1 do |
putpicturepixel(x,y,c);end;end;end |
/data/common/media/grafx2/scripts/samples_2.4/picture/GlassGridFilter.lua |
---|
0,0 → 1,12 |
-- Glass grid filter - Copyright 2010 Paulo Silva |
-- 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; version 2 of the License. See <http://www.gnu.org/licenses/> |
w,h=getpicturesize(); |
ok,xsiz,ysiz=inputbox("message","xsize",8,0,64,5,"ysize",8,0,64,6); |
if ok==true then |
for y1=0,h-1,xsiz do |
for x1=0,w-1,ysiz do |
for y2=0,(ysiz/2)-1,1 do |
for x2=0,xsiz-1,1 do |
c1=getpicturepixel(x1+x2,y1+y2);c2=getpicturepixel(x1+(xsiz-1)-x2,y1+(ysiz-1)-y2) |
putpicturepixel(x1+x2,y1+y2,c2);putpicturepixel(x1+(xsiz-1)-x2,y1+(ysiz-1)-y2,c1) |
end;end;end;end;end |
/data/common/media/grafx2/scripts/samples_2.4/picture/PaletteToPicture.lua |
---|
0,0 → 1,11 |
-- palette to picture - Copyright 2010 Paulo Silva |
-- 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; version 2 of the License. See <http://www.gnu.org/licenses/> |
w,h=getpicturesize(); |
ok,xsiz,ysiz=inputbox("palette to picture","x size",8,1,16,5,"y size",8,1,16,6); |
if ok==true then |
for y1=0,7,1 do |
for x1=0,31,1 do |
for y2=0,ysiz-1,1 do |
for x2=0,xsiz-1,1 do |
putpicturepixel(x1*xsiz+x2,y1*ysiz+y2,y1+x1*8) |
end;end;end;end;end |
/data/common/media/grafx2/scripts/samples_2.4/picture/Pic2isometric.lua |
---|
0,0 → 1,87 |
--PICTURE (part of): 2 Isometric v0.1b |
--by Richard Fhager |
--http://hem.fyristorg.com/dawnbringer/ |
-- Email: dawnbringer@hem.utfors.se |
-- MSN: annassar@hotmail.com |
-- |
-- Copyright 2010 Richard Fhager |
-- |
-- 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; version 2 |
-- of the License. See <http://www.gnu.org/licenses/> |
-- Color 0 is assumed to be the background |
-- |
iso = {{0, 0, 1, 1, 1, 1, 0, 0}, |
{1, 1, 1, 1, 1, 1, 1, 1}, |
{2, 2, 1, 1, 1, 1, 3, 3}, |
{2, 2, 2, 2, 3, 3, 3, 3}, |
{2, 2, 2, 2, 3, 3, 3, 3}, |
{2, 2, 2, 2, 3, 3, 3, 3}, |
{0, 0, 2, 2, 3, 3, 0, 0}} |
isowidth = 8 |
isoheight = 7 |
xoff = 0.5 |
yoff = 0 |
xstep = 4 |
ystep = 2 |
zstep = 4 |
-- Part of screen from top-left (4 = 1/4) |
xsize = 5 |
ysize = 4 |
w, h = getpicturesize() |
xo = math.floor(w * xoff) |
-- just don't render more than can be fittted right now |
w = math.floor(w / xsize) |
h = math.floor(h / ysize) |
for y = 0, h - 1, 1 do |
for x = 0, w - 1, 1 do |
isox = x * xstep - y * xstep |
isoy = y * ystep + x * ystep |
cb = getbackuppixel(x,y) |
-- |
if cb ~= 0 then |
r,g,b = getbackupcolor(cb); |
c1 = matchcolor(r,g,b); |
c2 = matchcolor(r+64, g+64, b+64); |
c3 = matchcolor(r-64, g-64, b-64); |
cols = {0,c1,c2,c3} |
for iy = 1, isoheight, 1 do |
for ix = 1, isowidth, 1 do |
i = iso[iy][ix] |
c = cols[i+1] |
if i ~= 0 then putpicturepixel(xo + isox+ix-1, isoy+iy-1, c); end |
end |
end |
end |
-- |
end |
end |
/data/common/media/grafx2/scripts/samples_2.4/picture/Rainbow-Dark2Bright.lua |
---|
0,0 → 1,36 |
--PICTURE: Rainbow - Dark to Bright v1.1 |
--by Richard Fhager |
--http://hem.fyristorg.com/dawnbringer/ |
-- Email: dawnbringer@hem.utfors.se |
-- MSN: annassar@hotmail.com |
-- |
--dofile("dawnbringer_lib.lua") |
run("../libs/dawnbringer_lib.lua") |
--> db.shiftHUE(r,g,b, deg) |
w, h = getpicturesize() |
for y = 0, h - 1, 1 do |
for x = 0, w - 1, 1 do |
-- Fractionalize image dimensions |
ox = x / w; |
oy = y / h; |
r = 255 * math.sin(oy * 2) |
g = (oy-0.5)*512 * oy |
b = (oy-0.5)*512 * oy |
r, g, b = db.shiftHUE(r,g,b,ox * 360); |
c = matchcolor(r,g,b) |
putpicturepixel(x, y, c); |
end |
updatescreen(); if (waitbreak(0)==1) then return; end |
end |
/data/common/media/grafx2/scripts/samples_2.4/picture/RemapImage2RGB.lua |
---|
0,0 → 1,50 |
--SCENE: Remap pic to RGB, diag.dith |
--by Richard Fhager |
--http://hem.fyristorg.com/dawnbringer/ |
-- Copyright 2010 Richard Fhager |
-- |
-- 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; version 2 |
-- of the License. See <http://www.gnu.org/licenses/> |
-- Set Palette (to a predefined one) |
colors = {{ 0, 0, 0}, |
{255, 0, 0}, |
{ 0,255, 0}, |
{ 0, 0,255} |
} |
chm = {1,0,0} |
for c = 1, #colors, 1 do |
setcolor(c-1,colors[c][1],colors[c][2],colors[c][3]) |
end |
for c = #colors, 255, 1 do |
setcolor(c,0,0,0) |
end |
w, h = getpicturesize() |
for y = 0, h - 1, 1 do |
for x = 0, w - 1, 1 do |
r,g,b = getbackupcolor(getbackuppixel(x,y)); |
rn = r * chm[1+(y+0+x)%3] |
gn = g * chm[1+(y+1+x)%3] |
bn = b * chm[1+(y+2+x)%3] |
n = matchcolor(rn,gn,bn); |
putpicturepixel(x, y, n); |
end |
end |
/data/common/media/grafx2/scripts/samples_2.4/picture/RemapImage2RGB_ed.lua |
---|
0,0 → 1,69 |
--SCENE: Remap pic 2 RGB, 1lineED-dith. (Same line simple error-diffusion dither) |
--by Richard Fhager |
--http://hem.fyristorg.com/dawnbringer/ |
-- Copyright 2010 Richard Fhager |
-- |
-- 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; version 2 |
-- of the License. See <http://www.gnu.org/licenses/> |
power = 0.615 |
c1 = 0.8 -- Error weight (white is green) |
c2 = 0.2 -- RGB weight (white is r+g+b) |
-- Set Palette (to a predefined one) |
colors = {{ 0, 0, 0}, |
{255, 0, 0}, |
{ 0,255, 0}, |
{ 0, 0,255} |
} |
chm = {1,0,0} |
for c = 1, #colors, 1 do |
setcolor(c-1,colors[c][1],colors[c][2],colors[c][3]) |
end |
for c = #colors, 255, 1 do |
setcolor(c,0,0,0) |
end |
w, h = getpicturesize() |
for y = 0, h - 1, 1 do |
re = 0 |
ge = 0 |
be = 0 |
for x = (y%2), w - 1, 1 do |
r,g,b = getbackupcolor(getbackuppixel(x,y)); |
rn = re * c1 + r * chm[1+(y+0+x)%3] * c2 |
gn = ge * c1 + g * chm[1+(y+1+x)%3] * c2 |
bn = be * c1 + b * chm[1+(y+2+x)%3] * c2 |
n = matchcolor(rn,gn,bn); |
putpicturepixel(x, y, n); |
rn,gn,bn = getcolor(getpicturepixel(x,y)); |
re = (re + (r - rn)) * power |
ge = (ge + (g - gn)) * power |
be = (be + (b - bn)) * power |
end |
end |
/data/common/media/grafx2/scripts/samples_2.4/picture/RemapImageTo3bitPal.lua |
---|
0,0 → 1,80 |
--SCENE: Remap pic to 3bit, LineEDdith. (Same line simple error-diffusion dither) |
--by Richard Fhager |
--http://hem.fyristorg.com/dawnbringer/ |
-- Copyright 2010 Richard Fhager |
-- |
-- 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; version 2 |
-- of the License. See <http://www.gnu.org/licenses/> |
-- |
-- Just a demonstration. |
-- |
power = 0.6 |
-- Channel shades (shades = 2 ^ bit-depth) |
shades = 2 |
mult = 255 / (shades-1) |
colors = {} |
col = 0 |
for r = 0, shades-1, 1 do |
for g = 0, shades-1, 1 do |
for b = 0, shades-1, 1 do |
col = col + 1 |
colors[col] = { r*mult, g*mult, b*mult } |
end |
end |
end |
for c = 1, #colors, 1 do |
setcolor(c-1,colors[c][1],colors[c][2],colors[c][3]) |
end |
for c = #colors, 255, 1 do |
setcolor(c,0,0,0) |
end |
w, h = getpicturesize() |
for y = 0, h - 1, 1 do |
re = 0 |
ge = 0 |
be = 0 |
for x = (y%2), w - 1, 1 do |
r,g,b = getbackupcolor(getbackuppixel(x,y)); |
rn = re + r |
gn = ge + g |
bn = be + b |
n = matchcolor(rn,gn,bn); |
putpicturepixel(x, y, n); |
rn,gn,bn = getcolor(getpicturepixel(x,y)); |
re = (re + (r - rn)) * power |
ge = (ge + (g - gn)) * power |
be = (be + (b - bn)) * power |
end |
end |
/data/common/media/grafx2/scripts/samples_2.4/picture/Tiler.lua |
---|
0,0 → 1,112 |
--Picture Tiler by Adrien Destugues |
--Extract unique tiles from the spare page |
--to the main one. Main page is erased. |
-- |
-- Copyright 2011 Adrien Destugues <pulkomandy@pulkomandy.ath.cx> |
-- |
-- 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; version 2 |
-- of the License. See <http://www.gnu.org/licenses/> |
-- Copy palette from spare to main |
-- TODO |
-- Grid size |
-- TODO : get it from GrafX2 |
xgrid = 16; |
ygrid = 16; |
-- picture size |
w, h = getpicturesize(); |
-- We may need less if there are duplicates |
setsparepicturesize(xgrid, w*h/xgrid); |
tileid = 0; |
-- blit part of the spare to picture |
function blitpicturetospare(srcx, srcy, dstx, dsty, width, height) |
local x,y; |
for y = 0, height - 1, 1 do |
for x = 0, width - 1, 1 do |
putsparepicturepixel(dstx+x, dsty+y, getpicturepixel(srcx + x, srcy + y)); |
end |
end |
end |
function comparesparewithpicture(srcx, srcy, dstx, dsty, width, height) |
local x,y,color |
for y = 0, height - 1, 1 do |
for x = 0, width - 1, 1 do |
color = getsparepicturepixel(srcx + x, srcy + y); |
if color ~= getpicturepixel(dstx+x, dsty+y) then |
-- they are different |
return false; |
end |
end |
end |
-- they are identical |
return true; |
end |
-- compute checksum of a picture area |
-- it may not be unique, we use it as a key for an hashmap |
function checksum(srcx, srcy, width, height) |
local sum,x,y |
sum = 0; |
for y = 0, height - 1, 1 do |
for x = 0, width - 1, 1 do |
sum = sum + getpicturepixel(srcx+x, srcy+y); |
end |
end |
return sum; |
end |
tilemap = {} |
-- foreach tile |
for y = 0, h-1, ygrid do |
for x = 0, w - 1, xgrid do |
-- existing one ? |
csum = checksum(x,y,xgrid,ygrid); |
if tilemap[csum] ~= nil then |
-- potential match |
-- Find matching tileid |
found = false; |
for id in pairs(tilemap[csum]) do |
-- is it a match ? |
if comparesparewithpicture(x,y,0,id*ygrid, xgrid, ygrid) then |
-- found it ! |
tilemap[csum][id] = tilemap[csum][id] + 1; |
found = true; |
break; |
end |
end |
-- Add tile anyway if needed |
if not found then |
desty = tileid * ygrid; |
blitpicturetospare(x, y, 0, desty, xgrid, ygrid); |
-- add it to the tilemap |
tilemap[csum][tileid] = 1; |
-- give it a tile id |
tileid = tileid + 1; |
end |
else |
-- Copy to spare |
desty = tileid * ygrid; |
blitpicturetospare(x, y, 0, desty, xgrid, ygrid); |
-- add it to the tilemap |
tilemap[csum] = {} |
tilemap[csum][tileid] = 1; |
-- give it a tile id |
tileid = tileid + 1; |
end |
end |
end |
setsparepicturesize(xgrid, (tileid-1)*ygrid) |
--updatescreen(); |
/data/common/media/grafx2/scripts/samples_2.4/picture/XBitColourXpaceFromPalette.lua |
---|
0,0 → 1,12 |
-- Copyright 2010 Paulo Silva |
-- 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; version 2 of the License. See <http://www.gnu.org/licenses/> |
w,h=getpicturesize(); |
ok,bitd=inputbox("colourspace from palette","bitdepth:",4,1,8,5); |
if ok==true then |
bitd3=(2^bitd);bitd8=(2^(math.floor(bitd/2)));bitd9=(2^((math.floor((bitd-1)/2))+1)) |
for y1=0,(bitd8-1),1 do |
for x1=0,(bitd9-1),1 do |
for y2=0,(bitd3-1),1 do |
for x2=0,(bitd3-1),1 do |
putpicturepixel(x1*bitd3+x2,y1*bitd3+y2,matchcolor((y2*255)/(bitd3-1),((y1*8+x1)*255)/(bitd3-1),(x2*255)/(bitd3-1))) |
end;end;end;end;end |
/data/common/media/grafx2/skins/font_Classic.png |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
Property changes: |
Added: svn:mime-type |
+application/octet-stream |
\ No newline at end of property |
/data/common/media/grafx2/skins/font_DPaint.png |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
Property changes: |
Added: svn:mime-type |
+application/octet-stream |
\ No newline at end of property |
/data/common/media/grafx2/skins/font_Fairlight.png |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
Property changes: |
Added: svn:mime-type |
+application/octet-stream |
\ No newline at end of property |
/data/common/media/grafx2/skins/font_Fun.png |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
Property changes: |
Added: svn:mime-type |
+application/octet-stream |
\ No newline at end of property |
/data/common/media/grafx2/skins/font_Melon.png |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
Property changes: |
Added: svn:mime-type |
+application/octet-stream |
\ No newline at end of property |
/data/common/media/grafx2/skins/font_Seen.png |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
Property changes: |
Added: svn:mime-type |
+application/octet-stream |
\ No newline at end of property |
/data/common/media/grafx2/skins/skin_Aurora.png |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
Property changes: |
Added: svn:mime-type |
+application/octet-stream |
\ No newline at end of property |
/data/common/media/grafx2/skins/skin_Clax2.gif |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
Property changes: |
Added: svn:mime-type |
+application/octet-stream |
\ No newline at end of property |
/data/common/media/grafx2/skins/skin_Clax3.gif |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
Property changes: |
Added: svn:mime-type |
+application/octet-stream |
\ No newline at end of property |
/data/common/media/grafx2/skins/skin_Clax4.gif |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
Property changes: |
Added: svn:mime-type |
+application/octet-stream |
\ No newline at end of property |
/data/common/media/grafx2/skins/skin_DPaint.png |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
Property changes: |
Added: svn:mime-type |
+application/octet-stream |
\ No newline at end of property |
/data/common/media/grafx2/skins/skin_classic.png |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
Property changes: |
Added: svn:mime-type |
+application/octet-stream |
\ No newline at end of property |
/data/common/media/grafx2/skins/skin_modern.png |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
Property changes: |
Added: svn:mime-type |
+application/octet-stream |
\ No newline at end of property |
/data/common/media/grafx2/skins/skin_scenish.png |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
Property changes: |
Added: svn:mime-type |
+application/octet-stream |
\ No newline at end of property |