samples_2.4 => samples
This commit is contained in:
committed by
Adrien Destugues
parent
428235636a
commit
0a38b78a9c
129
share/grafx2/scripts/samples/brush/ApplyColor.lua
Normal file
129
share/grafx2/scripts/samples/brush/ApplyColor.lua
Normal file
@@ -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
|
||||
31
share/grafx2/scripts/samples/brush/Fisheye.lua
Normal file
31
share/grafx2/scripts/samples/brush/Fisheye.lua
Normal file
@@ -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
|
||||
|
||||
24
share/grafx2/scripts/samples/brush/GrayscaleAvg.lua
Normal file
24
share/grafx2/scripts/samples/brush/GrayscaleAvg.lua
Normal file
@@ -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
|
||||
36
share/grafx2/scripts/samples/brush/GrayscaleDesat.lua
Normal file
36
share/grafx2/scripts/samples/brush/GrayscaleDesat.lua
Normal file
@@ -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
|
||||
34
share/grafx2/scripts/samples/brush/Halfsmooth.lua
Normal file
34
share/grafx2/scripts/samples/brush/Halfsmooth.lua
Normal file
@@ -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
|
||||
|
||||
|
||||
42
share/grafx2/scripts/samples/brush/Waves.lua
Normal file
42
share/grafx2/scripts/samples/brush/Waves.lua
Normal file
@@ -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
|
||||
|
||||
17
share/grafx2/scripts/samples/codenetsend.lua
Normal file
17
share/grafx2/scripts/samples/codenetsend.lua
Normal file
@@ -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
|
||||
460
share/grafx2/scripts/samples/demo/3DPalette.lua
Normal file
460
share/grafx2/scripts/samples/demo/3DPalette.lua
Normal file
@@ -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
|
||||
68
share/grafx2/scripts/samples/demo/Ellipse.lua
Normal file
68
share/grafx2/scripts/samples/demo/Ellipse.lua
Normal file
@@ -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
|
||||
17
share/grafx2/scripts/samples/demo/FlipPicture.lua
Normal file
17
share/grafx2/scripts/samples/demo/FlipPicture.lua
Normal file
@@ -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
|
||||
59
share/grafx2/scripts/samples/demo/SierpinskyCarpet.lua
Normal file
59
share/grafx2/scripts/samples/demo/SierpinskyCarpet.lua
Normal file
@@ -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
|
||||
|
||||
57
share/grafx2/scripts/samples/demo/SierpinskyTriangle.lua
Normal file
57
share/grafx2/scripts/samples/demo/SierpinskyTriangle.lua
Normal file
@@ -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
|
||||
|
||||
45
share/grafx2/scripts/samples/demo/Spritesheet.lua
Normal file
45
share/grafx2/scripts/samples/demo/Spritesheet.lua
Normal file
@@ -0,0 +1,45 @@
|
||||
--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
|
||||
57
share/grafx2/scripts/samples/demo/brush/Amigaball.lua
Normal file
57
share/grafx2/scripts/samples/demo/brush/Amigaball.lua
Normal file
@@ -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
|
||||
38
share/grafx2/scripts/samples/demo/brush/ColorSphere.lua
Normal file
38
share/grafx2/scripts/samples/demo/brush/ColorSphere.lua
Normal file
@@ -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
|
||||
100
share/grafx2/scripts/samples/demo/brush/FindAA.lua
Normal file
100
share/grafx2/scripts/samples/demo/brush/FindAA.lua
Normal file
@@ -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
|
||||
|
||||
|
||||
64
share/grafx2/scripts/samples/demo/brush/Mandelbrot.lua
Normal file
64
share/grafx2/scripts/samples/demo/brush/Mandelbrot.lua
Normal file
@@ -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
|
||||
3720
share/grafx2/scripts/samples/libs/dawnbringer_lib.lua
Normal file
3720
share/grafx2/scripts/samples/libs/dawnbringer_lib.lua
Normal file
File diff suppressed because it is too large
Load Diff
138
share/grafx2/scripts/samples/libs/memory.lua
Normal file
138
share/grafx2/scripts/samples/libs/memory.lua
Normal file
@@ -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
|
||||
40
share/grafx2/scripts/samples/palette/Desaturate.lua
Normal file
40
share/grafx2/scripts/samples/palette/Desaturate.lua
Normal file
@@ -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
|
||||
171
share/grafx2/scripts/samples/palette/ExpandColors.lua
Normal file
171
share/grafx2/scripts/samples/palette/ExpandColors.lua
Normal file
@@ -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
|
||||
|
||||
|
||||
|
||||
105
share/grafx2/scripts/samples/palette/FillColorCube.lua
Normal file
105
share/grafx2/scripts/samples/palette/FillColorCube.lua
Normal file
@@ -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
|
||||
|
||||
|
||||
|
||||
27
share/grafx2/scripts/samples/palette/InvertedRGB.lua
Normal file
27
share/grafx2/scripts/samples/palette/InvertedRGB.lua
Normal file
@@ -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
|
||||
39
share/grafx2/scripts/samples/palette/Set3bit.lua
Normal file
39
share/grafx2/scripts/samples/palette/Set3bit.lua
Normal file
@@ -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
|
||||
39
share/grafx2/scripts/samples/palette/Set6bit.lua
Normal file
39
share/grafx2/scripts/samples/palette/Set6bit.lua
Normal file
@@ -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
|
||||
50
share/grafx2/scripts/samples/palette/SetC64Palette.lua
Normal file
50
share/grafx2/scripts/samples/palette/SetC64Palette.lua
Normal file
@@ -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
|
||||
55
share/grafx2/scripts/samples/palette/ShiftHue.lua
Normal file
55
share/grafx2/scripts/samples/palette/ShiftHue.lua
Normal file
@@ -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
|
||||
37
share/grafx2/scripts/samples/picture/CellColourReducer.lua
Normal file
37
share/grafx2/scripts/samples/picture/CellColourReducer.lua
Normal file
@@ -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
|
||||
13
share/grafx2/scripts/samples/picture/DrawGridIsometric.lua
Normal file
13
share/grafx2/scripts/samples/picture/DrawGridIsometric.lua
Normal file
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
26
share/grafx2/scripts/samples/picture/FontConvert.lua
Normal file
26
share/grafx2/scripts/samples/picture/FontConvert.lua
Normal file
@@ -0,0 +1,26 @@
|
||||
--Font Extractor by Adrien Destugues
|
||||
--Cut the picture in characters and save them
|
||||
--to a binary file
|
||||
--
|
||||
--Copyright 2013, Adrien Destugues <pulkomandy@pulkomandy.tk>
|
||||
--
|
||||
--this file is distributed under the terms of the MIT licence
|
||||
|
||||
w,h = getpicturesize();
|
||||
|
||||
f = io.open("file.bin","w")
|
||||
|
||||
for y = 0, h-1, 8 do
|
||||
for x = 0, w-1, 8 do
|
||||
for y2 = 0, 7, 1 do
|
||||
word = 0;
|
||||
for x2 = 0,7,1 do
|
||||
word = word * 2 + getpicturepixel(x+x2,y+y2);
|
||||
-- read one word from the current line
|
||||
end
|
||||
f:write(string.char(word));
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
f:close()
|
||||
12
share/grafx2/scripts/samples/picture/GlassGridFilter.lua
Normal file
12
share/grafx2/scripts/samples/picture/GlassGridFilter.lua
Normal file
@@ -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
|
||||
11
share/grafx2/scripts/samples/picture/PaletteToPicture.lua
Normal file
11
share/grafx2/scripts/samples/picture/PaletteToPicture.lua
Normal file
@@ -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
|
||||
87
share/grafx2/scripts/samples/picture/Pic2isometric.lua
Normal file
87
share/grafx2/scripts/samples/picture/Pic2isometric.lua
Normal file
@@ -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
|
||||
|
||||
|
||||
|
||||
|
||||
36
share/grafx2/scripts/samples/picture/Rainbow-Dark2Bright.lua
Normal file
36
share/grafx2/scripts/samples/picture/Rainbow-Dark2Bright.lua
Normal file
@@ -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
|
||||
|
||||
|
||||
50
share/grafx2/scripts/samples/picture/RemapImage2RGB.lua
Normal file
50
share/grafx2/scripts/samples/picture/RemapImage2RGB.lua
Normal file
@@ -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
|
||||
69
share/grafx2/scripts/samples/picture/RemapImage2RGB_ed.lua
Normal file
69
share/grafx2/scripts/samples/picture/RemapImage2RGB_ed.lua
Normal file
@@ -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
|
||||
80
share/grafx2/scripts/samples/picture/RemapImageTo3bitPal.lua
Normal file
80
share/grafx2/scripts/samples/picture/RemapImageTo3bitPal.lua
Normal file
@@ -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
|
||||
34
share/grafx2/scripts/samples/picture/ThomsonConstraints.lua
Normal file
34
share/grafx2/scripts/samples/picture/ThomsonConstraints.lua
Normal file
@@ -0,0 +1,34 @@
|
||||
-- Thomson Constraints checker
|
||||
-- Check wether picture is compatible with Thomson computers video modes
|
||||
-- (8x1 cells with 2 colors out of 16 in each cell)
|
||||
|
||||
w,h=getpicturesize()
|
||||
xcell = 8
|
||||
|
||||
selectlayer(1)
|
||||
clearpicture(0)
|
||||
selectlayer(0)
|
||||
-- foreach grid cell
|
||||
for y=0,h-1,1 do
|
||||
for x1=0,w-1,xcell do
|
||||
-- initialize our two colors for the cell, c1 is the color of the first
|
||||
-- pixel, and we will look for c2 in the following pixels
|
||||
c1 = getpicturepixel(x1,y)
|
||||
c2 = -1
|
||||
for x2=0,xcell-1,1 do
|
||||
c = getpicturepixel(x1+x2, y)
|
||||
-- is it a new color ?
|
||||
if c ~= c1 and c ~= c2 then
|
||||
if c2 == -1 then
|
||||
-- C2 is free, we can use it for this new color
|
||||
c2 = c
|
||||
else
|
||||
-- out of colors !
|
||||
selectlayer(1)
|
||||
putpicturepixel(x1+x2,y,17);
|
||||
selectlayer(0)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
112
share/grafx2/scripts/samples/picture/Tiler.lua
Normal file
112
share/grafx2/scripts/samples/picture/Tiler.lua
Normal file
@@ -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.tk>
|
||||
--
|
||||
-- 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();
|
||||
@@ -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
|
||||
@@ -0,0 +1,141 @@
|
||||
-- ostro_zx.lua : converts a color image into a
|
||||
-- ZX-like image (8+8 fixed colors with color clash)
|
||||
-- using Ostromoukhov's error diffusion algorithm.
|
||||
--
|
||||
-- Version: 03/21/2017
|
||||
--
|
||||
-- Copyright 2016-2017 by Samuel Devulder
|
||||
--
|
||||
-- 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('../../thomson/lib/ostromoukhov.lua')
|
||||
|
||||
-- get screen size
|
||||
local screen_w, screen_h = getpicturesize()
|
||||
|
||||
OtherDither = {}
|
||||
function OtherDither:new(a)
|
||||
local o = { -- default ZX values
|
||||
-- width of the screen
|
||||
width=a and a.width or 256,
|
||||
-- height of the screen
|
||||
height=a and a.height or 192,
|
||||
-- size of Nx1 clash size
|
||||
clash_size=a and a.clash_size or 8,
|
||||
-- normalize the picture levels (like in imagemagick)
|
||||
normalize=a and a.normalize or 0.005,
|
||||
-- put a pixel
|
||||
pset=a and a.pset or function(self,x,y,c)
|
||||
if c<0 then c=-c-1 end
|
||||
self.screen[x+y*self.width] = c
|
||||
end,
|
||||
-- init gfx data
|
||||
setGfx=a and a.setGfx or function(self)
|
||||
self.screen={}
|
||||
end,
|
||||
-- update gfx to screen
|
||||
updatescreen=a and a.updatescreen or function(self)
|
||||
for i=0,255 do setcolor(i,0,0,0) end
|
||||
for y=0,self.height-1 do
|
||||
for x=0,self.width-1 do
|
||||
putpicturepixel(x,y,self.screen[x+y*self.width] or 0)
|
||||
end
|
||||
end
|
||||
-- refresh palette
|
||||
for i,v in ipairs(self.pal) do
|
||||
local r=v % 16
|
||||
local g=math.floor(v/16) % 16
|
||||
local b=math.floor(v/256) % 16
|
||||
setcolor(i+thomson._palette.offset-1,
|
||||
thomson.levels.pc[r+1],
|
||||
thomson.levels.pc[g+1],
|
||||
thomson.levels.pc[b+1])
|
||||
end
|
||||
updatescreen()
|
||||
end,
|
||||
-- palette with thomson ordering (to use thomson's
|
||||
-- lib support)
|
||||
pal= a and a.pal or {
|
||||
0x000,0xF00,0x00F,0xF0F,0x0F0,0xFF0,0x0FF,0xFFF,
|
||||
0x000,0x200,0x002,0x202,0x020,0x220,0x022,0x222
|
||||
}
|
||||
}
|
||||
setmetatable(o, self)
|
||||
self.__index = self
|
||||
return o
|
||||
end
|
||||
|
||||
-- Converts ZX coordinates (0-255,0-191) into screen coordinates
|
||||
function OtherDither:to_screen(x,y)
|
||||
local i,j;
|
||||
if screen_w/screen_h < self.width/self.height then
|
||||
i = x*screen_h/self.height
|
||||
j = y*screen_h/self.height
|
||||
else
|
||||
i = x*screen_w/self.width
|
||||
j = y*screen_w/self.width
|
||||
end
|
||||
return math.floor(i), math.floor(j)
|
||||
end
|
||||
|
||||
-- return the Color @(x,y) in linear space (0-255)
|
||||
-- corresonding to the other platform screen
|
||||
OtherDither._getLinearPixel = {} -- cache
|
||||
function OtherDither:getLinearPixel(x,y)
|
||||
local k=x+y*self.width
|
||||
local p = self._getLinearPixel and self._getLinearPixel[k]
|
||||
if not p then
|
||||
local x1,y1 = self:to_screen(x,y)
|
||||
local x2,y2 = self:to_screen(x+1,y+1)
|
||||
if x2==x1 then x2=x1+1 end
|
||||
if y2==y1 then y2=y1+1 end
|
||||
|
||||
p = Color:new(0,0,0)
|
||||
for j=y1,y2-1 do
|
||||
for i=x1,x2-1 do
|
||||
p:add(getLinearPictureColor(i,j))
|
||||
end
|
||||
end
|
||||
p:div((y2-y1)*(x2-x1)) --:floor()
|
||||
|
||||
if self._getLinearPixel then
|
||||
self._getLinearPixel[k]=p
|
||||
end
|
||||
end
|
||||
|
||||
return self._getLinearPixel and p:clone() or p
|
||||
end
|
||||
|
||||
function OtherDither:ccAcceptCouple(c1,c2)
|
||||
-- bright colors can't mix with dimmed ones
|
||||
return c1~=c2 and ((c1<=8 and c2<=8) or (c1>8 and c2>8))
|
||||
end
|
||||
|
||||
function OtherDither:dither()
|
||||
local NORMALIZE=Color.NORMALIZE
|
||||
Color.NORMALIZE=self.normalize
|
||||
|
||||
local dither=OstroDither:new(self.pal)
|
||||
dither.ccAcceptCouple = function(dither,c1,c2) return self:ccAcceptCouple(c1,c2) end
|
||||
dither.clash_size = self.clash_size
|
||||
dither.attenuation = .9
|
||||
|
||||
self:setGfx()
|
||||
dither:ccDither(self.width,self.height,
|
||||
function(x,y) return self:getLinearPixel(x,y) end,
|
||||
function(x,y,c) self:pset(x,y,c) end,
|
||||
true,
|
||||
function(y)
|
||||
thomson.info("Converting...",
|
||||
math.floor(y*100/self.height),"%")
|
||||
end,true)
|
||||
-- refresh screen
|
||||
setpicturesize(self.width,self.height)
|
||||
self:updatescreen()
|
||||
finalizepicture()
|
||||
Color.NORMALIZE=NORMALIZE
|
||||
end
|
||||
@@ -0,0 +1,27 @@
|
||||
-- ostro_zx.lua : converts a color image into a
|
||||
-- Oric image (8+8 fixed colors with color clash)
|
||||
-- using Ostromoukhov's error diffusion algorithm.
|
||||
--
|
||||
-- Version: 03/21/2017
|
||||
--
|
||||
-- Copyright 2016-2017 by Samuel Devulder
|
||||
--
|
||||
-- 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('lib/ostro_other.lua')
|
||||
|
||||
OtherDither:new{
|
||||
width=240,
|
||||
height=200,
|
||||
clash_size=6,
|
||||
pal={0x000,0x00F,0x0F0,0x0FF,0xF00,0xF0F,0xFF0,0xFFF},
|
||||
pset=function(self,x,y,c)
|
||||
if x<6 then c=0 end
|
||||
if c<0 then c=-c-1 end
|
||||
self.screen[x+y*self.width] = c
|
||||
end
|
||||
}:dither()
|
||||
@@ -0,0 +1,17 @@
|
||||
-- ostro_zx.lua : converts a color image into a
|
||||
-- ZX image (8+8 fixed colors with color clash)
|
||||
-- using Ostromoukhov's error diffusion algorithm.
|
||||
--
|
||||
-- Version: 03/21/2017
|
||||
--
|
||||
-- Copyright 2016-2017 by Samuel Devulder
|
||||
--
|
||||
-- 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('lib/ostro_other.lua')
|
||||
|
||||
OtherDither:new{width=256,height=192,clash_size=8}:dither()
|
||||
219
share/grafx2/scripts/samples/picture/thomson/bayer4_mo5.lua
Normal file
219
share/grafx2/scripts/samples/picture/thomson/bayer4_mo5.lua
Normal file
@@ -0,0 +1,219 @@
|
||||
-- bayer4_mo5.lua : converts an image into TO7/70-MO5
|
||||
-- mode for thomson machines (MO6,TO8,TO9,TO9+)
|
||||
-- using special bayer matrix that fits well with
|
||||
-- color clashes.
|
||||
--
|
||||
-- Version: 02-jan-2017
|
||||
--
|
||||
-- Copyright 2016-2017 by Samuel Devulder
|
||||
--
|
||||
-- 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/>
|
||||
|
||||
-- get screen size
|
||||
local screen_w, screen_h = getpicturesize()
|
||||
|
||||
run("lib/thomson.lua")
|
||||
run("lib/color.lua")
|
||||
run("lib/bayer.lua")
|
||||
|
||||
-- Converts thomson coordinates (0-319,0-199) into screen coordinates
|
||||
local function thom2screen(x,y)
|
||||
local i,j;
|
||||
if screen_w/screen_h < 1.6 then
|
||||
i = x*screen_h/200
|
||||
j = y*screen_h/200
|
||||
else
|
||||
i = x*screen_w/320
|
||||
j = y*screen_w/320
|
||||
end
|
||||
return math.floor(i), math.floor(j)
|
||||
end
|
||||
|
||||
-- return the pixel @(x,y) in normalized linear space (0-1)
|
||||
-- corresonding to the thomson screen (x in 0-319, y in 0-199)
|
||||
local function getLinearPixel(x,y)
|
||||
local x1,y1 = thom2screen(x,y)
|
||||
local x2,y2 = thom2screen(x+1,y+1)
|
||||
if x2==x1 then x2=x1+1 end
|
||||
if y2==y1 then y2=y1+1 end
|
||||
|
||||
local p,i,j = Color:new(0,0,0);
|
||||
for i=x1,x2-1 do
|
||||
for j=y1,y2-1 do
|
||||
p:add(getLinearPictureColor(i,j))
|
||||
end
|
||||
end
|
||||
p:div((y2-y1)*(x2-x1)*Color.ONE)
|
||||
|
||||
return p
|
||||
end
|
||||
|
||||
local dither = bayer.norm(bayer.double(bayer.double({{1,2},{3,4}})))
|
||||
local dx,dy=#dither,#dither[1]
|
||||
|
||||
-- get thomson palette pixel (linear, 0-1 range)
|
||||
local linearPalette = {}
|
||||
function linearPalette.get(i)
|
||||
local p = linearPalette[i]
|
||||
if not p then
|
||||
local pal = thomson.palette(i-1)
|
||||
local b=math.floor(pal/256)
|
||||
local g=math.floor(pal/16)%16
|
||||
local r=pal%16
|
||||
p = Color:new(thomson.levels.linear[r+1],
|
||||
thomson.levels.linear[g+1],
|
||||
thomson.levels.linear[b+1]):div(Color.ONE)
|
||||
linearPalette[i] = p
|
||||
end
|
||||
return p:clone()
|
||||
end
|
||||
|
||||
-- distance between two colors
|
||||
local distance = {}
|
||||
function distance.between(c1,c2)
|
||||
local k = c1..','..c2
|
||||
local d = distance[k]
|
||||
if false and not d then
|
||||
d = linearPalette.get(c1):euclid_dist2(linearPalette.get(c2))
|
||||
distance[k] = d
|
||||
end
|
||||
if not d then
|
||||
local x = linearPalette.get(c1):sub(linearPalette.get(c2))
|
||||
local c,c1,c2,c3=1.8,8,11,8
|
||||
local f = function(c,x) return math.abs(x)*c end
|
||||
d = f(c1,x.r)^c + f(c2,x.g)^c + f(c3,x.b)^c
|
||||
distance[k] = d
|
||||
end
|
||||
return d
|
||||
end
|
||||
|
||||
-- compute a set of best couples for a given histogram
|
||||
local best_couple = {n=0}
|
||||
function best_couple.get(h)
|
||||
local k = (((h[1]or 0)*8+(h[2]or 0))*8+(h[3]or 0))*8+(h[4]or 0)
|
||||
.. ',' .. (((h[5]or 0)*8+(h[6]or 0))*8+(h[7]or 0))*8+(h[8]or 0)
|
||||
local best_found = best_couple[k]
|
||||
if not best_found then
|
||||
local dm=1000000
|
||||
for i=1,15 do
|
||||
for j=i+1,16 do
|
||||
local d=0
|
||||
for p,n in pairs(h) do
|
||||
local d1,d2=distance.between(p,i),distance.between(p,j)
|
||||
d = d + n*(d1<d2 and d1 or d2)
|
||||
if d>dm then break; end
|
||||
end
|
||||
if d< dm then dm,best_found=d,{} end
|
||||
if d<=dm then table.insert(best_found, {c1=i,c2=j}) end
|
||||
end
|
||||
end
|
||||
|
||||
if best_couple.n>10000 then
|
||||
-- keep memory usage low
|
||||
best_couple = {n=0, get=best_couple.get}
|
||||
end
|
||||
best_couple[k] = best_found
|
||||
best_couple.n = best_couple.n+1
|
||||
end
|
||||
return best_found
|
||||
end
|
||||
|
||||
-- TO7/70 MO5 mode
|
||||
thomson.setMO5()
|
||||
|
||||
-- convert picture
|
||||
local err1,err2 = {},{}
|
||||
local coefs = {0,0.6,0}
|
||||
for x=-1,320 do
|
||||
err1[x] = Color:new(0,0,0)
|
||||
err2[x] = Color:new(0,0,0)
|
||||
end
|
||||
for y = 0,199 do
|
||||
err1,err2 = err2,err1
|
||||
for x=-1,320 do err2[x]:mul(0) end
|
||||
|
||||
for x = 0,319,8 do
|
||||
local h,q = {},{} -- histo, expected color
|
||||
for z=x,x+7 do
|
||||
local d=dither[1+(y%dx)][1+(z%dx)]
|
||||
local p=getLinearPixel(z,y):add(err1[z])
|
||||
local c=((p.r>d) and 1 or 0) +
|
||||
((p.g>d) and 2 or 0) +
|
||||
((p.b>d) and 4 or 0) + 1 -- theorical color
|
||||
|
||||
table.insert(q,c)
|
||||
h[c] = (h[c] or 0)+1
|
||||
end
|
||||
|
||||
local c1,c2
|
||||
for c,_ in pairs(h) do
|
||||
if c1==nil then c1=c
|
||||
elseif c2==nil then c2=c
|
||||
else c1=nil; break; end
|
||||
end
|
||||
if c1~=nil then
|
||||
c2 = c2 or c1
|
||||
else
|
||||
-- get best possible couples of colors
|
||||
local best_found = best_couple.get(h)
|
||||
if #best_found==1 then
|
||||
c1,c2 = best_found[1].c1,best_found[1].c2
|
||||
else
|
||||
-- keep the best of the best depending on max solvable color clashes
|
||||
function clamp(v) return v<0 and -v or v>1 and v-1 or 0 end
|
||||
local dm=10000000
|
||||
for _,couple in ipairs(best_found) do
|
||||
local d=0
|
||||
for k=1,8 do
|
||||
local q=q[k]
|
||||
local p=distance.between(q,couple.c1)<distance.between(q,couple.c2) and couple.c1 or couple.c2
|
||||
-- error between expected and best
|
||||
local e=linearPalette.get(q):sub(linearPalette.get(p)):mul(coefs[1])
|
||||
local z=getLinearPixel(x+k-1,y+1):add(e)
|
||||
d = d + clamp(z.r) + clamp(z.g) + clamp(z.b)
|
||||
end
|
||||
if d<=dm then dm,c1,c2=d,couple.c1,couple.c2 end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- thomson.pset(x,y,c1-1)
|
||||
-- thomson.pset(x,y,-c2)
|
||||
|
||||
for k=0,7 do
|
||||
local z=x+k
|
||||
local q=q[k+1]
|
||||
local p=distance.between(q,c1)<distance.between(q,c2) and c1 or c2
|
||||
local d=linearPalette.get(q):sub(linearPalette.get(p))
|
||||
err2[z]:add(d:mul(coefs[1]))
|
||||
|
||||
thomson.pset(z,y,p==c1 and c1-1 or -c2)
|
||||
end
|
||||
end
|
||||
thomson.info("Converting...",math.floor(y/2),"%")
|
||||
end
|
||||
|
||||
-- refresh screen
|
||||
setpicturesize(320,200)
|
||||
thomson.updatescreen()
|
||||
finalizepicture()
|
||||
|
||||
-- save picture
|
||||
do
|
||||
local function exist(file)
|
||||
local f=io.open(file,'rb')
|
||||
if not f then return false else io.close(f); return true; end
|
||||
end
|
||||
local name,path = getfilename()
|
||||
local mapname = string.gsub(name,"%.%w*$","") .. ".map"
|
||||
local fullname = path .. '/' .. mapname
|
||||
local ok = not exist(fullname)
|
||||
if not ok then
|
||||
selectbox("Ovr " .. mapname .. "?", "Yes", function() ok = true; end, "No", function() ok = false; end)
|
||||
end
|
||||
if ok then thomson.savep(fullname) end
|
||||
end
|
||||
299
share/grafx2/scripts/samples/picture/thomson/bayer4_to8.lua
Normal file
299
share/grafx2/scripts/samples/picture/thomson/bayer4_to8.lua
Normal file
@@ -0,0 +1,299 @@
|
||||
-- bayer4_to8.lua : converts an image into BM16
|
||||
-- mode for thomson machines (MO6,TO8,TO9,TO9+)
|
||||
-- using bayer matrix and a special palette.
|
||||
--
|
||||
-- Version: 02-jan-2017
|
||||
--
|
||||
-- Copyright 2016-2017 by Samuel Devulder
|
||||
--
|
||||
-- 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 is my first code in lua, so excuse any bad
|
||||
-- coding practice.
|
||||
|
||||
-- use a zig zag. If false (recommended value), this gives
|
||||
-- a raster look and feel
|
||||
local with_zig_zag = with_zig_zag or false
|
||||
|
||||
-- debug: displays histograms
|
||||
local debug = false
|
||||
|
||||
-- enhance luminosity since our mode divide it by two
|
||||
local enhance_lum = enhance_lum or true
|
||||
|
||||
-- use fixed levels (default=false, give better result)
|
||||
local fixed_levels = fixed_levels or false
|
||||
|
||||
-- use void-and-cluster 8x8 matrix (default=false)
|
||||
local use_vac = use_vac or false
|
||||
|
||||
-- get screen size
|
||||
local screen_w, screen_h = getpicturesize()
|
||||
|
||||
run("lib/thomson.lua")
|
||||
run("lib/color.lua")
|
||||
run("lib/bayer.lua")
|
||||
|
||||
-- Converts thomson coordinates (0-159,0-99) into screen coordinates
|
||||
local function thom2screen(x,y)
|
||||
local i,j;
|
||||
if screen_w/screen_h < 1.6 then
|
||||
i = x*screen_h/100
|
||||
j = y*screen_h/100
|
||||
else
|
||||
i = x*screen_w/160
|
||||
j = y*screen_w/160
|
||||
end
|
||||
return math.floor(i), math.floor(j)
|
||||
end
|
||||
|
||||
-- return the pixel @(x,y) in linear space corresonding to the thomson screen (x in 0-159, y in 0-99)
|
||||
local function getLinearPixel(x,y)
|
||||
local x1,y1 = thom2screen(x,y)
|
||||
local x2,y2 = thom2screen(x+1,y+1)
|
||||
if x2==x1 then x2=x1+1 end
|
||||
if y2==y1 then y2=y1+1 end
|
||||
|
||||
local p,i,j = Color:new(0,0,0);
|
||||
for i=x1,x2-1 do
|
||||
for j=y1,y2-1 do
|
||||
p:add(getLinearPictureColor(i,j))
|
||||
end
|
||||
end
|
||||
|
||||
return p:div((y2-y1)*(x2-x1)):floor()
|
||||
end
|
||||
|
||||
--[[ make a bayer matrix
|
||||
function bayer(matrix)
|
||||
local m,n=#matrix,#matrix[1]
|
||||
local r,i,j = {}
|
||||
for j=1,m*2 do
|
||||
local t = {}
|
||||
for i=1,n*2 do t[i]=0; end
|
||||
r[j] = t;
|
||||
end
|
||||
|
||||
-- 0 3
|
||||
-- 2 1
|
||||
for j=1,m do
|
||||
for i=1,n do
|
||||
local v = 4*matrix[j][i]
|
||||
r[m*0+j][n*0+i] = v-3
|
||||
r[m*1+j][n*1+i] = v-2
|
||||
r[m*1+j][n*0+i] = v-1
|
||||
r[m*0+j][n*1+i] = v-0
|
||||
end
|
||||
end
|
||||
|
||||
return r;
|
||||
end
|
||||
--]]
|
||||
|
||||
-- dither matrix
|
||||
local dither = bayer.make(4)
|
||||
|
||||
if use_vac then
|
||||
-- vac8: looks like FS
|
||||
dither = bayer.norm{
|
||||
{35,57,19,55,7,51,4,21},
|
||||
{29,6,41,27,37,17,59,45},
|
||||
{61,15,53,12,62,25,33,9},
|
||||
{23,39,31,49,2,47,13,43},
|
||||
{3,52,8,22,36,58,20,56},
|
||||
{38,18,60,46,30,5,42,28},
|
||||
{63,26,34,11,64,16,54,10},
|
||||
{14,48,1,44,24,40,32,50}
|
||||
}
|
||||
end
|
||||
|
||||
-- get color statistics
|
||||
local stat = {};
|
||||
function stat:clear()
|
||||
self.r = {}
|
||||
self.g = {}
|
||||
self.b = {}
|
||||
for i=1,16 do self.r[i] = 0; self.g[i] = 0; self.b[i] = 0; end
|
||||
end
|
||||
function stat:update(px)
|
||||
local pc2to = thomson.levels.pc2to
|
||||
local r,g,b=pc2to[px.r], pc2to[px.g], pc2to[px.b];
|
||||
self.r[r] = self.r[r] + 1;
|
||||
self.g[g] = self.g[g] + 1;
|
||||
self.b[b] = self.b[b] + 1;
|
||||
end
|
||||
function stat:coversThr(perc)
|
||||
local function f(stat)
|
||||
local t=-stat[1]
|
||||
for i,n in ipairs(stat) do t=t+n end
|
||||
local thr = t*perc; t=-stat[1]
|
||||
for i,n in ipairs(stat) do
|
||||
t=t+n
|
||||
if t>=thr then return i end
|
||||
end
|
||||
return 0
|
||||
end
|
||||
return f(self.r),f(self.g),f(self.b)
|
||||
end
|
||||
stat:clear();
|
||||
for y = 0,99 do
|
||||
for x = 0,159 do
|
||||
stat:update(getLinearPixel(x,y))
|
||||
end
|
||||
thomson.info("Collecting stats...",y,"%")
|
||||
end
|
||||
|
||||
-- enhance luminosity since our mode divide it by two
|
||||
local gain = 1
|
||||
if enhance_lum then
|
||||
-- findout level that covers 98% of all non-black pixels
|
||||
local max = math.max(stat:coversThr(.98))
|
||||
|
||||
gain = math.min(2,255/thomson.levels.linear[max])
|
||||
|
||||
if gain>1 then
|
||||
-- redo stat with enhanced levels
|
||||
-- messagebox('gain '..gain..' '..table.concat({stat:coversThr(.98)},','))
|
||||
stat:clear();
|
||||
for y = 0,99 do
|
||||
for x = 0,159 do
|
||||
stat:update(getLinearPixel(x,y):mul(gain):floor())
|
||||
end
|
||||
thomson.info("Enhancing levels..",y,"%")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- find regularly spaced levels in thomson space
|
||||
local levels = {}
|
||||
function levels.compute(name, stat, num)
|
||||
local tot, max = -stat[1],0;
|
||||
for _,t in ipairs(stat) do
|
||||
max = math.max(t,max)
|
||||
tot = tot + t
|
||||
end
|
||||
local acc,full=-stat[1],0
|
||||
for i,t in ipairs(stat) do
|
||||
acc = acc + t
|
||||
if acc>tot*.98 then
|
||||
full=thomson.levels.linear[i]
|
||||
break
|
||||
end
|
||||
end
|
||||
-- sanity
|
||||
if fixed_levels or full==0 then full=255 end
|
||||
local res = {1}; num = num-1
|
||||
for i=1,num do
|
||||
local p = math.floor(full*i/num)
|
||||
local q = thomson.levels.linear2to[p]
|
||||
if q==res[i] and q<16 then q=q+1 end
|
||||
if not fixed_levels and i<num then
|
||||
if q>res[i]+1 and stat[q-1]>stat[q] then q=q-1 end
|
||||
if q>res[i]+1 and stat[q-1]>stat[q] then q=q-1 end
|
||||
-- 3 corrections? no need...
|
||||
-- if q>res[i]+1 and stat[q-1]>stat[q] then q=q-1 end
|
||||
end
|
||||
res[1+i] = q
|
||||
end
|
||||
|
||||
-- debug
|
||||
if debug then
|
||||
local txt = ""
|
||||
for _,i in ipairs(res) do
|
||||
txt = txt .. i .. " "
|
||||
end
|
||||
for i,t in ipairs(stat) do
|
||||
txt = txt .. "\n" .. string.format("%s%2d:%3d%% ", name, i, math.floor(100*t/(tot+stat[1]))) .. string.rep('X', math.floor(23*t/max))
|
||||
end
|
||||
messagebox(txt)
|
||||
end
|
||||
|
||||
return res
|
||||
end
|
||||
function levels.computeAll(stat)
|
||||
levels.grn = levels.compute("GRN",stat.g,5)
|
||||
levels.red = levels.compute("RED",stat.r,4)
|
||||
levels.blu = levels.compute("BLU",stat.b,3)
|
||||
end
|
||||
levels.computeAll(stat)
|
||||
|
||||
-- put a pixel at (x,y) with dithering
|
||||
local function pset(x,y,px)
|
||||
local thr = dither[1+(y % #dither)][1+(x % #dither[1])]
|
||||
local function dither(val,thr,lvls)
|
||||
local i=#lvls
|
||||
local a,b = thomson.levels.linear[lvls[i]],1e30
|
||||
while i>1 and val<a do
|
||||
i=i-1;
|
||||
a,b=thomson.levels.linear[lvls[i]],a;
|
||||
end
|
||||
return i + ((val-a)>=thr*(b-a) and 0 or -1)
|
||||
end
|
||||
|
||||
local r = dither(px.r, thr, levels.red);
|
||||
local g = dither(px.g, thr, levels.grn);
|
||||
local b = dither(px.b, thr, levels.blu);
|
||||
|
||||
local i = r + b*4
|
||||
local j = g==0 and 0 or (11 + g)
|
||||
|
||||
if with_zig_zag and x%2==1 then
|
||||
thomson.pset(x,y*2+0,j)
|
||||
thomson.pset(x,y*2+1,i)
|
||||
else
|
||||
thomson.pset(x,y*2+0,i)
|
||||
thomson.pset(x,y*2+1,j)
|
||||
end
|
||||
end
|
||||
|
||||
-- BM16 mode
|
||||
thomson.setBM16()
|
||||
|
||||
-- define palette
|
||||
for i=0,15 do
|
||||
local r,g,b=0,0,0
|
||||
if i<12 then
|
||||
-- r = bit32.band(i,3)
|
||||
-- b = bit32.rshift(i,2)
|
||||
b = math.floor(i/4)
|
||||
r = i-4*b
|
||||
else
|
||||
g = i-11
|
||||
end
|
||||
r,g,b=levels.red[r+1],levels.grn[g+1],levels.blu[b+1]
|
||||
thomson.palette(i,b*256+g*16+r-273)
|
||||
end
|
||||
|
||||
-- convert picture
|
||||
for y = 0,99 do
|
||||
for x = 0,159 do
|
||||
pset(x,y, getLinearPixel(x,y):mul(gain):floor())
|
||||
end
|
||||
thomson.info("Converting...",y,"%")
|
||||
end
|
||||
|
||||
-- refresh screen
|
||||
setpicturesize(320,200)
|
||||
thomson.updatescreen()
|
||||
finalizepicture()
|
||||
|
||||
-- save picture
|
||||
do
|
||||
local function exist(file)
|
||||
local f=io.open(file,'rb')
|
||||
if not f then return false else io.close(f); return true; end
|
||||
end
|
||||
local name,path = getfilename()
|
||||
local mapname = string.gsub(name,"%.%w*$","") .. ".map"
|
||||
local fullname = path .. '/' .. mapname
|
||||
-- fullname = 'D:/tmp/toto.map'
|
||||
local ok = not exist(fullname)
|
||||
if not ok then
|
||||
selectbox("Ovr " .. mapname .. "?", "Yes", function() ok = true; end, "No", function() ok = false; end)
|
||||
end
|
||||
if ok then thomson.savep(fullname) end
|
||||
end
|
||||
68
share/grafx2/scripts/samples/picture/thomson/lib/bayer.lua
Normal file
68
share/grafx2/scripts/samples/picture/thomson/lib/bayer.lua
Normal file
@@ -0,0 +1,68 @@
|
||||
-- bayer.lua : bayer matrix suppport.
|
||||
--
|
||||
-- Version: 02-jan-2017
|
||||
--
|
||||
-- Copyright 2016-2017 by Samuel Devulder
|
||||
--
|
||||
-- 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/>
|
||||
|
||||
if not bayer then
|
||||
bayer = {}
|
||||
|
||||
-- doubles a matrix rows and columns
|
||||
function bayer.double(matrix)
|
||||
local m,n=#matrix,#matrix[1]
|
||||
local r = {}
|
||||
for j=1,m*2 do
|
||||
local t = {}
|
||||
for i=1,n*2 do t[i]=0; end
|
||||
r[j] = t;
|
||||
end
|
||||
|
||||
-- 0 3
|
||||
-- 2 1
|
||||
for j=1,m do
|
||||
for i=1,n do
|
||||
local v = 4*matrix[j][i]
|
||||
r[m*0+j][n*0+i] = v-3
|
||||
r[m*1+j][n*1+i] = v-2
|
||||
r[m*1+j][n*0+i] = v-1
|
||||
r[m*0+j][n*1+i] = v-0
|
||||
end
|
||||
end
|
||||
|
||||
return r;
|
||||
end
|
||||
|
||||
-- returns a version of the matrix normalized into
|
||||
-- the 0-1 range
|
||||
function bayer.norm(matrix)
|
||||
local m,n=#matrix,#matrix[1]
|
||||
local max,ret = 0,{}
|
||||
for j=1,m do
|
||||
for i=1,n do
|
||||
max = math.max(max,matrix[j][i])
|
||||
end
|
||||
end
|
||||
-- max=max+1
|
||||
for j=1,m do
|
||||
ret[j] = {}
|
||||
for i=1,n do
|
||||
ret[j][i]=matrix[j][i]/max
|
||||
end
|
||||
end
|
||||
return ret
|
||||
end
|
||||
|
||||
-- returns a normalized order-n bayer matrix
|
||||
function bayer.make(n)
|
||||
local m = {{1}}
|
||||
while n>1 do n,m = n/2,bayer.double(m) end
|
||||
return bayer.norm(m)
|
||||
end
|
||||
|
||||
end -- Bayer
|
||||
345
share/grafx2/scripts/samples/picture/thomson/lib/color.lua
Normal file
345
share/grafx2/scripts/samples/picture/thomson/lib/color.lua
Normal file
@@ -0,0 +1,345 @@
|
||||
-- color.lua : a color class capable of representing
|
||||
-- and manipulating colors in PC-space (gamma=2.2) or
|
||||
-- in linear space (gamma=1).
|
||||
--
|
||||
-- Version: 02-jan-2017
|
||||
--
|
||||
-- Copyright 2016-2017 by Samuel Devulder
|
||||
--
|
||||
-- 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/>
|
||||
|
||||
|
||||
if not Color then
|
||||
Color = {ONE=255,NORMALIZE=.005}
|
||||
function Color:new(r,g,b)
|
||||
local o = {};
|
||||
o.r = type(r)=='number' and r or r and r.r or 0;
|
||||
o.g = type(g)=='number' and g or r and r.g or 0;
|
||||
o.b = type(b)=='number' and b or r and r.b or 0;
|
||||
setmetatable(o, self)
|
||||
self.__index = self
|
||||
return o
|
||||
end
|
||||
Color.black = Color:new(0,0,0)
|
||||
|
||||
function Color.clamp(v,...)
|
||||
if v then
|
||||
return v<0 and 0 or
|
||||
v>Color.ONE and Color.ONE or
|
||||
v,Color.clamp(...)
|
||||
end
|
||||
end
|
||||
|
||||
function Color:clone()
|
||||
return Color:new(self.r, self.g, self.b)
|
||||
end
|
||||
|
||||
function Color:tostring()
|
||||
return "(r=" .. self.r .. " g=" .. self.g .. " b=" .. self.b .. ")"
|
||||
end
|
||||
|
||||
function Color:HSV()
|
||||
local max=math.floor(.5+math.max(self.r,self.g,self.b))
|
||||
local min=math.floor(.5+math.min(self.r,self.g,self.b))
|
||||
|
||||
local H=(max<=min and 0 or
|
||||
max<=self.r and (self.g-self.b)/(max-min)+6 or
|
||||
max<=self.g and (self.b-self.r)/(max-min)+2 or
|
||||
max<=self.b and (self.r-self.g)/(max-min)+4)/6 % 1.0
|
||||
local S=(max==0 or max<=min) and 0 or 1-min/max
|
||||
local V=max/Color.ONE
|
||||
|
||||
return H,S,V
|
||||
end
|
||||
|
||||
function Color:intensity()
|
||||
return .3*self.r + .59*self.g + .11*self.b
|
||||
end
|
||||
|
||||
function Color:mul(val)
|
||||
self.r = self.r * val;
|
||||
self.g = self.g * val;
|
||||
self.b = self.b * val;
|
||||
return self;
|
||||
end
|
||||
|
||||
function Color:div(val)
|
||||
return self:mul(1/val);
|
||||
end
|
||||
|
||||
function Color:add(other)
|
||||
self.r = self.r + other.r;
|
||||
self.g = self.g + other.g;
|
||||
self.b = self.b + other.b;
|
||||
return self;
|
||||
end
|
||||
|
||||
function Color:sub(other)
|
||||
self.r = self.r - other.r;
|
||||
self.g = self.g - other.g;
|
||||
self.b = self.b - other.b;
|
||||
return self;
|
||||
end
|
||||
|
||||
function Color:dist2(other)
|
||||
return self:euclid_dist2(other)
|
||||
-- return Color.dE2000(self,other)^2
|
||||
-- return Color.dE2fast(self,other)
|
||||
end
|
||||
|
||||
function Color:euclid_dist2(other)
|
||||
return (self.r - other.r)^2 +
|
||||
(self.g - other.g)^2 +
|
||||
(self.b - other.b)^2
|
||||
end
|
||||
|
||||
function Color:floor()
|
||||
self.r = math.min(math.floor(self.r),Color.ONE);
|
||||
self.g = math.min(math.floor(self.g),Color.ONE);
|
||||
self.b = math.min(math.floor(self.b),Color.ONE);
|
||||
return self;
|
||||
end
|
||||
|
||||
function Color:toPC()
|
||||
local function f(val)
|
||||
val = val/Color.ONE
|
||||
-- if val<=0.018 then val = 4.5*val; else val = 1.099*(val ^ (1/2.2))-0.099; end
|
||||
|
||||
-- works much metter: https://fr.wikipedia.org/wiki/SRGB
|
||||
if val<=0.0031308 then val=12.92*val else val = 1.055*(val ^ (1/2.4))-0.055 end
|
||||
return val*Color.ONE
|
||||
end;
|
||||
self.r = f(self.r);
|
||||
self.g = f(self.g);
|
||||
self.b = f(self.b);
|
||||
return self;
|
||||
end
|
||||
|
||||
function Color:toLinear()
|
||||
local function f(val)
|
||||
val = val/Color.ONE
|
||||
-- if val<=0.081 then val = val/4.5; else val = ((val+0.099)/1.099)^2.2; end
|
||||
|
||||
-- works much metter: https://fr.wikipedia.org/wiki/SRGB#Transformation_inverse
|
||||
if val<=0.04045 then val = val/12.92 else val = ((val+0.055)/1.055)^2.4 end
|
||||
return val*Color.ONE
|
||||
end;
|
||||
self.r = f(self.r);
|
||||
self.g = f(self.g);
|
||||
self.b = f(self.b);
|
||||
return self;
|
||||
end
|
||||
|
||||
function Color:toRGB()
|
||||
return self.r, self.g, self.b
|
||||
end
|
||||
|
||||
-- return the Color @(x,y) on the original screen in linear space
|
||||
local screen_w, screen_h, _getLinearPictureColor = getpicturesize()
|
||||
function getLinearPictureColor(x,y)
|
||||
if _getLinearPictureColor==nil then
|
||||
_getLinearPictureColor = {}
|
||||
for i=0,255 do _getLinearPictureColor[i] = Color:new(getbackupcolor(i)):toLinear(); end
|
||||
if Color.NORMALIZE>0 then
|
||||
local histo = {}
|
||||
for i=0,255 do histo[i] = 0 end
|
||||
for y=0,screen_h-1 do
|
||||
for x=0,screen_w-1 do
|
||||
local r,g,b = getbackupcolor(getbackuppixel(x,y))
|
||||
histo[r] = histo[r]+1
|
||||
histo[g] = histo[g]+1
|
||||
histo[b] = histo[b]+1
|
||||
end
|
||||
end
|
||||
local acc,thr=0,Color.NORMALIZE*screen_h*screen_w*3
|
||||
local max
|
||||
for i=255,0,-1 do
|
||||
acc = acc + histo[i]
|
||||
if not max and acc>=thr then
|
||||
max = Color:new(i,i,i):toLinear().r
|
||||
end
|
||||
end
|
||||
for _,c in ipairs(_getLinearPictureColor) do
|
||||
c:mul(Color.ONE/max)
|
||||
c.r,c.g,c.b = Color.clamp(c.r,c.g,c.b)
|
||||
end
|
||||
end
|
||||
end
|
||||
return (x<0 or y<0 or x>=screen_w or y>=screen_h) and Color.black or _getLinearPictureColor[getbackuppixel(x,y)]
|
||||
end
|
||||
|
||||
-- http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html
|
||||
function Color.RGBtoXYZ(R,G,B)
|
||||
return 0.4887180*R +0.3106803*G +0.2006017*B,
|
||||
0.1762044*R +0.8129847*G +0.0108109*B,
|
||||
0.0102048*G +0.9897952*B
|
||||
end
|
||||
|
||||
function Color.XYZtoRGB(X,Y,Z)
|
||||
return 2.3706743*X -0.9000405*Y -0.4706338*Z,
|
||||
-0.5138850*X +1.4253036*Y +0.0885814*Z,
|
||||
0.0052982*X -0.0146949*Y +1.0093968*Z
|
||||
end
|
||||
|
||||
-- https://fr.wikipedia.org/wiki/CIE_L*a*b*
|
||||
function Color.XYZtoCIELab(X,Y,Z)
|
||||
local function f(t)
|
||||
return t>0.00885645167 and t^(1/3)
|
||||
or 7.78703703704*t+0.13793103448
|
||||
end
|
||||
X,Y,Z=X/Color.ONE,Y/Color.ONE,Z/Color.ONE
|
||||
return 116*f(Y)-16,
|
||||
500*(f(X)-f(Y)),
|
||||
200*(f(Y)-f(Z))
|
||||
end
|
||||
function Color.CIEALabtoXYZ(L,a,b)
|
||||
local function f(t)
|
||||
return t>0.20689655172 and t^3
|
||||
or 0.12841854934*(t-0.13793103448)
|
||||
end
|
||||
local l=(L+16)/116
|
||||
return Color.ONE*f(l),
|
||||
Color.ONE*f(l+a/500),
|
||||
Color.ONE*f(l-b/200)
|
||||
end
|
||||
function Color:toLab()
|
||||
return Color.XYZtoCIELab(Color.RGBtoXYZ(self:toRGB()))
|
||||
end
|
||||
|
||||
-- http://www.brucelindbloom.com/Eqn_DeltaE_CIE2000.html
|
||||
function Color.dE1976(col1,col2)
|
||||
local L1,a1,b1 = col1:toLab()
|
||||
local L2,a2,b2 = col2:toLab()
|
||||
return ((L1-L2)^2+(a1-a2)^2+(b1-b2)^2)^.5
|
||||
end
|
||||
function Color.dE1994(col1,col2)
|
||||
local L1,a1,b1 = col1:toLab()
|
||||
local L2,a2,b2 = col2:toLab()
|
||||
|
||||
local k1,k2 = 0.045,0.015
|
||||
local kL,kC,kH = 1,1,1
|
||||
|
||||
local c1 = (a1^2 + b1^2)^.5
|
||||
local c2 = (a2^2 + b2^2)^.5
|
||||
|
||||
local dA = a1 - a2
|
||||
local dB = b1 - b2
|
||||
local dC = c1 - c2
|
||||
|
||||
local dH2 = dA^2 + dB^2 - dC^2
|
||||
local dH = dH2>0 and dH2^.5 or 0
|
||||
local dL = L1 - L2
|
||||
|
||||
local sL = 1
|
||||
local sC = 1 + k1*c1
|
||||
local sH = 1 + k2*c1
|
||||
|
||||
local vL = dL/(kL*sL)
|
||||
local vC = dC/(kC*sC)
|
||||
local vH = dH/(kH*sH)
|
||||
|
||||
return (vL^2 + vC^2 + vH^2)^.5
|
||||
end
|
||||
-- http://www.color.org/events/colorimetry/Melgosa_CIEDE2000_Workshop-July4.pdf
|
||||
-- https://en.wikipedia.org/wiki/Color_difference#CIEDE2000
|
||||
function Color.dE2000(col1,col2)
|
||||
local L1,a1,b1 = col1:toLab()
|
||||
local L2,a2,b2 = col2:toLab()
|
||||
|
||||
local kL,kC,kH = 1,1,1
|
||||
|
||||
local l_p = (L1 + L2)/2
|
||||
|
||||
function sqrt(x)
|
||||
return x^.5
|
||||
end
|
||||
function norm(x,y)
|
||||
return sqrt(x^2+y^2)
|
||||
end
|
||||
function mean(x,y)
|
||||
return (x+y)/2
|
||||
end
|
||||
local function atan2(a,b)
|
||||
local t=math.atan2(a,b)*180/math.pi
|
||||
return t<0 and t+360 or t
|
||||
end
|
||||
local function sin(x)
|
||||
return math.sin(x*math.pi/180)
|
||||
end
|
||||
local function cos(x)
|
||||
return math.cos(x*math.pi/180)
|
||||
end
|
||||
|
||||
local c1 = norm(a1,b1)
|
||||
local c2 = norm(a2,b2)
|
||||
local c_ = mean(c1,c2)
|
||||
|
||||
local G = 0.5*(1-sqrt(c_^7/(c_^7+25^7)))
|
||||
local a1p = a1*(1+G)
|
||||
local a2p = a2*(1+G)
|
||||
|
||||
local c1p = norm(a1p,b1)
|
||||
local c2p = norm(a2p,b2)
|
||||
local c_p = mean(c1p,c2p)
|
||||
|
||||
local h1p = atan2(b1,a1p)
|
||||
local h2p = atan2(b2,a2p)
|
||||
|
||||
local h_p = mean(h1p,h2p) +
|
||||
(math.abs(h1p - h2p)<=180 and 0 or
|
||||
h1p+h2p<360 and 180 or -180)
|
||||
|
||||
local T = 1 -
|
||||
0.17 * cos( h_p - 30) +
|
||||
0.24 * cos(2 * h_p ) +
|
||||
0.32 * cos(3 * h_p + 6) -
|
||||
0.20 * cos(4 * h_p - 63)
|
||||
|
||||
local dhp = h2p - h1p + (math.abs(h1p - h2p)<=180 and 0 or
|
||||
h2p<=h1p and 360 or
|
||||
-360)
|
||||
local dLp = L2 - L1
|
||||
local dCp = c2p - c1p
|
||||
local dHp = 2*sqrt(c1p*c2p)*sin(dhp/2)
|
||||
|
||||
|
||||
local sL = 1 + 0.015*(l_p - 50)^2/sqrt(20+(l_p-50)^2)
|
||||
local sC = 1 + 0.045*c_p
|
||||
local sH = 1 + 0.015*c_p*T
|
||||
|
||||
local d0 = 30*math.exp(-((h_p-275)/25)^2)
|
||||
|
||||
local rC = 2*sqrt(c_p^7/(c_p^7+25^7))
|
||||
local rT = -rC * sin(2*d0)
|
||||
|
||||
return sqrt( (dLp / (kL*sL))^2 +
|
||||
(dCp / (kC*sC))^2 +
|
||||
(dHp / (kH*sH))^2 +
|
||||
(dCp / (kC*sC))*(dHp / (kH*sH))*rT )
|
||||
end
|
||||
|
||||
function Color.dE2fast(col1,col2)
|
||||
-- http://www.compuphase.com/cmetric.htm#GAMMA
|
||||
local r1,g1,b1 = Color.clamp(col1:toRGB())
|
||||
local r2,g2,b2 = Color.clamp(col2:toRGB())
|
||||
|
||||
local rM = (r1+r2)/(Color.ONE*2)
|
||||
|
||||
return ((r1-r2)^2)*(2+rM) +
|
||||
((g1-g2)^2)*(4+1) +
|
||||
((b1-b2)^2)*(3-rM)
|
||||
end
|
||||
|
||||
function Color:hash(M)
|
||||
M=M or 256
|
||||
local m=(M-1)/Color.ONE
|
||||
local function f(x)
|
||||
return math.floor(.5+(x<0 and 0 or x>Color.ONE and Color.ONE or x)*m)
|
||||
end
|
||||
return f(self.r)+M*(f(self.g)+M*f(self.b))
|
||||
end
|
||||
end -- Color defined
|
||||
@@ -0,0 +1,520 @@
|
||||
-- color_reduction.lua : support for reducing the
|
||||
-- colors for a thomson image.
|
||||
--
|
||||
-- Inspire by Xiaolin Wu v2 (Xiaolin Wu 1992).
|
||||
-- Greedy orthogonal bipartition of RGB space for
|
||||
-- variance minimization aided by inclusion-exclusion
|
||||
-- tricks. (Author's description)
|
||||
-- http://www.ece.mcmaster.ca/%7Exwu/cq.c
|
||||
--
|
||||
-- Version: 02-jan-2017
|
||||
--
|
||||
-- Copyright 2016-2017 by Samuel Devulder
|
||||
--
|
||||
-- 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('color.lua')
|
||||
run('bayer.lua')
|
||||
run('thomson.lua')
|
||||
run('convex_hull.lua')
|
||||
|
||||
if not ColorReducer then
|
||||
|
||||
-- clamp a value in the 0-255 range
|
||||
local function clamp(v)
|
||||
v=math.floor(v+.5)
|
||||
return v<0 and 0 or v>255 and 255 or v
|
||||
end
|
||||
|
||||
local Voxel = {}
|
||||
|
||||
function Voxel:new()
|
||||
local o = {m2 = 0, wt=0, mr=0, mg=0, mb=0}
|
||||
setmetatable(o, self)
|
||||
self.__index = self
|
||||
return o
|
||||
end
|
||||
|
||||
function Voxel:rgb()
|
||||
local n=self.wt; n=n>0 and n or 1
|
||||
return clamp(self.mr/n),
|
||||
clamp(self.mg/n),
|
||||
clamp(self.mb/n)
|
||||
end
|
||||
|
||||
function Voxel:toThomson()
|
||||
local r,g,b=self:rgb()
|
||||
return thomson.levels.linear2to[r]-1,
|
||||
thomson.levels.linear2to[g]-1,
|
||||
thomson.levels.linear2to[b]-1
|
||||
end
|
||||
|
||||
function Voxel:toPal()
|
||||
local r,g,b=self:toThomson()
|
||||
return r+g*16+b*256
|
||||
end
|
||||
|
||||
function Voxel:tostring()
|
||||
local n=self.wt
|
||||
local r,g,b=self:rgb()
|
||||
return "(n="..math.floor(n*10)/10 .." r=" .. r.. " g="..g .. " b=" .. b.. " rgb=".. table.concat({self:toThomson()},',').. ")"
|
||||
end
|
||||
|
||||
function Voxel:addColor(color)
|
||||
local r,g,b=color:toRGB()
|
||||
self.wt = self.wt + 1
|
||||
self.mr = self.mr + r
|
||||
self.mg = self.mg + g
|
||||
self.mb = self.mb + b
|
||||
self.m2 = self.m2 + r*r + g*g + b*b
|
||||
return self
|
||||
end
|
||||
|
||||
function Voxel:add(other,k)
|
||||
k=k or 1
|
||||
self.wt = self.wt + other.wt*k
|
||||
self.mr = self.mr + other.mr*k
|
||||
self.mg = self.mg + other.mg*k
|
||||
self.mb = self.mb + other.mb*k
|
||||
self.m2 = self.m2 + other.m2*k
|
||||
return self
|
||||
end
|
||||
|
||||
function Voxel:mul(k)
|
||||
return self:add(self,k-1)
|
||||
end
|
||||
|
||||
function Voxel:module2()
|
||||
return self.mr*self.mr + self.mg*self.mg + self.mb*self.mb
|
||||
end
|
||||
|
||||
ColorReducer = {}
|
||||
|
||||
function ColorReducer:new()
|
||||
local o = {}
|
||||
setmetatable(o, self)
|
||||
self.__index = self
|
||||
return o
|
||||
end
|
||||
|
||||
function ColorReducer:v(r,g,b)
|
||||
local i=(r*17+g)*17+b
|
||||
if not self[i] then self[i]=Voxel:new() end
|
||||
return self[i]
|
||||
end
|
||||
|
||||
function ColorReducer:add(linearColor)
|
||||
local r,g,b=linearColor:toRGB()
|
||||
|
||||
r,g,b=thomson.levels.linear2to[clamp(r)],
|
||||
thomson.levels.linear2to[clamp(g)],
|
||||
thomson.levels.linear2to[clamp(b)]
|
||||
self:v(r,g,b):addColor(linearColor)
|
||||
-- if r==1 and g==1 and b==1 then messagebox(self:v(r,g,b).wt) end
|
||||
end
|
||||
|
||||
function ColorReducer:M3d()
|
||||
-- convert histogram into moments so that we can
|
||||
-- rapidly calculate the sums of the above quantities
|
||||
-- over any desired box.
|
||||
for r=1,16 do
|
||||
local area={}
|
||||
for i=0,16 do area[i]=Voxel:new() end
|
||||
for g=1,16 do
|
||||
local line=Voxel:new()
|
||||
for b=1,16 do
|
||||
local v = self:v(r,g,b)
|
||||
-- v:mul(0):add(self:v(r-1,g,b)):add(area[b]:add(line:add(v))
|
||||
line:add(v)
|
||||
area[b]:add(line)
|
||||
v:mul(0):add(self:v(r-1,g,b)):add(area[b])
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function ColorReducer:Vol(cube)
|
||||
-- Compute sum over a box of all statistics
|
||||
return Voxel:new()
|
||||
:add(self:v(cube.r1,cube.g1,cube.b1), 1)
|
||||
:add(self:v(cube.r1,cube.g1,cube.b0),-1)
|
||||
:add(self:v(cube.r1,cube.g0,cube.b1),-1)
|
||||
:add(self:v(cube.r1,cube.g0,cube.b0), 1)
|
||||
:add(self:v(cube.r0,cube.g1,cube.b1),-1)
|
||||
:add(self:v(cube.r0,cube.g1,cube.b0), 1)
|
||||
:add(self:v(cube.r0,cube.g0,cube.b1), 1)
|
||||
:add(self:v(cube.r0,cube.g0,cube.b0),-1)
|
||||
end
|
||||
|
||||
-- The next two routines allow a slightly more efficient
|
||||
-- calculation of Vol() for a proposed subbox of a given
|
||||
-- box. The sum of Top() and Bottom() is the Vol() of a
|
||||
-- subbox split in the given direction and with the specified
|
||||
-- new upper bound.
|
||||
|
||||
function ColorReducer:Bottom(cube,dir)
|
||||
-- Compute part of Vol(cube, mmt) that doesn't
|
||||
-- depend on r1, g1, or b1 (depending on dir)
|
||||
local v=Voxel:new()
|
||||
if dir=="RED" then
|
||||
v:add(self:v(cube.r0,cube.g1,cube.b1),-1)
|
||||
:add(self:v(cube.r0,cube.g1,cube.b0), 1)
|
||||
:add(self:v(cube.r0,cube.g0,cube.b1), 1)
|
||||
:add(self:v(cube.r0,cube.g0,cube.b0),-1)
|
||||
elseif dir=="GREEN" then
|
||||
v:add(self:v(cube.r1,cube.g0,cube.b1),-1)
|
||||
:add(self:v(cube.r1,cube.g0,cube.b0), 1)
|
||||
:add(self:v(cube.r0,cube.g0,cube.b1), 1)
|
||||
:add(self:v(cube.r0,cube.g0,cube.b0),-1)
|
||||
elseif dir=="BLUE" then
|
||||
v:add(self:v(cube.r1,cube.g1,cube.b0),-1)
|
||||
:add(self:v(cube.r1,cube.g0,cube.b0), 1)
|
||||
:add(self:v(cube.r0,cube.g1,cube.b0), 1)
|
||||
:add(self:v(cube.r0,cube.g0,cube.b0),-1)
|
||||
end
|
||||
return v
|
||||
end
|
||||
|
||||
function ColorReducer:Top(cube,dir,pos)
|
||||
-- Compute remainder of Vol(cube, mmt), substituting
|
||||
-- pos for r1, g1, or b1 (depending on dir)
|
||||
local v=Voxel:new()
|
||||
if dir=="RED" then
|
||||
v:add(self:v(pos,cube.g1,cube.b1), 1)
|
||||
:add(self:v(pos,cube.g1,cube.b0),-1)
|
||||
:add(self:v(pos,cube.g0,cube.b1),-1)
|
||||
:add(self:v(pos,cube.g0,cube.b0), 1)
|
||||
elseif dir=="GREEN" then
|
||||
v:add(self:v(cube.r1,pos,cube.b1), 1)
|
||||
:add(self:v(cube.r1,pos,cube.b0),-1)
|
||||
:add(self:v(cube.r0,pos,cube.b1),-1)
|
||||
:add(self:v(cube.r0,pos,cube.b0), 1)
|
||||
elseif dir=="BLUE" then
|
||||
v:add(self:v(cube.r1,cube.g1,pos), 1)
|
||||
:add(self:v(cube.r1,cube.g0,pos),-1)
|
||||
:add(self:v(cube.r0,cube.g1,pos),-1)
|
||||
:add(self:v(cube.r0,cube.g0,pos), 1)
|
||||
end
|
||||
return v
|
||||
end
|
||||
|
||||
function ColorReducer:Var(cube)
|
||||
-- Compute the weighted variance of a box
|
||||
-- NB: as with the raw statistics, this is really the variance * size
|
||||
local v = self:Vol(cube)
|
||||
return v.m2 - v:module2()/v.wt
|
||||
end
|
||||
|
||||
-- We want to minimize the sum of the variances of two subboxes.
|
||||
-- The sum(c^2) terms can be ignored since their sum over both subboxes
|
||||
-- is the same (the sum for the whole box) no matter where we split.
|
||||
-- The remaining terms have a minus sign in the variance formula,
|
||||
-- so we drop the minus sign and MAXIMIZE the sum of the two terms.
|
||||
|
||||
function ColorReducer:Maximize(cube,dir,first,last,cut,whole)
|
||||
local base = self:Bottom(cube,dir)
|
||||
local max = 0
|
||||
cut[dir] = -1
|
||||
for i=first,last-1 do
|
||||
local half = Voxel:new():add(base):add(self:Top(cube,dir,i))
|
||||
-- now half is sum over lower half of box, if split at i
|
||||
if half.wt>0 then -- subbox could be empty of pixels!
|
||||
local temp = half:module2()/half.wt
|
||||
half:mul(-1):add(whole)
|
||||
if half.wt>0 then
|
||||
temp = temp + half:module2()/half.wt
|
||||
if temp>max then max=temp; cut[dir] = i end
|
||||
end
|
||||
end
|
||||
end
|
||||
return max
|
||||
end
|
||||
|
||||
function ColorReducer:Cut(set1,set2)
|
||||
local whole = self:Vol(set1)
|
||||
local cut = {}
|
||||
local maxr = self:Maximize(set1,"RED", set1.r0+1,set1.r1, cut, whole)
|
||||
local maxg = self:Maximize(set1,"GREEN",set1.g0+1,set1.g1, cut, whole)
|
||||
local maxb = self:Maximize(set1,"BLUE", set1.b0+1,set1.b1, cut, whole)
|
||||
local dir = "BLUE"
|
||||
if maxr>=maxg and maxr>=maxb then
|
||||
dir = "RED"
|
||||
if cut.RED<0 then return false end -- can't split the box
|
||||
elseif maxg>=maxr and maxg>=maxb then
|
||||
dir = "GREEN"
|
||||
end
|
||||
|
||||
set2.r1=set1.r1
|
||||
set2.g1=set1.g1
|
||||
set2.b1=set1.b1
|
||||
if dir=="RED" then
|
||||
set1.r1 = cut[dir]
|
||||
set2.r0 = cut[dir]
|
||||
set2.g0 = set1.g0
|
||||
set2.b0 = set1.b0
|
||||
elseif dir=="GREEN" then
|
||||
set1.g1 = cut[dir]
|
||||
set2.g0 = cut[dir]
|
||||
set2.r0 = set1.r0
|
||||
set2.b0 = set1.b0
|
||||
else
|
||||
set1.b1 = cut[dir]
|
||||
set2.b0 = cut[dir]
|
||||
set2.r0 = set1.r0
|
||||
set2.g0 = set1.g0
|
||||
end
|
||||
local function vol(box)
|
||||
local function q(a,b) return (a-b)*(a-b) end
|
||||
return q(box.r1,box.r0) + q(box.g1,box.g0) + q(box.b1,box.b0)
|
||||
end
|
||||
set1.vol = vol(set1)
|
||||
set2.vol = vol(set2)
|
||||
return true
|
||||
end
|
||||
|
||||
function ColorReducer:boostBorderColors()
|
||||
-- Idea: consider the convex hull of all the colors.
|
||||
-- These color can be mixed to produce any other used
|
||||
-- color, so they are kind of really important.
|
||||
-- Unfortunately most color-reduction algorithm do not
|
||||
-- retain these color ue to averaging property. The idea
|
||||
-- here is not artifically increase their count so that
|
||||
-- the averaging goes into these colors.
|
||||
|
||||
-- do return self end -- for testing
|
||||
|
||||
local hull=ConvexHull:new(function(v)
|
||||
return {v:rgb()}
|
||||
end)
|
||||
|
||||
-- collect set of points
|
||||
local pts,tot={},0
|
||||
for i=0,17*17*17-1 do
|
||||
local v = self[i]
|
||||
if v then
|
||||
pts[v] = true
|
||||
tot=tot+v.wt
|
||||
end
|
||||
end
|
||||
|
||||
-- build convex hull of colors.
|
||||
for v in pairs(pts) do
|
||||
hull:addPoint(v)
|
||||
end
|
||||
|
||||
-- collect points near the hull
|
||||
local bdr, hsz, hnb, max = {},0,0,0
|
||||
for v in pairs(pts) do
|
||||
if hull:distToHull(v)>-.1 then
|
||||
bdr[v] = true
|
||||
hnb = hnb+1
|
||||
hsz = hsz+v.wt
|
||||
max = math.max(max,v.wt)
|
||||
end
|
||||
end
|
||||
|
||||
if tot>hsz then
|
||||
-- heuristic formula to boost colors of the hull
|
||||
-- not too little, not to much. It might be tuned
|
||||
-- over time, but this version gives satisfying
|
||||
-- result (.51 is important)
|
||||
for v in pairs(bdr) do
|
||||
v:mul(math.min(max,tot-hsz,v.wt*(1+.51*max*hnb/hsz))/v.wt)
|
||||
end
|
||||
end
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
function ColorReducer:buildPalette(max, forceBlack)
|
||||
if self.palette then return self.palette end
|
||||
|
||||
forceBlack=forceBlack or true
|
||||
|
||||
self:M3d()
|
||||
local function c(r0,g0,b0,r1,g1,b1)
|
||||
return {r0=r0,r1=r1,g0=g0,g1=g1,b0=b0,b1=b1}
|
||||
end
|
||||
local cube = {c(0,0,0,16,16,16)}
|
||||
local n,i = 1,2
|
||||
local vv = {}
|
||||
while i<=max do
|
||||
cube[i] = c(0,0,0,1,1,1)
|
||||
if forceBlack and i==max then
|
||||
local ko = true;
|
||||
for j=1,max-1 do
|
||||
if self:Vol(cube[j]):toPal()==0 then
|
||||
ko = false
|
||||
break
|
||||
end
|
||||
end
|
||||
if ko then break end -- forcingly add black
|
||||
end
|
||||
if self:Cut(cube[n], cube[i]) then
|
||||
vv[n] = cube[n].vol>1 and self:Var(cube[n]) or 0
|
||||
vv[i] = cube[i].vol>1 and self:Var(cube[i]) or 0
|
||||
else
|
||||
vv[n] = 0
|
||||
cube[i] = nil
|
||||
i=i-1
|
||||
end
|
||||
n = 1; local temp = vv[n]
|
||||
for k=2,i do if vv[k]>temp then temp=vv[k]; n=k; end end
|
||||
if temp<=0 then break end -- not enough color
|
||||
i = i+1
|
||||
end
|
||||
|
||||
-- helper to sort the palette
|
||||
local pal = {}
|
||||
for _,c in ipairs(cube) do
|
||||
local r,g,b=self:Vol(c):toThomson()
|
||||
table.insert(pal, {r=r+1,g=g+1,b=b+1})
|
||||
end
|
||||
-- messagebox(#pal)
|
||||
|
||||
-- sort the palette in a nice color distribution
|
||||
local function cmp(a,b)
|
||||
local t=thomson.levels.pc
|
||||
a = Color:new(t[a.r],t[a.g],t[a.b])
|
||||
b = Color:new(t[b.r],t[b.g],t[b.b])
|
||||
local ah,as,av=a:HSV()
|
||||
local bh,bs,bv=b:HSV()
|
||||
as,bs=a:intensity()/255,b:intensity()/255
|
||||
-- function lum(a) return ((.241*a.r + .691*a.g + .068*a.b)/255)^.5 end
|
||||
-- as,bs=lum(a),lum(b)
|
||||
local sat,int=32,256
|
||||
local function quant(ah,as,av)
|
||||
return math.floor(ah*8),
|
||||
math.floor(as*sat),
|
||||
math.floor(av*int+.5)
|
||||
end
|
||||
ah,as,av=quant(ah,as,av)
|
||||
bh,bs,bv=quant(bh,bs,bv)
|
||||
-- if true then return ah<bh end
|
||||
-- if true then return av<bv or av==bv and as<bs end
|
||||
-- if true then return as<bs or as==bs and av<bv end
|
||||
if ah%2==1 then as,av=sat-as,int-av end
|
||||
if bh%2==1 then bs,bv=sat-bs,int-bv end
|
||||
return ah<bh or (ah==bh and (as<bs or (as==bs and av<bv)))
|
||||
end
|
||||
table.sort(pal, cmp)
|
||||
|
||||
-- add black if color count is not reached
|
||||
while #pal<max do table.insert(pal,{r=1,g=1,b=1}) end
|
||||
|
||||
-- linear palette
|
||||
local linear = {}
|
||||
for i=1,#pal do
|
||||
linear[i] = Color:new(thomson.levels.linear[pal[i].r],
|
||||
thomson.levels.linear[pal[i].g],
|
||||
thomson.levels.linear[pal[i].b])
|
||||
end
|
||||
self.linear = linear
|
||||
|
||||
-- thomson palette
|
||||
local palette = {}
|
||||
for i=1,#pal do
|
||||
palette[i] = pal[i].r+pal[i].g*16+pal[i].b*256-273
|
||||
end
|
||||
self.palette = palette
|
||||
|
||||
return palette
|
||||
end
|
||||
|
||||
function ColorReducer:getLinearColors()
|
||||
return self.linear
|
||||
end
|
||||
|
||||
function ColorReducer:getColor(linearColor)
|
||||
local M=64
|
||||
local m=(M-1)/255
|
||||
local function f(x)
|
||||
return math.floor(.5+(x<0 and 0 or x>255 and 255 or x)*m)
|
||||
end
|
||||
local k=f(linearPixel.r)+M*(f(linearPixel.g)+M*f(linearPixel.b))
|
||||
local c=self[k]
|
||||
if c==nil then
|
||||
local dm=1e30
|
||||
for i,palette in ipairs(self.linear) do
|
||||
local d = palette:dist2(linearColor)
|
||||
if d<dm then dm,c=d,i end
|
||||
end
|
||||
self[k] = c-1
|
||||
end
|
||||
return c
|
||||
end
|
||||
|
||||
function ColorReducer:analyze(w,h,getLinearPixel,info)
|
||||
if not info then info=function(y) thomson.info() end end
|
||||
for y=0,h-1 do
|
||||
info(y)
|
||||
for x=0,w-1 do
|
||||
self:add(getLinearPixel(x,y))
|
||||
end
|
||||
end
|
||||
return self
|
||||
end
|
||||
|
||||
-- fixes the issue ith low-level of intensity
|
||||
function ColorReducer:analyzeWithDither(w,h,getLinearPixel,info)
|
||||
-- do return self:analyze(w,h,getLinearPixel,info) end
|
||||
local mat=bayer.make(4)
|
||||
local mx,my=#mat,#mat[1]
|
||||
local function dith(x,y)
|
||||
local function dith(v,t)
|
||||
local L=thomson.levels.linear
|
||||
local i=14
|
||||
local a,b=L[i+1],L[i+2]
|
||||
if v>=b then return v end
|
||||
while v<a do a,b,i=L[i],a,i-1 end
|
||||
return (v-a)/(b-a)>=t and b or a
|
||||
end
|
||||
local t = mat[1+(x%mx)][1+(y%my)]
|
||||
local p=getLinearPixel(x,y)
|
||||
p.r = dith(p.r, t)
|
||||
p.g = dith(p.g, t)
|
||||
p.b = dith(p.b, t)
|
||||
return p
|
||||
end
|
||||
return self:analyze(w,h, function(x,y)
|
||||
return
|
||||
dith(x,y)
|
||||
-- :mul(4):add(getLinearPixel(x,y)):div(5)
|
||||
-- :add(getLinearPixel(x-1,y))
|
||||
-- :add(getLinearPixel(x+1,y))
|
||||
-- :div(3)
|
||||
end, info)
|
||||
end
|
||||
|
||||
--[[
|
||||
function ColorReducer:analyzeBuildWithDither(w,h,max,getLinearPixel,info)
|
||||
if not info then info=function(y) wait(0) end end
|
||||
|
||||
local dith = ColorReducer:new()
|
||||
dith:analyze(w,h,getLinearPixel,function(y) info(y/2) end)
|
||||
|
||||
|
||||
local ostro = OstroDither:new(dith:buildPalette(max),
|
||||
thomson.levels.linear, .9)
|
||||
ostro:dither(w,h,
|
||||
function(x,y,xs,err)
|
||||
local p = getLinearPixel(x,y)
|
||||
self:add(err[x]:clone():add(p))
|
||||
self:add(p)
|
||||
return p
|
||||
end,
|
||||
function(x,y,c)
|
||||
-- self:add(ostro:_linearPalette(c+1))
|
||||
end,true,
|
||||
function(y) info((h+y)/2) end
|
||||
)
|
||||
|
||||
return self:buildPalette(max)
|
||||
end
|
||||
--]]
|
||||
|
||||
end -- ColorReduction
|
||||
219
share/grafx2/scripts/samples/picture/thomson/lib/convex_hull.lua
Normal file
219
share/grafx2/scripts/samples/picture/thomson/lib/convex_hull.lua
Normal file
@@ -0,0 +1,219 @@
|
||||
-- convxhull.lua : support for computing the convex
|
||||
-- hull of a set of points.
|
||||
--
|
||||
-- inspired from: https://gist.github.com/anonymous/5184ba0bcab21d3dd19781efd3aae543
|
||||
--
|
||||
-- Version: 02-jan-2017
|
||||
--
|
||||
-- Copyright 2016-2017 by Samuel Devulder
|
||||
--
|
||||
-- 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/>
|
||||
|
||||
if not ConvexHull then
|
||||
|
||||
local function sub(u,v)
|
||||
return {u[1]-v[1],u[2]-v[2],u[3]-v[3]}
|
||||
end
|
||||
|
||||
local function mul(k,u)
|
||||
return {k*u[1],k*u[2],k*u[3]}
|
||||
end
|
||||
|
||||
local function cross(u,v)
|
||||
return {u[2]*v[3] - u[3]*v[2],
|
||||
u[3]*v[1] - u[1]*v[3],
|
||||
u[1]*v[2] - u[2]*v[1]}
|
||||
end
|
||||
|
||||
local function dot(u,v)
|
||||
return u[1]*v[1] + u[2]*v[2] + u[3]*v[3]
|
||||
end
|
||||
|
||||
local function unit(u)
|
||||
local d=dot(u,u)
|
||||
return d==0 and u or mul(1/d^.5, u)
|
||||
end
|
||||
|
||||
ConvexHull = {}
|
||||
|
||||
function ConvexHull:new(coordFct)
|
||||
local o = {
|
||||
points={},
|
||||
coord=coordFct
|
||||
}
|
||||
setmetatable(o, self)
|
||||
self.__index = self
|
||||
return o
|
||||
end
|
||||
|
||||
function ConvexHull.coord(elt)
|
||||
return {elt[1],elt[2],elt[3]}
|
||||
end
|
||||
|
||||
function ConvexHull:vect(a,b)
|
||||
return sub(self.coord(b),self.coord(a))
|
||||
end
|
||||
|
||||
function ConvexHull:normal(face)
|
||||
local u=self:vect(face[1],face[2])
|
||||
local v=self:vect(face[1],face[3])
|
||||
return cross(u,v)
|
||||
end
|
||||
|
||||
function ConvexHull:printPoint(p)
|
||||
return '('..table.concat(self.coord(p),',')..')'
|
||||
end
|
||||
|
||||
function ConvexHull:printFace(F)
|
||||
return '['..self:printPoint(F[1])..' '..
|
||||
self:printPoint(F[2])..' '..
|
||||
self:printPoint(F[3])..']'
|
||||
end
|
||||
|
||||
function ConvexHull:seen(face,p)
|
||||
local N=self:normal(face)
|
||||
local P=self:vect(face[1],p)
|
||||
return dot(N,P)>=0
|
||||
end
|
||||
|
||||
function ConvexHull:bdry(faces)
|
||||
local code={n=0}
|
||||
function code.encode(pt,...)
|
||||
if pt then
|
||||
local k = code[pt]
|
||||
if not k then
|
||||
k = code.n+1
|
||||
code[k] = pt
|
||||
code[pt] = k
|
||||
code.n = k
|
||||
end
|
||||
local rest = code.encode(...)
|
||||
return rest and (k..','..rest) or ""..k
|
||||
end
|
||||
end
|
||||
function code.decode(str)
|
||||
local i = str:find(',')
|
||||
if i then
|
||||
local k = str:sub(1,i-1)
|
||||
return code[tonumber(k)],code.decode(str:sub(i+1))
|
||||
else
|
||||
return code[tonumber(str)]
|
||||
end
|
||||
end
|
||||
local set = {}
|
||||
local function add(...)
|
||||
set[code.encode(...)] = true
|
||||
end
|
||||
local function rem(...)
|
||||
set[code.encode(...)] = nil
|
||||
end
|
||||
local function keys()
|
||||
local r = {}
|
||||
for k in pairs(set) do
|
||||
r[{code.decode(k)}] = true
|
||||
end
|
||||
return r
|
||||
end
|
||||
for F in pairs(faces) do
|
||||
add(F[1],F[2])
|
||||
add(F[2],F[3])
|
||||
add(F[3],F[1])
|
||||
end
|
||||
for F in pairs(faces) do
|
||||
rem(F[1],F[3])
|
||||
rem(F[3],F[2])
|
||||
rem(F[2],F[1])
|
||||
end
|
||||
return keys()
|
||||
end
|
||||
|
||||
function ConvexHull:addPoint(p)
|
||||
-- first 3 points
|
||||
if self.points then
|
||||
if p==self.points[1] or p==self.points[2] then return end
|
||||
table.insert(self.points,p)
|
||||
|
||||
if #self.points==3 then
|
||||
self.hull={
|
||||
{self.points[1],self.points[2],self.points[3]},
|
||||
{self.points[1],self.points[3],self.points[2]}
|
||||
}
|
||||
self.points=nil
|
||||
end
|
||||
else
|
||||
local seenF,n = {},0
|
||||
for _,F in ipairs(self.hull) do
|
||||
if F[1]==p or F[2]==p or F[3]==p then return end
|
||||
if self:seen(F,p) then seenF[F]=true;n=n+1 end
|
||||
end
|
||||
|
||||
if n==#self.hull then
|
||||
-- if can see all faces, unsee ones looking "down"
|
||||
local N
|
||||
for F in pairs(seenF) do N=self:normal(F); break; end
|
||||
for F in pairs(seenF) do
|
||||
if dot(self:normal(F),N)<=0 then
|
||||
seenF[F] = nil
|
||||
n=n-1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- remove (old) seen faces
|
||||
local z=#self.hull
|
||||
for i=#self.hull,1,-1 do
|
||||
if seenF[self.hull[i]] then
|
||||
table.remove(self.hull,i)
|
||||
end
|
||||
end
|
||||
|
||||
-- insert new boundaries with seen faces
|
||||
for E in pairs(self:bdry(seenF)) do
|
||||
table.insert(self.hull,{E[1],E[2],p})
|
||||
end
|
||||
end
|
||||
return self
|
||||
end
|
||||
|
||||
function ConvexHull:verticesSet()
|
||||
local v = {}
|
||||
if self.hull then
|
||||
for _,F in ipairs(self.hull) do
|
||||
v[F[1]] = true
|
||||
v[F[2]] = true
|
||||
v[F[3]] = true
|
||||
end
|
||||
end
|
||||
return v
|
||||
end
|
||||
|
||||
function ConvexHull:verticesSize()
|
||||
local n = 0
|
||||
for _ in pairs(self:verticesSet()) do n=n+1 end
|
||||
return n
|
||||
end
|
||||
|
||||
function ConvexHull:distToFace(F,pt)
|
||||
local N=unit(self:normal(F))
|
||||
local P=self:vect(F[1],pt)
|
||||
return dot(N,P)
|
||||
end
|
||||
|
||||
function ConvexHull:distToHull(pt)
|
||||
local d
|
||||
for _,F in ipairs(self.hull) do
|
||||
local t = self:distToFace(F,pt)
|
||||
d = d==nil and t or
|
||||
(0<=t and t<d or
|
||||
0>=t and t>d) and t or
|
||||
d
|
||||
if d==0 then break end
|
||||
end
|
||||
return d
|
||||
end
|
||||
|
||||
end -- ConvexHull
|
||||
@@ -0,0 +1,629 @@
|
||||
-- ostromoukhov.lua : Color dithering using variable
|
||||
-- coefficients.
|
||||
--
|
||||
-- https://liris.cnrs.fr/victor.ostromoukhov/publications/pdf/SIGGRAPH01_varcoeffED.pdf
|
||||
--
|
||||
-- Version: 02-jan-2017
|
||||
--
|
||||
-- Copyright 2016-2017 by Samuel Devulder
|
||||
--
|
||||
-- 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('color.lua')
|
||||
run('thomson.lua')
|
||||
|
||||
if not OstroDither then
|
||||
|
||||
OstroDither = {}
|
||||
|
||||
local function default_levels()
|
||||
return {r={0,Color.ONE},g={0,Color.ONE},b={0,Color.ONE}}
|
||||
end
|
||||
|
||||
function OstroDither:new(palette,attenuation,levels)
|
||||
local o = {
|
||||
attenuation = attenuation or .9, -- works better than 1
|
||||
palette = palette or thomson.default_palette,
|
||||
levels = levels or default_levels(),
|
||||
clash_size = 8 -- for color clash
|
||||
}
|
||||
setmetatable(o, self)
|
||||
self.__index = self
|
||||
return o
|
||||
end
|
||||
|
||||
function OstroDither:setLevelsFromPalette()
|
||||
local rLevels = {[1]=true,[16]=true}
|
||||
local gLevels = {[1]=true,[16]=true}
|
||||
local bLevels = {[1]=true,[16]=true}
|
||||
local default_palette = true
|
||||
for i,pal in ipairs(self.palette) do
|
||||
local r,g,b=pal%16,math.floor(pal/16)%16,math.floor(pal/256)
|
||||
rLevels[1+r] = true
|
||||
gLevels[1+g] = true
|
||||
bLevels[1+b] = true
|
||||
if pal~=thomson.default_palette[i] then
|
||||
default_palette = false
|
||||
end
|
||||
end
|
||||
local levels = {r={},g={},b={}}
|
||||
for i,v in ipairs(thomson.levels.linear) do
|
||||
if false then
|
||||
if rLevels[i] and gLevels[i] and bLevels[i] then
|
||||
table.insert(levels.r, v)
|
||||
table.insert(levels.g, v)
|
||||
table.insert(levels.b, v)
|
||||
end
|
||||
else
|
||||
if rLevels[i] then table.insert(levels.r, v) end
|
||||
if gLevels[i] then table.insert(levels.g, v) end
|
||||
if bLevels[i] then table.insert(levels.b, v) end
|
||||
end
|
||||
end
|
||||
self.levels = levels
|
||||
if default_palette then
|
||||
self.attenuation = .98
|
||||
self.levels = default_levels()
|
||||
else
|
||||
self.attenuation = .9
|
||||
self.levels = levels
|
||||
end
|
||||
end
|
||||
|
||||
function OstroDither:_coefs(linearLevel,rgb)
|
||||
if self._ostro==nil then
|
||||
-- original coefs, about to be adapted to the levels
|
||||
local t={
|
||||
13, 0, 5,
|
||||
13, 0, 5,
|
||||
21, 0, 10,
|
||||
7, 0, 4,
|
||||
8, 0, 5,
|
||||
47, 3, 28,
|
||||
23, 3, 13,
|
||||
15, 3, 8,
|
||||
22, 6, 11,
|
||||
43, 15, 20,
|
||||
7, 3, 3,
|
||||
501, 224, 211,
|
||||
249, 116, 103,
|
||||
165, 80, 67,
|
||||
123, 62, 49,
|
||||
489, 256, 191,
|
||||
81, 44, 31,
|
||||
483, 272, 181,
|
||||
60, 35, 22,
|
||||
53, 32, 19,
|
||||
237, 148, 83,
|
||||
471, 304, 161,
|
||||
3, 2, 1,
|
||||
459, 304, 161,
|
||||
38, 25, 14,
|
||||
453, 296, 175,
|
||||
225, 146, 91,
|
||||
149, 96, 63,
|
||||
111, 71, 49,
|
||||
63, 40, 29,
|
||||
73, 46, 35,
|
||||
435, 272, 217,
|
||||
108, 67, 56,
|
||||
13, 8, 7,
|
||||
213, 130, 119,
|
||||
423, 256, 245,
|
||||
5, 3, 3,
|
||||
281, 173, 162,
|
||||
141, 89, 78,
|
||||
283, 183, 150,
|
||||
71, 47, 36,
|
||||
285, 193, 138,
|
||||
13, 9, 6,
|
||||
41, 29, 18,
|
||||
36, 26, 15,
|
||||
289, 213, 114,
|
||||
145, 109, 54,
|
||||
291, 223, 102,
|
||||
73, 57, 24,
|
||||
293, 233, 90,
|
||||
21, 17, 6,
|
||||
295, 243, 78,
|
||||
37, 31, 9,
|
||||
27, 23, 6,
|
||||
149, 129, 30,
|
||||
299, 263, 54,
|
||||
75, 67, 12,
|
||||
43, 39, 6,
|
||||
151, 139, 18,
|
||||
303, 283, 30,
|
||||
38, 36, 3,
|
||||
305, 293, 18,
|
||||
153, 149, 6,
|
||||
307, 303, 6,
|
||||
1, 1, 0,
|
||||
101, 105, 2,
|
||||
49, 53, 2,
|
||||
95, 107, 6,
|
||||
23, 27, 2,
|
||||
89, 109, 10,
|
||||
43, 55, 6,
|
||||
83, 111, 14,
|
||||
5, 7, 1,
|
||||
172, 181, 37,
|
||||
97, 76, 22,
|
||||
72, 41, 17,
|
||||
119, 47, 29,
|
||||
4, 1, 1,
|
||||
4, 1, 1,
|
||||
4, 1, 1,
|
||||
4, 1, 1,
|
||||
4, 1, 1,
|
||||
4, 1, 1,
|
||||
4, 1, 1,
|
||||
4, 1, 1,
|
||||
4, 1, 1,
|
||||
65, 18, 17,
|
||||
95, 29, 26,
|
||||
185, 62, 53,
|
||||
30, 11, 9,
|
||||
35, 14, 11,
|
||||
85, 37, 28,
|
||||
55, 26, 19,
|
||||
80, 41, 29,
|
||||
155, 86, 59,
|
||||
5, 3, 2,
|
||||
5, 3, 2,
|
||||
5, 3, 2,
|
||||
5, 3, 2,
|
||||
5, 3, 2,
|
||||
5, 3, 2,
|
||||
5, 3, 2,
|
||||
5, 3, 2,
|
||||
5, 3, 2,
|
||||
5, 3, 2,
|
||||
5, 3, 2,
|
||||
5, 3, 2,
|
||||
5, 3, 2,
|
||||
305, 176, 119,
|
||||
155, 86, 59,
|
||||
105, 56, 39,
|
||||
80, 41, 29,
|
||||
65, 32, 23,
|
||||
55, 26, 19,
|
||||
335, 152, 113,
|
||||
85, 37, 28,
|
||||
115, 48, 37,
|
||||
35, 14, 11,
|
||||
355, 136, 109,
|
||||
30, 11, 9,
|
||||
365, 128, 107,
|
||||
185, 62, 53,
|
||||
25, 8, 7,
|
||||
95, 29, 26,
|
||||
385, 112, 103,
|
||||
65, 18, 17,
|
||||
395, 104, 101,
|
||||
4, 1, 1,
|
||||
4, 1, 1,
|
||||
395, 104, 101,
|
||||
65, 18, 17,
|
||||
385, 112, 103,
|
||||
95, 29, 26,
|
||||
25, 8, 7,
|
||||
185, 62, 53,
|
||||
365, 128, 107,
|
||||
30, 11, 9,
|
||||
355, 136, 109,
|
||||
35, 14, 11,
|
||||
115, 48, 37,
|
||||
85, 37, 28,
|
||||
335, 152, 113,
|
||||
55, 26, 19,
|
||||
65, 32, 23,
|
||||
80, 41, 29,
|
||||
105, 56, 39,
|
||||
155, 86, 59,
|
||||
305, 176, 119,
|
||||
5, 3, 2,
|
||||
5, 3, 2,
|
||||
5, 3, 2,
|
||||
5, 3, 2,
|
||||
5, 3, 2,
|
||||
5, 3, 2,
|
||||
5, 3, 2,
|
||||
5, 3, 2,
|
||||
5, 3, 2,
|
||||
5, 3, 2,
|
||||
5, 3, 2,
|
||||
5, 3, 2,
|
||||
5, 3, 2,
|
||||
155, 86, 59,
|
||||
80, 41, 29,
|
||||
55, 26, 19,
|
||||
85, 37, 28,
|
||||
35, 14, 11,
|
||||
30, 11, 9,
|
||||
185, 62, 53,
|
||||
95, 29, 26,
|
||||
65, 18, 17,
|
||||
4, 1, 1,
|
||||
4, 1, 1,
|
||||
4, 1, 1,
|
||||
4, 1, 1,
|
||||
4, 1, 1,
|
||||
4, 1, 1,
|
||||
4, 1, 1,
|
||||
4, 1, 1,
|
||||
4, 1, 1,
|
||||
119, 47, 29,
|
||||
72, 41, 17,
|
||||
97, 76, 22,
|
||||
172, 181, 37,
|
||||
5, 7, 1,
|
||||
83, 111, 14,
|
||||
43, 55, 6,
|
||||
89, 109, 10,
|
||||
23, 27, 2,
|
||||
95, 107, 6,
|
||||
49, 53, 2,
|
||||
101, 105, 2,
|
||||
1, 1, 0,
|
||||
307, 303, 6,
|
||||
153, 149, 6,
|
||||
305, 293, 18,
|
||||
38, 36, 3,
|
||||
303, 283, 30,
|
||||
151, 139, 18,
|
||||
43, 39, 6,
|
||||
75, 67, 12,
|
||||
299, 263, 54,
|
||||
149, 129, 30,
|
||||
27, 23, 6,
|
||||
37, 31, 9,
|
||||
295, 243, 78,
|
||||
21, 17, 6,
|
||||
293, 233, 90,
|
||||
73, 57, 24,
|
||||
291, 223, 102,
|
||||
145, 109, 54,
|
||||
289, 213, 114,
|
||||
36, 26, 15,
|
||||
41, 29, 18,
|
||||
13, 9, 6,
|
||||
285, 193, 138,
|
||||
71, 47, 36,
|
||||
283, 183, 150,
|
||||
141, 89, 78,
|
||||
281, 173, 162,
|
||||
5, 3, 3,
|
||||
423, 256, 245,
|
||||
213, 130, 119,
|
||||
13, 8, 7,
|
||||
108, 67, 56,
|
||||
435, 272, 217,
|
||||
73, 46, 35,
|
||||
63, 40, 29,
|
||||
111, 71, 49,
|
||||
149, 96, 63,
|
||||
225, 146, 91,
|
||||
453, 296, 175,
|
||||
38, 25, 14,
|
||||
459, 304, 161,
|
||||
3, 2, 1,
|
||||
471, 304, 161,
|
||||
237, 148, 83,
|
||||
53, 32, 19,
|
||||
60, 35, 22,
|
||||
483, 272, 181,
|
||||
81, 44, 31,
|
||||
489, 256, 191,
|
||||
123, 62, 49,
|
||||
165, 80, 67,
|
||||
249, 116, 103,
|
||||
501, 224, 211,
|
||||
7, 3, 3,
|
||||
43, 15, 20,
|
||||
22, 6, 11,
|
||||
15, 3, 8,
|
||||
23, 3, 13,
|
||||
47, 3, 28,
|
||||
8, 0, 5,
|
||||
7, 0, 4,
|
||||
21, 0, 10,
|
||||
13, 0, 5,
|
||||
13, 0, 5}
|
||||
local function process(tab)
|
||||
local tab2={}
|
||||
local function add(i)
|
||||
i=3*math.floor(i+.5)
|
||||
local c0,c1,c2=t[i+1],t[i+2],t[i+3]
|
||||
local norm=self.attenuation/(c0+c1+c2)
|
||||
table.insert(tab2,c0*norm)
|
||||
table.insert(tab2,c1*norm)
|
||||
table.insert(tab2,c2*norm)
|
||||
end
|
||||
local function level(i)
|
||||
return tab[i]*255/Color.ONE
|
||||
end
|
||||
local a,b,j=level(1),level(2),3
|
||||
for i=0,255 do
|
||||
if i>b then a,b,j=b,level(j),j+1; end
|
||||
add(255*(i-a)/(b-a))
|
||||
end
|
||||
return tab2
|
||||
end
|
||||
self._ostro = {r=process(self.levels.r),
|
||||
g=process(self.levels.g),
|
||||
b=process(self.levels.b)}
|
||||
end
|
||||
local i = math.floor(linearLevel[rgb]*255/Color.ONE+.5)
|
||||
i = 3*(i<0 and 0 or i>255 and 255 or i)
|
||||
return self._ostro[rgb][i+1],self._ostro[rgb][i+2],self._ostro[rgb][i+3]
|
||||
end
|
||||
|
||||
function OstroDither:_linearPalette(colorIndex)
|
||||
if self._linear==nil then
|
||||
self._linear = {}
|
||||
local t=thomson.levels.linear
|
||||
for i,pal in ipairs(self.palette) do
|
||||
local r,g,b=pal%16,math.floor(pal/16)%16,math.floor(pal/256)
|
||||
self._linear[i] = Color:new(t[1+r],t[1+g],t[1+b])
|
||||
end
|
||||
end
|
||||
return self._linear[colorIndex]
|
||||
end
|
||||
|
||||
function OstroDither:getColorIndex(linearPixel)
|
||||
local k=linearPixel:hash(64)
|
||||
local c=self[k]
|
||||
if c==nil then
|
||||
local dm=1e30
|
||||
for i=1,#self.palette do
|
||||
local d = self:_linearPalette(i):dist2(linearPixel)
|
||||
if d<dm then dm,c=d,i end
|
||||
end
|
||||
self[k] = c
|
||||
end
|
||||
return c
|
||||
end
|
||||
|
||||
function OstroDither:_diffuse(linearColor,err, err0,err1,err2)
|
||||
local c=self:getColorIndex(err:add(linearColor))
|
||||
local M = Color.ONE
|
||||
|
||||
err:sub(self:_linearPalette(c))
|
||||
local function d(rgb)
|
||||
local e = err[rgb]
|
||||
function f(a,c)
|
||||
a=a+c*e
|
||||
return a<-M and -M or
|
||||
a> M and M or a
|
||||
end
|
||||
local c0,c1,c2=self:_coefs(linearColor,rgb)
|
||||
if err0 and c0>0 then err0[rgb] = f(err0[rgb],c0) end
|
||||
if err1 and c1>0 then err1[rgb] = f(err1[rgb],c1) end
|
||||
if err2 and c2>0 then err2[rgb] = f(err2[rgb],c2) end
|
||||
end
|
||||
d("r"); d("g"); d("b")
|
||||
|
||||
return c
|
||||
end
|
||||
|
||||
function OstroDither:dither(screen_w,screen_h,getLinearPixel,pset,serpentine,info)
|
||||
if not info then info = function(y) thomson.info() end end
|
||||
if not serpentine then serpentine = true end
|
||||
|
||||
local err1,err2 = {},{}
|
||||
for x=-1,screen_w do
|
||||
err1[x] = Color:new(0,0,0)
|
||||
err2[x] = Color:new(0,0,0)
|
||||
end
|
||||
|
||||
for y=0,screen_h-1 do
|
||||
-- permute error buffers
|
||||
err1,err2 = err2,err1
|
||||
-- clear current-row's buffer
|
||||
for i=-1,screen_w do err2[i]:mul(0) end
|
||||
|
||||
local x0,x1,xs=0,screen_w-1,1
|
||||
if serpentine and y%2==1 then x0,x1,xs=x1,x0,-xs end
|
||||
|
||||
for x=x0,x1,xs do
|
||||
local p = getLinearPixel(x,y,xs,err1)
|
||||
local c = self:_diffuse(p,err1[x],err1[x+xs],
|
||||
err2[x-xs],err2[x])
|
||||
pset(x,y,c-1)
|
||||
end
|
||||
info(y)
|
||||
end
|
||||
end
|
||||
|
||||
function OstroDither:ccAcceptCouple(c1,c2)
|
||||
return c1~=c2
|
||||
end
|
||||
|
||||
function OstroDither:ccDither(screen_w,screen_h,getLinearPixel,pset,serpentine,info) -- dither with color clash
|
||||
local c1,c2
|
||||
self.getColorIndex = function(self,p)
|
||||
return p:dist2(self:_linearPalette(c1))<p:dist2(self:_linearPalette(c2)) and c1 or c2
|
||||
end
|
||||
|
||||
local function _pset(x,y,c)
|
||||
pset(x,y,c==c1-1 and c or -c2)
|
||||
end
|
||||
|
||||
local findC1C2 = function(x,y,xs,err1)
|
||||
-- collect the data we are working on
|
||||
local gpl = {
|
||||
clone = function(self)
|
||||
local r={}
|
||||
for i,v in ipairs(self) do
|
||||
r[i] = {pix=v.pix:clone(),
|
||||
err=v.err:clone()}
|
||||
end
|
||||
return r
|
||||
end,
|
||||
fill = function(self,dither)
|
||||
for i=x,x+(dither.clash_size-1)*xs,xs do
|
||||
table.insert(self,
|
||||
{pix=getLinearPixel(i,y),
|
||||
err=err1[i]})
|
||||
end
|
||||
table.insert(self, {pix=Color:new(),
|
||||
err=Color:new()})
|
||||
end
|
||||
}
|
||||
gpl:fill(self)
|
||||
|
||||
local histo = {
|
||||
fill = function(self,dither)
|
||||
local t=gpl:clone()
|
||||
for i=1,#dither.palette do self[i] = {n=0,c=i} end
|
||||
local back = dither.getColorIndex
|
||||
dither.getColorIndex = OstroDither.getColorIndex
|
||||
for i=1,dither.clash_size do
|
||||
local c = dither:_diffuse(t[i].pix,t[i].err,
|
||||
t[i+1].err)
|
||||
self[c].n = self[c].n+1
|
||||
end
|
||||
dither.getColorIndex = back
|
||||
table.sort(self, function(a,b)
|
||||
return a.n>b.n or a.n==b.n and a.c<b.c end)
|
||||
end,
|
||||
get = function(self,i,...)
|
||||
if i then
|
||||
return self[i].c,self:get(...)
|
||||
end
|
||||
end,
|
||||
num = function(self,i,...)
|
||||
if i then
|
||||
return self[i].n,self:num(...)
|
||||
end
|
||||
end,
|
||||
sum = function(self,i,...)
|
||||
return i and self[i].n+self:sum(...) or 0
|
||||
end
|
||||
}
|
||||
histo:fill(self)
|
||||
|
||||
c1,c2=histo:get(1,2)
|
||||
|
||||
if not self:ccAcceptCouple(c1,c2) or histo:sum(1,2)<=self.clash_size-2 then
|
||||
info(y)
|
||||
local dm=1e30
|
||||
local function eval()
|
||||
if self:ccAcceptCouple(c1,c2) then
|
||||
local d,t = 0,gpl:clone()
|
||||
for i=1,self.clash_size do
|
||||
local err=t[i].err
|
||||
self:_diffuse(t[i].pix,err,t[i+1].err)
|
||||
d = d + err.r^2 + err.g^2 + err.b^2
|
||||
if d>dm then break end
|
||||
end
|
||||
return d
|
||||
else
|
||||
return dm
|
||||
end
|
||||
end
|
||||
dm=eval()
|
||||
|
||||
if histo:num(1)>=self.clash_size/2+1 then
|
||||
local z=c2
|
||||
for i=1,#self.palette do c2=i
|
||||
local d=eval()
|
||||
if d<dm then dm,z=d,i end
|
||||
end
|
||||
c2=z
|
||||
else
|
||||
local a,b=c1,c2
|
||||
for i=1,#self.palette-1 do c1=i
|
||||
for j=1+i,#self.palette do c2=j
|
||||
local d=eval()
|
||||
if d<dm then dm,a,b=d,i,j end
|
||||
end
|
||||
end
|
||||
c1,c2=a,b
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function _getLinearPixel(x,y,xs,err1)
|
||||
if x%self.clash_size==(xs>0 and 0 or self.clash_size-1) then
|
||||
findC1C2(x,y,xs,err1)
|
||||
end
|
||||
return getLinearPixel(x,y)
|
||||
end
|
||||
|
||||
self:dither(screen_w,screen_h,_getLinearPixel,_pset,serpentine,info)
|
||||
end
|
||||
|
||||
function OstroDither:dither40cols(getpalette,serpentine)
|
||||
-- get screen size
|
||||
local screen_w, screen_h = getpicturesize()
|
||||
|
||||
-- Converts thomson coordinates (0-159,0-199) into screen coordinates
|
||||
local function thom2screen(x,y)
|
||||
local i,j;
|
||||
if screen_w/screen_h < 1.6 then
|
||||
i = x*screen_h/200
|
||||
j = y*screen_h/200
|
||||
else
|
||||
i = x*screen_w/320
|
||||
j = y*screen_w/320
|
||||
end
|
||||
return math.floor(i), math.floor(j)
|
||||
end
|
||||
|
||||
-- return the Color @(x,y) in linear space (0-255)
|
||||
-- corresonding to the thomson screen (x in 0-319,
|
||||
-- y in 0-199)
|
||||
local function getLinearPixel(x,y)
|
||||
local with_cache = true
|
||||
if not self._getLinearPixel then self._getLinearPixel = {} end
|
||||
local k=x+y*thomson.w
|
||||
local p = self._getLinearPixel[k]
|
||||
if not p then
|
||||
local x1,y1 = thom2screen(x,y)
|
||||
local x2,y2 = thom2screen(x+1,y+1)
|
||||
if x2==x1 then x2=x1+1 end
|
||||
if y2==y1 then y2=y1+1 end
|
||||
|
||||
p = Color:new(0,0,0);
|
||||
for j=y1,y2-1 do
|
||||
for i=x1,x2-1 do
|
||||
p:add(getLinearPictureColor(i,j))
|
||||
end
|
||||
end
|
||||
p:div((y2-y1)*(x2-x1)) --:floor()
|
||||
|
||||
if with_cache then self._getLinearPixel[k]=p end
|
||||
end
|
||||
|
||||
return with_cache and p:clone() or p
|
||||
end
|
||||
|
||||
-- MO5 mode
|
||||
thomson.setMO5()
|
||||
self.palette = getpalette(thomson.w,thomson.h,getLinearPixel)
|
||||
|
||||
-- compute levels from palette
|
||||
self:setLevelsFromPalette()
|
||||
|
||||
-- convert picture
|
||||
self:ccDither(thomson.w,thomson.h,
|
||||
getLinearPixel, thomson.pset,
|
||||
serpentine or true, function(y)
|
||||
thomson.info("Converting...",
|
||||
math.floor(y*100/thomson.h),"%")
|
||||
end,true)
|
||||
|
||||
-- refresh screen
|
||||
setpicturesize(thomson.w,thomson.h)
|
||||
thomson.updatescreen()
|
||||
thomson.savep()
|
||||
finalizepicture()
|
||||
end
|
||||
|
||||
end -- OstroDither
|
||||
454
share/grafx2/scripts/samples/picture/thomson/lib/thomson.lua
Normal file
454
share/grafx2/scripts/samples/picture/thomson/lib/thomson.lua
Normal file
@@ -0,0 +1,454 @@
|
||||
-- thomson.lua : lots of utility for handling
|
||||
-- thomson screen.
|
||||
--
|
||||
-- Version: 02-jan-2017
|
||||
--
|
||||
-- Copyright 2016-2017 by Samuel Devulder
|
||||
--
|
||||
-- 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/>
|
||||
|
||||
if not thomson then
|
||||
|
||||
run("color.lua") -- optionnal
|
||||
|
||||
thomson = {optiMAP=true}
|
||||
|
||||
-- RAM banks
|
||||
thomson.ramA = {}
|
||||
thomson.ramB = {}
|
||||
|
||||
function thomson.clear()
|
||||
for i=1,8000 do
|
||||
thomson.ramA[i] = 0
|
||||
thomson.ramB[i] = 0
|
||||
end
|
||||
end
|
||||
|
||||
-- color levels
|
||||
thomson.levels = {
|
||||
-- in pc-space (0-255):
|
||||
pc = {0,100,127,142,163,179,191,203,215,223,231,239,
|
||||
243,247,251,255},
|
||||
-- in linear space (0-255):
|
||||
linear = {},
|
||||
-- maps pc-levels (0-255) to thomson levels (1-16)
|
||||
pc2to={},
|
||||
-- maps linear-levels (0-255) to thomson levels (1-16)
|
||||
linear2to={}
|
||||
};
|
||||
|
||||
-- pc space to linear space
|
||||
local function toLinear(val)
|
||||
-- use the version from Color library
|
||||
if not Color then
|
||||
val = val/255
|
||||
if val<=0.081 then
|
||||
val = val/4.5;
|
||||
else
|
||||
val = ((val+0.099)/1.099)^2.2;
|
||||
end
|
||||
val = val*255
|
||||
return val;
|
||||
else
|
||||
return Color:new(val,0,0):toLinear().r
|
||||
end
|
||||
end
|
||||
|
||||
for i=1,16 do
|
||||
thomson.levels.linear[i] = toLinear(thomson.levels.pc[i])
|
||||
end
|
||||
for i=0,255 do
|
||||
local r,cm,dm;
|
||||
r,cm,dm = toLinear(i),0,1e30
|
||||
for c,v in ipairs(thomson.levels.linear) do
|
||||
local d = math.abs(v-r);
|
||||
if d<dm then cm,dm = c,d; end
|
||||
end
|
||||
thomson.levels.pc2to[i] = cm;
|
||||
r,cm,dm = i,0,1e30
|
||||
for c,v in ipairs(thomson.levels.linear) do
|
||||
local d = math.abs(v-r);
|
||||
if d<dm then cm,dm = c,d; end
|
||||
end
|
||||
thomson.levels.linear2to[i] = cm;
|
||||
end
|
||||
|
||||
-- palette stuff
|
||||
function thomson.palette(i, pal)
|
||||
-- returns palette #i if pal is missing (nil)
|
||||
-- if pal is a number, sets palette #i
|
||||
-- if pal is an array, sets the palette #i, #i+1, ...
|
||||
if type(pal)=='table' then
|
||||
for j,v in ipairs(pal) do
|
||||
thomson.palette(i+j-1,v)
|
||||
end
|
||||
elseif pal and i>=0 and i<thomson._palette.max then
|
||||
thomson._palette[i+1] = pal
|
||||
elseif not pal and i>=0 and i<thomson._palette.max then
|
||||
return thomson._palette[i+1]
|
||||
end
|
||||
end;
|
||||
thomson._palette = {offset = 0, max=16}
|
||||
thomson.default_palette = {0,15,240,255,3840,3855,4080,4095,
|
||||
1911,826,931,938,2611,2618,3815,123}
|
||||
|
||||
-- border color
|
||||
function thomson.border(c)
|
||||
if c then
|
||||
thomson._border = c;
|
||||
else
|
||||
return thomson._border
|
||||
end
|
||||
end
|
||||
thomson.border(0)
|
||||
|
||||
-- helper to appen tables to tables
|
||||
function thomson._append(result, ...)
|
||||
for _,tab in ipairs({...}) do
|
||||
for _,v in ipairs(tab) do
|
||||
table.insert(result,v)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- RLE compression of data into result
|
||||
function thomson._compress(result,data)
|
||||
local partial,p,pmax={},1,#data
|
||||
local function addCarToPartial(car)
|
||||
partial[2] = partial[2]+1
|
||||
partial[2+partial[2]] = car
|
||||
end
|
||||
while p<=pmax do
|
||||
local num,car = 1,data[p]
|
||||
while num<255 and p<pmax and data[p+1]==car do
|
||||
num,p = num+1,p+1
|
||||
end
|
||||
local default=true
|
||||
if partial[1] then
|
||||
-- 01 aa 01 bb ==> 00 02 aa bb
|
||||
if default and num==1 and partial[1]==1 then
|
||||
partial = {0,2,partial[2],car}
|
||||
default = false
|
||||
end
|
||||
-- 00 n xx xx xx 01 bb ==> 00 n+1 xx xx xx bb
|
||||
if default and num==1 and partial[1]==0 and partial[2]<255 then
|
||||
addCarToPartial(car)
|
||||
default = false
|
||||
end
|
||||
-- 00 n xx xx xx 02 bb ==> 00 n+2 xx xx xx bb bb (pas utile mais sert quand combiné à la regle ci-dessus)
|
||||
if default and num==2 and partial[1]==0 and partial[2]<254 then
|
||||
addCarToPartial(car)
|
||||
addCarToPartial(car)
|
||||
default = false
|
||||
end
|
||||
end
|
||||
if default then
|
||||
thomson._append(result, partial)
|
||||
partial = {num,car}
|
||||
end
|
||||
p=p+1
|
||||
end
|
||||
thomson._append(result, partial)
|
||||
return result
|
||||
end
|
||||
|
||||
-- save a map file corresponging to the current file
|
||||
-- if a map file already exist, a confirmation is
|
||||
-- prompted to the user
|
||||
local function save_current_file()
|
||||
local function exist(file)
|
||||
local f=io.open(file,'rb')
|
||||
if not f then return false else io.close(f); return true; end
|
||||
end
|
||||
local name,path = getfilename()
|
||||
local mapname = string.gsub(name,"%.%w*$","") .. ".map"
|
||||
local fullname = path .. '/' .. mapname
|
||||
local ok = not exist(fullname)
|
||||
if not ok then
|
||||
selectbox("Ovr " .. mapname .. "?", "Yes", function() ok = true; end, "No", function() ok = false; end)
|
||||
end
|
||||
if ok then thomson.savep(fullname) end
|
||||
end
|
||||
|
||||
-- saves the thomson screen into a MAP file
|
||||
function thomson.savep(name)
|
||||
if not name then return save_current_file() end
|
||||
|
||||
wait(0) -- allow for key handling
|
||||
local data = thomson._get_map_data()
|
||||
local tmp = {0, math.floor(#data/256), #data%256,0,0}
|
||||
thomson._append(tmp,data,{255,0,0,0,0})
|
||||
local function save(name, buf)
|
||||
local out = io.open(name,"wb")
|
||||
out:write(buf)
|
||||
out:close()
|
||||
end
|
||||
save(name, string.char(unpack(tmp)))
|
||||
|
||||
-- save raw data as well ?
|
||||
local moved, key, mx, my, mb = waitinput(0.01)
|
||||
if key==4123 then -- shift-ESC ==> save raw files as well
|
||||
save(name .. ".rama", string.char(unpack(thomson.ramA)))
|
||||
save(name .. ".ramb", string.char(unpack(thomson.ramB)))
|
||||
local pal = ""
|
||||
for i=0,15 do
|
||||
local val = thomson.palette(i)
|
||||
pal=pal..string.char(math.floor(val/256),val%256)
|
||||
end
|
||||
save(name .. ".pal", pal)
|
||||
messagebox('Saved MAP + RAMA/RAMB/PAL files.')
|
||||
end
|
||||
end
|
||||
waitbreak(0.01)
|
||||
|
||||
function thomson.info(...)
|
||||
local txt = ""
|
||||
for _,t in ipairs({...}) do txt = txt .. t end
|
||||
statusmessage(txt);
|
||||
if waitbreak(0)==1 then
|
||||
local ok=false
|
||||
selectbox("Abort ?", "Yes", function() ok = true end, "No", function() ok = false end)
|
||||
if ok then error('Operation aborted') end
|
||||
end
|
||||
end
|
||||
|
||||
-- copy ramA/B onto GrafX2 screen
|
||||
function thomson.updatescreen()
|
||||
-- back out
|
||||
for i=0,255 do
|
||||
setcolor(i,0,0,0)
|
||||
end
|
||||
-- refresh screen content
|
||||
clearpicture(thomson._palette.offset + thomson.border())
|
||||
for y=0,thomson.h-1 do
|
||||
for x=0,thomson.w-1 do
|
||||
local p = thomson.point(x,y)
|
||||
if p<0 then p=-p-1 end
|
||||
thomson._putpixel(x,y,thomson._palette.offset + p)
|
||||
end
|
||||
end
|
||||
-- refresh palette
|
||||
for i=1,thomson._palette.max do
|
||||
local v=thomson._palette[i]
|
||||
local r=v % 16
|
||||
local g=math.floor(v/16) % 16
|
||||
local b=math.floor(v/256) % 16
|
||||
setcolor(i+thomson._palette.offset-1,
|
||||
thomson.levels.pc[r+1],
|
||||
thomson.levels.pc[g+1],
|
||||
thomson.levels.pc[b+1])
|
||||
end
|
||||
updatescreen()
|
||||
end
|
||||
|
||||
-- bitmap 16 mode
|
||||
function thomson.setBM16()
|
||||
-- put a pixel onto real screen
|
||||
function thomson._putpixel(x,y,c)
|
||||
putpicturepixel(x*2+0,y,c)
|
||||
putpicturepixel(x*2+1,y,c)
|
||||
end
|
||||
-- put a pixel in thomson screen
|
||||
function thomson.pset(x,y,c)
|
||||
local bank = x%4<2 and thomson.ramA or thomson.ramB
|
||||
local offs = math.floor(x/4)+y*40+1
|
||||
if x%2==0 then
|
||||
bank[offs] = (bank[offs]%16)+c*16
|
||||
else
|
||||
bank[offs] = math.floor(bank[offs]/16)*16+c
|
||||
end
|
||||
-- c=c+thomson._palette.offset
|
||||
-- putpicturepixel(x*2+0,y,c)
|
||||
-- putpicturepixel(x*2+1,y,c)
|
||||
end
|
||||
-- get thomson pixel at (x,y)
|
||||
function thomson.point(x,y)
|
||||
local bank = x%4<2 and thomson.ramA or thomson.ramB
|
||||
local offs = math.floor(x/4)+y*40+1
|
||||
if x%2==0 then
|
||||
return math.floor(bank[offs]/16)
|
||||
else
|
||||
return bank[offs]%16
|
||||
end
|
||||
end
|
||||
-- return internal MAP file
|
||||
function thomson._get_map_data()
|
||||
local tmp = {}
|
||||
for x=1,40 do
|
||||
for y=x,x+7960,40 do
|
||||
table.insert(tmp, thomson.ramA[y])
|
||||
end
|
||||
for y=x,x+7960,40 do
|
||||
table.insert(tmp, thomson.ramB[y])
|
||||
end
|
||||
wait(0) -- allow for key handling
|
||||
end
|
||||
local pal = {}
|
||||
for i=1,16 do
|
||||
pal[2*i-1] = math.floor(thomson._palette[i]/256)
|
||||
pal[2*i+0] = thomson._palette[i]%256
|
||||
end
|
||||
-- build data
|
||||
local data={
|
||||
-- BM16
|
||||
0x40,
|
||||
-- ncols-1
|
||||
79,
|
||||
-- nlines-1
|
||||
24
|
||||
};
|
||||
thomson._compress(data, tmp)
|
||||
thomson._append(data,{0,0})
|
||||
-- padd to word
|
||||
if #data%2==1 then table.insert(data,0); end
|
||||
-- tosnap
|
||||
thomson._append(data,{0,128,0,thomson.border(),0,3})
|
||||
thomson._append(data, pal)
|
||||
thomson._append(data,{0xa5,0x5a})
|
||||
return data
|
||||
end
|
||||
|
||||
thomson.w = 160
|
||||
thomson.h = 200
|
||||
thomson.palette(0,thomson.default_palette)
|
||||
thomson.border(0)
|
||||
thomson.clear()
|
||||
end
|
||||
|
||||
-- mode MO5
|
||||
function thomson.setMO5()
|
||||
-- put a pixel onto real screen
|
||||
thomson._putpixel = putpicturepixel
|
||||
-- helpers
|
||||
local function bittst(val,mask)
|
||||
-- return bit32.btest(val,mask)
|
||||
return (val % (2*mask))>=mask;
|
||||
end
|
||||
local function bitset(val,mask)
|
||||
-- return bit32.bor(val, mask)
|
||||
return bittst(val,mask) and val or (val+mask)
|
||||
end
|
||||
local function bitclr(val,mask)
|
||||
-- return bit32.band(val,255-mask)
|
||||
return bittst(val,mask) and (val-mask) or val
|
||||
end
|
||||
-- put a pixel in thomson screen
|
||||
function thomson.pset(x,y,c)
|
||||
local offs = math.floor(x/8)+y*40+1
|
||||
local mask = 2^(7-(x%8))
|
||||
if c>=0 then
|
||||
thomson.ramB[offs] = (thomson.ramB[offs]%16)+c*16
|
||||
thomson.ramA[offs] = bitset(thomson.ramA[offs],mask)
|
||||
else
|
||||
c=-c-1
|
||||
thomson.ramB[offs] = math.floor(thomson.ramB[offs]/16)*16+c
|
||||
thomson.ramA[offs] = bitclr(thomson.ramA[offs],mask)
|
||||
end
|
||||
end
|
||||
-- get thomson pixel at (x,y)
|
||||
function thomson.point(x,y)
|
||||
local offs = math.floor(x/8)+y*40+1
|
||||
local mask = 2^(7-(x%8))
|
||||
if bittst(thomson.ramA[offs],mask) then
|
||||
return math.floor(thomson.ramB[offs]/16)
|
||||
else
|
||||
return -(thomson.ramB[offs]%16)-1
|
||||
end
|
||||
end
|
||||
-- convert color from MO5 to TO7 (MAP requires TO7 encoding)
|
||||
local function mo5to7(val)
|
||||
-- MO5: DCBA 4321
|
||||
-- __
|
||||
-- TO7: 4DCB A321
|
||||
local t=((val%16)>=8) and 0 or 128
|
||||
val = math.floor(val/16)*8 + (val%8)
|
||||
val = (val>=64 and val-64 or val+64) + t
|
||||
return val
|
||||
end
|
||||
-- return internal MAP file
|
||||
function thomson._get_map_data()
|
||||
-- create columnwise data
|
||||
local tmpA,tmpB={},{};
|
||||
for x=1,40 do
|
||||
for y=x,x+7960,40 do
|
||||
table.insert(tmpA, thomson.ramA[y])
|
||||
table.insert(tmpB, thomson.ramB[y])
|
||||
end
|
||||
wait(0) -- allow for key handling
|
||||
end
|
||||
if thomson.optiMAP then
|
||||
-- optimize
|
||||
for i=2,8000 do
|
||||
local c1,c2 = math.floor(tmpB[i-0]/16),tmpB[i-0]%16
|
||||
local d1,d2 = math.floor(tmpB[i-1]/16),tmpB[i-1]%16
|
||||
|
||||
if tmpA[i-1]==255-tmpA[i] or c1==d2 and c2==c1 then
|
||||
tmpA[i] = 255-tmpA[i]
|
||||
tmpB[i] = c2*16+c1
|
||||
elseif tmpA[i]==255 and c1==d1 or tmpA[i]==0 and c2==d2 then
|
||||
tmpB[i] = tmpB[i-1]
|
||||
end
|
||||
end
|
||||
else
|
||||
for i=1,8000 do
|
||||
local c1,c2 = math.floor(tmpB[i]/16),tmpB[i]%16
|
||||
|
||||
if tmpA[i]==255 or c1<c2 then
|
||||
tmpA[i] = 255-tmpA[i]
|
||||
tmpB[i] = c2*16+c1
|
||||
end
|
||||
end
|
||||
end
|
||||
-- convert into to7 encoding
|
||||
for i=1,#tmpB do tmpB[i] = mo5to7(tmpB[i]); end
|
||||
-- build data
|
||||
local data={
|
||||
-- BM40
|
||||
0x00,
|
||||
-- ncols-1
|
||||
39,
|
||||
-- nlines-1
|
||||
24
|
||||
};
|
||||
thomson._compress(data, tmpA); tmpA=nil;
|
||||
thomson._append(data,{0,0})
|
||||
thomson._compress(data, tmpB); tmpB=nil;
|
||||
thomson._append(data,{0,0})
|
||||
-- padd to word (for compatibility with basic)
|
||||
if #data%2==1 then table.insert(data,0); end
|
||||
|
||||
-- tosnap
|
||||
local orig_palette = true
|
||||
for i=0,15 do
|
||||
if thomson.default_palette[i+1]~=thomson.palette(i) then
|
||||
orig_palette = false
|
||||
break
|
||||
end
|
||||
end
|
||||
if not orig_palette then
|
||||
local pal = {}
|
||||
for i=0,15 do
|
||||
local v = thomson.palette(i)
|
||||
pal[2*i+1] = math.floor(v/256)
|
||||
pal[2*i+2] = v%256
|
||||
end
|
||||
thomson._append(data,{0,0,0,thomson.border(),0,0})
|
||||
thomson._append(data, pal)
|
||||
thomson._append(data,{0xa5,0x5a})
|
||||
end
|
||||
|
||||
return data
|
||||
end
|
||||
|
||||
thomson.w = 320
|
||||
thomson.h = 200
|
||||
thomson.palette(0,thomson.default_palette)
|
||||
thomson.border(0)
|
||||
thomson.clear()
|
||||
end
|
||||
|
||||
end -- thomson
|
||||
27
share/grafx2/scripts/samples/picture/thomson/none_mo5.lua
Normal file
27
share/grafx2/scripts/samples/picture/thomson/none_mo5.lua
Normal file
@@ -0,0 +1,27 @@
|
||||
-- ostro_mo5.lua : converts a color image into a
|
||||
-- MO5 image (16 fixed colors with color clash)
|
||||
-- using Ostromoukhov's error diffusion algorithm.
|
||||
--
|
||||
-- Version: 02-jan-2017
|
||||
--
|
||||
-- Copyright 2016-2017 by Samuel Devulder
|
||||
--
|
||||
-- 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('lib/ostromoukhov.lua')
|
||||
|
||||
local dith=OstroDither:new()
|
||||
local tmp=dith.setLevelsFromPalette
|
||||
dith.setLevelsFromPalette = function(self)
|
||||
tmp(self)
|
||||
self.attenuation=0
|
||||
end
|
||||
dith:dither40cols(function(w,h,getLinearPixel)
|
||||
local pal={}
|
||||
for i=0,15 do pal[i+1] = thomson.palette(i) end
|
||||
return pal
|
||||
end)
|
||||
82
share/grafx2/scripts/samples/picture/thomson/none_to8.lua
Normal file
82
share/grafx2/scripts/samples/picture/thomson/none_to8.lua
Normal file
@@ -0,0 +1,82 @@
|
||||
-- ostro_to8.lua : convert a color image to a BM16
|
||||
-- (160x200x16) thomson image using the Ostromoukhov's
|
||||
-- error diffusion algorithm.
|
||||
--
|
||||
-- Version: 02-jan-2017
|
||||
--
|
||||
-- Copyright 2016-2017 by Samuel Devulder
|
||||
--
|
||||
-- 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('lib/thomson.lua')
|
||||
run('lib/ostromoukhov.lua')
|
||||
run('lib/color_reduction.lua')
|
||||
-- run('lib/zzz.lua')
|
||||
|
||||
-- get screen size
|
||||
local screen_w, screen_h = getpicturesize()
|
||||
|
||||
-- Converts thomson coordinates (0-159,0-199) into screen coordinates
|
||||
local function thom2screen(x,y)
|
||||
local i,j;
|
||||
if screen_w/screen_h < 1.6 then
|
||||
i = x*screen_h/200
|
||||
j = y*screen_h/200
|
||||
else
|
||||
i = x*screen_w/320
|
||||
j = y*screen_w/320
|
||||
end
|
||||
return math.floor(i*2), math.floor(j)
|
||||
end
|
||||
|
||||
-- return the Color @(x,y) in normalized linear space (0-1)
|
||||
-- corresonding to the thomson screen (x in 0-319, y in 0-199)
|
||||
local function getLinearPixel(x,y)
|
||||
local x1,y1 = thom2screen(x,y)
|
||||
local x2,y2 = thom2screen(x+1,y+1)
|
||||
if x2==x1 then x2=x1+1 end
|
||||
if y2==y1 then y2=y1+1 end
|
||||
|
||||
local p = Color:new(0,0,0);
|
||||
for j=y1,y2-1 do
|
||||
for i=x1,x2-1 do
|
||||
p:add(getLinearPictureColor(i,j))
|
||||
end
|
||||
end
|
||||
p:div((y2-y1)*(x2-x1)) --:floor()
|
||||
|
||||
return p
|
||||
end
|
||||
|
||||
local red = ColorReducer:new():analyzeWithDither(160,200,
|
||||
getLinearPixel,
|
||||
function(y)
|
||||
thomson.info("Collecting stats...",math.floor(y/2),"%")
|
||||
end)
|
||||
|
||||
-- BM16 mode
|
||||
thomson.setBM16()
|
||||
|
||||
-- define palette
|
||||
local palette = red:boostBorderColors():buildPalette(16)
|
||||
thomson.palette(0, palette)
|
||||
|
||||
-- convert picture
|
||||
OstroDither:new(palette, 0)
|
||||
:dither(thomson.h,thomson.w,
|
||||
function(y,x) return getLinearPixel(x,y) end,
|
||||
function(y,x,c) thomson.pset(x,y,c) end,
|
||||
true,
|
||||
function(x) thomson.info("Converting...",math.floor(x*100/160),"%") end)
|
||||
|
||||
-- refresh screen
|
||||
setpicturesize(320,200)
|
||||
thomson.updatescreen()
|
||||
finalizepicture()
|
||||
|
||||
-- save picture
|
||||
thomson.savep()
|
||||
55
share/grafx2/scripts/samples/picture/thomson/none_to9.lua
Normal file
55
share/grafx2/scripts/samples/picture/thomson/none_to9.lua
Normal file
@@ -0,0 +1,55 @@
|
||||
-- ostro_mo5.lua : converts a color image into a
|
||||
-- TO9 image (320x200x16 with color clashes)
|
||||
-- using Ostromoukhov's error diffusion algorithm.
|
||||
--
|
||||
-- Version: 02-jan-2017
|
||||
--
|
||||
-- Copyright 2016-2017 by Samuel Devulder
|
||||
--
|
||||
-- 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('lib/thomson.lua')
|
||||
thomson.optiMAP = false
|
||||
|
||||
run('lib/ostromoukhov.lua')
|
||||
run('lib/color_reduction.lua')
|
||||
|
||||
local dith=OstroDither:new()
|
||||
local tmp=dith.setLevelsFromPalette
|
||||
dith.setLevelsFromPalette = function(self)
|
||||
tmp(self)
|
||||
self.attenuation=0
|
||||
end
|
||||
dith:dither40cols(function(w,h,getLinearPixel)
|
||||
local c16 = true
|
||||
for y=0,h-1 do
|
||||
for x=0,w-1 do
|
||||
if getbackuppixel(x,y)>15 then c16 = false end
|
||||
end
|
||||
end
|
||||
|
||||
local pal
|
||||
if c16 then
|
||||
pal = {}
|
||||
for i=0,15 do
|
||||
local r,g,b=getbackupcolor(i)
|
||||
r = thomson.levels.pc2to[r]
|
||||
g = thomson.levels.pc2to[g]
|
||||
b = thomson.levels.pc2to[b]
|
||||
pal[i+1] = r+g*16+b*256-273
|
||||
end
|
||||
else
|
||||
pal=ColorReducer:new():analyzeWithDither(w,h,
|
||||
getLinearPixel,
|
||||
function(y)
|
||||
thomson.info("Building palette...",math.floor(y*100/h),"%")
|
||||
end):buildPalette(16)
|
||||
end
|
||||
thomson.palette(0, pal)
|
||||
|
||||
return pal
|
||||
end)
|
||||
21
share/grafx2/scripts/samples/picture/thomson/ostro_mo5.lua
Normal file
21
share/grafx2/scripts/samples/picture/thomson/ostro_mo5.lua
Normal file
@@ -0,0 +1,21 @@
|
||||
-- ostro_mo5.lua : converts a color image into a
|
||||
-- MO5 image (16 fixed colors with color clash)
|
||||
-- using Ostromoukhov's error diffusion algorithm.
|
||||
--
|
||||
-- Version: 02-jan-2017
|
||||
--
|
||||
-- Copyright 2016-2017 by Samuel Devulder
|
||||
--
|
||||
-- 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('lib/ostromoukhov.lua')
|
||||
|
||||
OstroDither:new():dither40cols(function(w,h,getLinearPixel)
|
||||
local pal={}
|
||||
for i=0,15 do pal[i+1] = thomson.palette(i) end
|
||||
return pal
|
||||
end)
|
||||
21
share/grafx2/scripts/samples/picture/thomson/ostro_to7.lua
Normal file
21
share/grafx2/scripts/samples/picture/thomson/ostro_to7.lua
Normal file
@@ -0,0 +1,21 @@
|
||||
-- ostro_mo5.lua : converts a color image into a
|
||||
-- TO7 image (8 fixed colors with color clash)
|
||||
-- using Ostromoukhov's error diffusion algorithm.
|
||||
--
|
||||
-- Version: 02-jan-2017
|
||||
--
|
||||
-- Copyright 2016-2017 by Samuel Devulder
|
||||
--
|
||||
-- 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('lib/ostromoukhov.lua')
|
||||
|
||||
OstroDither:new():dither40cols(function(w,h,getLinearPixel)
|
||||
local pal={}
|
||||
for i=0,7 do pal[i+1] = thomson.palette(i) end
|
||||
return pal
|
||||
end)
|
||||
82
share/grafx2/scripts/samples/picture/thomson/ostro_to8.lua
Normal file
82
share/grafx2/scripts/samples/picture/thomson/ostro_to8.lua
Normal file
@@ -0,0 +1,82 @@
|
||||
-- ostro_to8.lua : convert a color image to a BM16
|
||||
-- (160x200x16) thomson image using the Ostromoukhov's
|
||||
-- error diffusion algorithm.
|
||||
--
|
||||
-- Version: 02-jan-2017
|
||||
--
|
||||
-- Copyright 2016-2017 by Samuel Devulder
|
||||
--
|
||||
-- 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('lib/thomson.lua')
|
||||
run('lib/ostromoukhov.lua')
|
||||
run('lib/color_reduction.lua')
|
||||
-- run('lib/zzz.lua')
|
||||
|
||||
-- get screen size
|
||||
local screen_w, screen_h = getpicturesize()
|
||||
|
||||
-- Converts thomson coordinates (0-159,0-199) into screen coordinates
|
||||
local function thom2screen(x,y)
|
||||
local i,j;
|
||||
if screen_w/screen_h < 1.6 then
|
||||
i = x*screen_h/200
|
||||
j = y*screen_h/200
|
||||
else
|
||||
i = x*screen_w/320
|
||||
j = y*screen_w/320
|
||||
end
|
||||
return math.floor(i*2), math.floor(j)
|
||||
end
|
||||
|
||||
-- return the Color @(x,y) in normalized linear space (0-1)
|
||||
-- corresonding to the thomson screen (x in 0-319, y in 0-199)
|
||||
local function getLinearPixel(x,y)
|
||||
local x1,y1 = thom2screen(x,y)
|
||||
local x2,y2 = thom2screen(x+1,y+1)
|
||||
if x2==x1 then x2=x1+1 end
|
||||
if y2==y1 then y2=y1+1 end
|
||||
|
||||
local p = Color:new(0,0,0);
|
||||
for j=y1,y2-1 do
|
||||
for i=x1,x2-1 do
|
||||
p:add(getLinearPictureColor(i,j))
|
||||
end
|
||||
end
|
||||
p:div((y2-y1)*(x2-x1)) --:floor()
|
||||
|
||||
return p
|
||||
end
|
||||
|
||||
local red = ColorReducer:new():analyzeWithDither(160,200,
|
||||
getLinearPixel,
|
||||
function(y)
|
||||
thomson.info("Collecting stats...",math.floor(y/2),"%")
|
||||
end)
|
||||
|
||||
-- BM16 mode
|
||||
thomson.setBM16()
|
||||
|
||||
-- define palette
|
||||
local palette = red:boostBorderColors():buildPalette(16)
|
||||
thomson.palette(0, palette)
|
||||
|
||||
-- convert picture
|
||||
OstroDither:new(palette)
|
||||
:dither(thomson.h,thomson.w,
|
||||
function(y,x) return getLinearPixel(x,y) end,
|
||||
function(y,x,c) thomson.pset(x,y,c) end,
|
||||
true,
|
||||
function(x) thomson.info("Converting...",math.floor(x*100/160),"%") end)
|
||||
|
||||
-- refresh screen
|
||||
setpicturesize(320,200)
|
||||
thomson.updatescreen()
|
||||
finalizepicture()
|
||||
|
||||
-- save picture
|
||||
thomson.savep()
|
||||
47
share/grafx2/scripts/samples/picture/thomson/ostro_to9.lua
Normal file
47
share/grafx2/scripts/samples/picture/thomson/ostro_to9.lua
Normal file
@@ -0,0 +1,47 @@
|
||||
-- ostro_mo5.lua : converts a color image into a
|
||||
-- TO9 image (320x200x16 with color clashes)
|
||||
-- using Ostromoukhov's error diffusion algorithm.
|
||||
--
|
||||
-- Version: 02-jan-2017
|
||||
--
|
||||
-- Copyright 2016-2017 by Samuel Devulder
|
||||
--
|
||||
-- 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('lib/ostromoukhov.lua')
|
||||
run('lib/color_reduction.lua')
|
||||
|
||||
OstroDither:new():dither40cols(function(w,h,getLinearPixel)
|
||||
local c16 = h==200 and w==320
|
||||
for y=0,h-1 do
|
||||
for x=0,w-1 do
|
||||
if getbackuppixel(x,y)>15 then c16 = false end
|
||||
end
|
||||
end
|
||||
|
||||
local pal
|
||||
if c16 then
|
||||
pal = {}
|
||||
for i=0,15 do
|
||||
local r,g,b=getbackupcolor(i)
|
||||
r = thomson.levels.pc2to[r]
|
||||
g = thomson.levels.pc2to[g]
|
||||
b = thomson.levels.pc2to[b]
|
||||
pal[i+1] = r+g*16+b*256-273
|
||||
end
|
||||
else
|
||||
pal=ColorReducer:new():analyzeWithDither(w,h,
|
||||
getLinearPixel,
|
||||
function(y)
|
||||
thomson.info("Building palette...",math.floor(y*100/h),"%")
|
||||
end):boostBorderColors():buildPalette(16)
|
||||
end
|
||||
|
||||
thomson.palette(0, pal)
|
||||
|
||||
return pal
|
||||
end)
|
||||
Reference in New Issue
Block a user