mirror of
https://github.com/dschmenk/PLASMA.git
synced 2026-04-20 16:16:34 +00:00
Save full version of DHGRRGB and simplify main DHGRRGB
This commit is contained in:
@@ -0,0 +1,843 @@
|
||||
include "inc/cmdsys.plh"
|
||||
include "inc/args.plh"
|
||||
include "inc/fileio.plh"
|
||||
include "inc/int32.plh"
|
||||
include "dhgr.tk/inc/dhgrlib.plh"
|
||||
include "dhgr.tk/inc/dhgrutils.plh"
|
||||
|
||||
sysflags resxtxt1|reshgr1|resxhgr1
|
||||
|
||||
// Bit patterns and associated default NTSC colors
|
||||
// NTSC_BLACK = 0000
|
||||
// NTSC_DRKBLUE = 0001 73, 14, 116
|
||||
// NTSC_DRKGREEN = 0010 0, 104, 100
|
||||
// NTSC_BROWN = 0100 55, 113, 11
|
||||
// NTSC_MAGENTA = 1000 127, 23, 27
|
||||
// NTSC_PURPLE = 1001
|
||||
// NTSC_MEDBLUE = 0011
|
||||
// NTSC_LTBLUE = 1011
|
||||
// NTSC_AQUA = 0111
|
||||
// NTSC_GREEN = 0110
|
||||
// NTSC_ORANGE = 1100
|
||||
// NTSC_PINK = 1101
|
||||
// NTSC_YELLOW = 1110
|
||||
// NTSC_WHITE = 1111
|
||||
|
||||
const RED = 0
|
||||
const GRN = 1
|
||||
const BLU = 2
|
||||
// According to what I could find out about the NTSC color wheel:
|
||||
// Red maxes at 103.5 degrees
|
||||
// Green maxes at 240.7 degrees
|
||||
// Blue maxes at 347.1 degrees
|
||||
const RED_PHASE_NTSC = 104
|
||||
const GREEN_PHASE_NTSC = 241
|
||||
const BLUE_PHASE_NTSC = 347
|
||||
// Ideal phase angles for 4 phase
|
||||
const RED_PHASE_IDEAL = 90
|
||||
const GREEN_PHASE_IDEAL = 270
|
||||
const BLUE_PHASE_IDEAL = 360
|
||||
// Equal 120 deg phase angles
|
||||
const RED_PHASE_EQUAL = 120
|
||||
const GREEN_PHASE_EQUAL = 240
|
||||
const BLUE_PHASE_EQUAL = 360
|
||||
// Simplified phase angles: 90 deg between R and B, 135 between RG and BG
|
||||
const RED_PHASE_SIMPLE = 90
|
||||
const GREEN_PHASE_SIMPLE = 225
|
||||
const BLUE_PHASE_SIMPLE = 360
|
||||
const GREY_CHROMA = 32 * 4 / 3
|
||||
// Flags
|
||||
const GREY_HACK = $01 // Remap GREY1->GREY2 hack
|
||||
const MEM_MODE = $02 // Render to memory surface
|
||||
const DUMP_STATE = $04 // Dump internal state
|
||||
const RAW_INFILE = $08 // Raw 560x192 24BPP RGB values
|
||||
const MATCH_PREV = $00 // Match previous RGB
|
||||
const MATCH_NEXT = $10 // Match next pixel
|
||||
const MATCH_CYCLE = $20 // Match current cycle
|
||||
const MATCH_ONE = 8
|
||||
const MATCH_ZERO = 0
|
||||
byte clrRot = $00,$02,$04,$06,$08,$0A,$0C,$0E
|
||||
byte = $01,$03,$05,$07,$09,$0B,$0D,$0F
|
||||
var sin90[] // first 90 degrees of sin in fixed s.15 format
|
||||
var = 0, 571, 1143, 1714, 2285, 2855, 3425, 3993
|
||||
var = 4560, 5126, 5690, 6252, 6812, 7371, 7927, 8480
|
||||
var = 9032, 9580, 10125, 10668, 11207, 11743, 12275, 12803
|
||||
var = 13327, 13848, 14364, 14876, 15383, 15886, 16383, 16876
|
||||
var = 17364, 17846, 18323, 18794, 19260, 19720, 20173, 20621
|
||||
var = 21062, 21497, 21926, 22347, 22762, 23170, 23571, 23964
|
||||
var = 24351, 24730, 25101, 25465, 25821, 26169, 26509, 26841
|
||||
var = 27165, 27481, 27788, 28087, 28377, 28659, 28932, 29196
|
||||
var = 29451, 29697, 29935, 30163, 30381, 30591, 30791, 30982
|
||||
var = 31164, 31336, 31498, 31651, 31794, 31928, 32051, 32165
|
||||
var = 32270, 32364, 32449, 32523, 32588, 32643, 32688, 32723
|
||||
var = 32748, 32763, 32767
|
||||
word hgrScan[] // HGR scanline order for saving memory buffer as DHGR
|
||||
word = $0000,$0400,$0800,$0C00,$1000,$1400,$1800,$1C00
|
||||
word = $0080,$0480,$0880,$0C80,$1080,$1480,$1880,$1C80
|
||||
word = $0100,$0500,$0900,$0D00,$1100,$1500,$1900,$1D00
|
||||
word = $0180,$0580,$0980,$0D80,$1180,$1580,$1980,$1D80
|
||||
word = $0200,$0600,$0A00,$0E00,$1200,$1600,$1A00,$1E00
|
||||
word = $0280,$0680,$0A80,$0E80,$1280,$1680,$1A80,$1E80
|
||||
word = $0300,$0700,$0B00,$0F00,$1300,$1700,$1B00,$1F00
|
||||
word = $0380,$0780,$0B80,$0F80,$1380,$1780,$1B80,$1F80
|
||||
word = $0028,$0428,$0828,$0C28,$1028,$1428,$1828,$1C28
|
||||
word = $00A8,$04A8,$08A8,$0CA8,$10A8,$14A8,$18A8,$1CA8
|
||||
word = $0128,$0528,$0928,$0D28,$1128,$1528,$1928,$1D28
|
||||
word = $01A8,$05A8,$09A8,$0DA8,$11A8,$15A8,$19A8,$1DA8
|
||||
word = $0228,$0628,$0A28,$0E28,$1228,$1628,$1A28,$1E28
|
||||
word = $02A8,$06A8,$0AA8,$0EA8,$12A8,$16A8,$1AA8,$1EA8
|
||||
word = $0328,$0728,$0B28,$0F28,$1328,$1728,$1B28,$1F28
|
||||
word = $03A8,$07A8,$0BA8,$0FA8,$13A8,$17A8,$1BA8,$1FA8
|
||||
word = $0050,$0450,$0850,$0C50,$1050,$1450,$1850,$1C50
|
||||
word = $00D0,$04D0,$08D0,$0CD0,$10D0,$14D0,$18D0,$1CD0
|
||||
word = $0150,$0550,$0950,$0D50,$1150,$1550,$1950,$1D50
|
||||
word = $01D0,$05D0,$09D0,$0DD0,$11D0,$15D0,$19D0,$1DD0
|
||||
word = $0250,$0650,$0A50,$0E50,$1250,$1650,$1A50,$1E50
|
||||
word = $02D0,$06D0,$0AD0,$0ED0,$12D0,$16D0,$1AD0,$1ED0
|
||||
word = $0350,$0750,$0B50,$0F50,$1350,$1750,$1B50,$1F50
|
||||
word = $03D0,$07D0,$0BD0,$0FD0,$13D0,$17D0,$1BD0,$1FD0
|
||||
var surfMem, surfSpan
|
||||
var rgbMatch
|
||||
var[12] ntscChroma
|
||||
var[12] ntscCycle
|
||||
var[16] pixRed, pixGrn, pixBlu
|
||||
var prevRed, prevBlu, prevGrn
|
||||
byte[256] gammaRed // RED gamma correction
|
||||
byte[256] gammaGrn // GREEN gamma correction
|
||||
byte[256] gammaBlu // BLUE gamma correction
|
||||
var[3] phase = RED_PHASE_NTSC, GREEN_PHASE_NTSC, BLUE_PHASE_NTSC
|
||||
byte[3] gamut = 128, 128, 128 // Gamut
|
||||
byte gamma = 1 // Gamma correction
|
||||
var brightness = 0
|
||||
var saturation = 255 // 1.0
|
||||
var tint = 22 // = 45/2 deg
|
||||
byte errDiv = 4
|
||||
byte flags = GREY_HACK
|
||||
var rgbErr // Running color error array
|
||||
var arg
|
||||
|
||||
// Handy numeric functions
|
||||
|
||||
def min(a, b)#1
|
||||
return a < b ?? a :: b
|
||||
end
|
||||
|
||||
def max(a, b)#1
|
||||
return a > b ?? a :: b
|
||||
end
|
||||
|
||||
def sin(deg)#1
|
||||
while deg > 360; deg = deg - 360; loop
|
||||
while deg < 0; deg = deg + 360; loop
|
||||
if deg <= 90
|
||||
return sin90[deg]
|
||||
elsif deg <= 180
|
||||
return sin90[180 - deg]
|
||||
elsif deg <= 270
|
||||
return -sin90[deg - 180]
|
||||
fin
|
||||
return -sin90[360 - deg]
|
||||
end
|
||||
|
||||
def cos(deg)#1
|
||||
return sin(deg + 90)
|
||||
end
|
||||
|
||||
def dist(dr, dg, db)#2 // Linear distance
|
||||
res[t_i32] rr, gg
|
||||
|
||||
loadi16(dr)
|
||||
muli16(dr)
|
||||
store32(@rr)
|
||||
loadi16(dg)
|
||||
muli16(dg)
|
||||
store32(@gg)
|
||||
loadi16(db)
|
||||
muli16(db)
|
||||
add32(@gg)
|
||||
add32(@rr)
|
||||
store32(@rr)
|
||||
return rr:[0], rr:[1]
|
||||
end
|
||||
|
||||
def atoi(strptr)#1
|
||||
var num, len, sign
|
||||
|
||||
sign = 1
|
||||
num = 0
|
||||
len = ^strptr
|
||||
strptr++
|
||||
if ^strptr == '-'
|
||||
sign = -1
|
||||
strptr++
|
||||
len--
|
||||
elsif ^strptr == '+'
|
||||
strptr++
|
||||
len--
|
||||
fin
|
||||
while len and ^strptr >= '0' and ^strptr <= '9'
|
||||
num = num * 10 + ^strptr - '0'
|
||||
strptr++
|
||||
len--
|
||||
loop
|
||||
return num * sign
|
||||
end
|
||||
|
||||
def calcChroma(angle)#0
|
||||
var r, g, b
|
||||
byte i
|
||||
|
||||
for i = 0 to 3
|
||||
// Calculate RGB for this DHGR pixel
|
||||
//r = max(0, (saturation + (cos(angle - phase[RED]) >> 7)))
|
||||
//g = max(0, (saturation + (cos(angle - phase[GRN]) >> 7)))
|
||||
//b = max(0, (saturation + (cos(angle - phase[BLU]) >> 7)))
|
||||
r = saturation + (cos(angle - phase[RED]) >> 7)
|
||||
g = saturation + (cos(angle - phase[GRN]) >> 7)
|
||||
b = saturation + (cos(angle - phase[BLU]) >> 7)
|
||||
// Make chroma add up to white
|
||||
ntscChroma[i*3 + RED] = (r + 2) / 4
|
||||
ntscChroma[i*3 + GRN] = (g + 2) / 4
|
||||
ntscChroma[i*3 + BLU] = (b + 2) / 4
|
||||
// Next NTSC chroma pixel
|
||||
angle = angle - 90
|
||||
next
|
||||
end
|
||||
|
||||
def errProp(er, eg, eb, errptr)#0
|
||||
// Propogate error down and forward
|
||||
errptr=>[RED] = er
|
||||
errptr=>[GRN] = eg
|
||||
errptr=>[BLU] = eb
|
||||
errptr = errptr + 6
|
||||
errptr=>[RED] = er + errptr=>[RED]
|
||||
errptr=>[GRN] = eg + errptr=>[GRN]
|
||||
errptr=>[BLU] = eb + errptr=>[BLU]
|
||||
end
|
||||
|
||||
def rgbMatchCycle(r, g, b, errptr, cx)#1
|
||||
var pr1, pg1, pb1
|
||||
var pr2, pg2, pb2
|
||||
var pr3, pg3, pb3
|
||||
var nr, ng, nb
|
||||
var pr, pg, pb
|
||||
var cr, cg, cb
|
||||
var er, eg, eb
|
||||
byte i, match
|
||||
res[t_i32] pd, d0, nd, cd
|
||||
|
||||
// Previous 1/4 chroma cycle
|
||||
i = ((cx - 1) & 3) * 3
|
||||
pr1 = ntscCycle[i+RED]
|
||||
pg1 = ntscCycle[i+GRN]
|
||||
pb1 = ntscCycle[i+BLU]
|
||||
// Previous 2/4 chroma cycle
|
||||
i = ((cx - 2) & 3) * 3
|
||||
pr2 = ntscCycle[i+RED] + pr1
|
||||
pg2 = ntscCycle[i+GRN] + pg1
|
||||
pb2 = ntscCycle[i+BLU] + pb1
|
||||
// Previous 3/4 chroma cycle
|
||||
i = ((cx - 3) & 3) * 3
|
||||
pr3 = ntscCycle[i+RED] + pr2
|
||||
pg3 = ntscCycle[i+GRN] + pg2
|
||||
pb3 = ntscCycle[i+BLU] + pb2
|
||||
// Previous chroma cycle
|
||||
i = cx * 3 // ((cx - 4) & 3) * 3
|
||||
pr = (pr1 + pr2 + pr3 + ntscCycle[i+RED] / 2) / 4
|
||||
pg = (pg1 + pg2 + pg3 + ntscCycle[i+GRN] / 2) / 4
|
||||
pb = (pb1 + pb2 + pb3 + ntscCycle[i+BLU] / 2) / 4
|
||||
// Current potential chroma cycle
|
||||
//i = cx * 3
|
||||
cr = pr + ntscChroma[i+RED]
|
||||
cg = pg + ntscChroma[i+GRN]
|
||||
cb = pb + ntscChroma[i+BLU]
|
||||
// Match next chroma subcycle
|
||||
pd:[0], pd:[1] = dist(r - pr, g - pg, b - pb)
|
||||
dist(r - cr, g - cg, b - cb)
|
||||
if islt32(@pd)
|
||||
// RGB better matched with next chroma color
|
||||
er = r - cr
|
||||
eg = g - cg
|
||||
eb = b - cb
|
||||
ntscCycle[i+RED] = ntscChroma[i+RED]
|
||||
ntscCycle[i+GRN] = ntscChroma[i+GRN]
|
||||
ntscCycle[i+BLU] = ntscChroma[i+BLU]
|
||||
i = MATCH_ONE
|
||||
else
|
||||
// RGB closer to previous chroma color
|
||||
er = r - pr
|
||||
eg = g - pg
|
||||
eb = b - pb
|
||||
ntscCycle[i+RED] = 0
|
||||
ntscCycle[i+GRN] = 0
|
||||
ntscCycle[i+BLU] = 0
|
||||
i = MATCH_ZERO
|
||||
fin
|
||||
errProp(er, eg, eb, errptr)
|
||||
return i
|
||||
end
|
||||
|
||||
def rgbMatchNext(r, g, b, errptr, cx)#1
|
||||
var pr1, pg1, pb1
|
||||
var pr2, pg2, pb2
|
||||
var pr3, pg3, pb3
|
||||
var pr, pg, pb
|
||||
var cr, cg, cb
|
||||
var er, eg, eb
|
||||
byte i, match
|
||||
res[t_i32] nd, cd
|
||||
|
||||
// Previous 1/4 chroma cycle
|
||||
i = ((cx - 1) & 3) * 3
|
||||
pr1 = ntscCycle[i+RED]
|
||||
pg1 = ntscCycle[i+GRN]
|
||||
pb1 = ntscCycle[i+BLU]
|
||||
// Previous 2/4 chroma cycle
|
||||
i = ((cx - 2) & 3) * 3
|
||||
pr2 = ntscCycle[i+RED]
|
||||
pg2 = ntscCycle[i+GRN]
|
||||
pb2 = ntscCycle[i+BLU]
|
||||
// Previous 3/4 chroma cycle
|
||||
i = ((cx - 3) & 3) * 3
|
||||
pr3 = ntscCycle[i+RED]
|
||||
pg3 = ntscCycle[i+GRN]
|
||||
pb3 = ntscCycle[i+BLU]
|
||||
// Previous chroma cycle
|
||||
i = cx * 3 // ((cx - 4) & 3) * 3
|
||||
pr = pr1 + pr2 + pr3
|
||||
pg = pg1 + pg2 + pg3
|
||||
pb = pb1 + pb2 + pb3
|
||||
// Current potential chroma cycle
|
||||
//i = cx * 3
|
||||
cr = pr + ntscChroma[i+RED]
|
||||
cg = pg + ntscChroma[i+GRN]
|
||||
cb = pb + ntscChroma[i+BLU]
|
||||
// Match next full chroma cycle (pixel)
|
||||
cd:[0], cd:[1] = $FFFF, $7FFF
|
||||
for i = 0 to 15
|
||||
nd:[0], nd:[1] = dist(r - pixRed[i], g - pixGrn[i], b - pixBlu[i])
|
||||
if islt32(@cd)
|
||||
cd:[0], cd:[1] = nd:[0], nd:[1]
|
||||
match = i
|
||||
fin
|
||||
next
|
||||
i = cx * 3
|
||||
if match & (1 << cx)
|
||||
// RGB better matched with next chroma color
|
||||
er = r - cr
|
||||
eg = g - cg
|
||||
eb = b - cb
|
||||
ntscCycle[i+RED] = ntscChroma[i+RED]
|
||||
ntscCycle[i+GRN] = ntscChroma[i+GRN]
|
||||
ntscCycle[i+BLU] = ntscChroma[i+BLU]
|
||||
i = MATCH_ONE
|
||||
else
|
||||
// RGB closer to previous chroma color
|
||||
er = r - pr
|
||||
eg = g - pg
|
||||
eb = b - pb
|
||||
ntscCycle[i+RED] = 0
|
||||
ntscCycle[i+GRN] = 0
|
||||
ntscCycle[i+BLU] = 0
|
||||
i = MATCH_ZERO
|
||||
fin
|
||||
errProp(er, eg, eb, errptr)
|
||||
return i
|
||||
end
|
||||
|
||||
def rgbMatchPrev(r, g, b, errptr, cx)#1
|
||||
var cr, cg, cb
|
||||
var er, eg, eb
|
||||
byte i,
|
||||
res[t_i32] pd
|
||||
|
||||
// Previous RGB minus current chroma cycle
|
||||
prevRed = (prevRed * 3) / 4
|
||||
prevGrn = (prevGrn * 3) / 4
|
||||
prevBlu = (prevBlu * 3) / 4
|
||||
// Current potential RGB
|
||||
i = cx * 3
|
||||
cr = prevRed + ntscChroma[i+RED]
|
||||
cg = prevGrn + ntscChroma[i+GRN]
|
||||
cb = prevBlu + ntscChroma[i+BLU]
|
||||
// Match next chroma subcycle
|
||||
pd:[0], pd:[1] = dist(r - prevRed, g - prevGrn, b - prevBlu)
|
||||
dist(r - cr, g - cg, b - cb)
|
||||
if islt32(@pd)
|
||||
// RGB better matched with next chroma color
|
||||
prevRed = cr
|
||||
prevGrn = cg
|
||||
prevBlu = cb
|
||||
i = MATCH_ONE
|
||||
else
|
||||
i = MATCH_ZERO
|
||||
fin
|
||||
// Propogate error down and forward
|
||||
er = r - prevRed
|
||||
errptr=>[RED] = er
|
||||
eg = g - prevGrn
|
||||
errptr=>[GRN] = eg
|
||||
eb = b - prevBlu
|
||||
errptr=>[BLU] = eb
|
||||
errptr=>[RED+3] = er + errptr=>[RED+3]
|
||||
errptr=>[GRN+3] = eg + errptr=>[GRN+3]
|
||||
errptr=>[BLU+3] = eb + errptr=>[BLU+3]
|
||||
return i
|
||||
end
|
||||
|
||||
def rgbInit#0
|
||||
var i
|
||||
res[t_i32] g32
|
||||
|
||||
if flags & DUMP_STATE
|
||||
puts("Gamma = "); puti(sext(gamma)); putln
|
||||
fin
|
||||
when gamma
|
||||
is 255 // (i + 1 / i^2) / 2
|
||||
for i = 0 to 255
|
||||
loadi16(i)
|
||||
muli16(i)
|
||||
addi16(127)
|
||||
divi16(255)
|
||||
neg32
|
||||
addi16(255)
|
||||
addi16(255 - i)
|
||||
divi16(2)
|
||||
store32(@g32)
|
||||
gammaRed[255 - i] = g32
|
||||
gammaGrn[255 - i] = g32
|
||||
gammaBlu[255 - i] = g32
|
||||
next
|
||||
break
|
||||
is 254 // 1 - i^2
|
||||
for i = 0 to 255
|
||||
loadi16(i)
|
||||
muli16(i)
|
||||
addi16(127)
|
||||
divi16(255)
|
||||
neg32
|
||||
addi16(255)
|
||||
store32(@g32)
|
||||
gammaRed[255 - i] = g32
|
||||
gammaGrn[255 - i] = g32
|
||||
gammaBlu[255 - i] = g32
|
||||
next
|
||||
break
|
||||
is 2 // 1/(i^2)
|
||||
for i = 0 to 255
|
||||
loadi16(i)
|
||||
muli16(i)
|
||||
addi16(127)
|
||||
divi16(255)
|
||||
store32(@g32)
|
||||
gammaRed[i] = g32
|
||||
gammaGrn[i] = g32
|
||||
gammaBlu[i] = g32
|
||||
next
|
||||
break
|
||||
is 1 // (i + i^2) / 2
|
||||
for i = 0 to 255
|
||||
loadi16(i)
|
||||
muli16(i)
|
||||
addi16(127)
|
||||
divi16(255)
|
||||
addi16(i)
|
||||
divi16(2)
|
||||
store32(@g32)
|
||||
gammaRed[i] = g32
|
||||
gammaGrn[i] = g32
|
||||
gammaBlu[i] = g32
|
||||
next
|
||||
break
|
||||
otherwise // i
|
||||
for i = 0 to 255
|
||||
gammaRed[i] = i
|
||||
gammaGrn[i] = i
|
||||
gammaBlu[i] = i
|
||||
next
|
||||
wend
|
||||
if gamut[RED] <> 128
|
||||
for i = 0 to 255
|
||||
gammaRed[i] = max(0, min(255, (gammaRed[i] * 128) / gamut[RED]))
|
||||
next
|
||||
fin
|
||||
if gamut[GRN] <> 128
|
||||
for i = 0 to 255
|
||||
gammaGrn[i] = max(0, min(255, (gammaGrn[i] * 128) / gamut[GRN]))
|
||||
next
|
||||
fin
|
||||
if gamut[BLU] <> 128
|
||||
for i = 0 to 255
|
||||
gammaBlu[i] = max(0, min(255, (gammaBlu[i] * 128) / gamut[BLU]))
|
||||
next
|
||||
fin
|
||||
if brightness
|
||||
for i = 0 to 255
|
||||
gammaRed[i] = max(0, min(255, gammaRed[i] + brightness))
|
||||
gammaGrn[i] = max(0, min(255, gammaGrn[i] + brightness))
|
||||
gammaBlu[i] = max(0, min(255, gammaBlu[i] + brightness))
|
||||
next
|
||||
fin
|
||||
calcChroma(tint)
|
||||
if flags & DUMP_STATE
|
||||
puts("Err Div = "); puti(errDiv); putln
|
||||
puts("Brightness = "); puti(brightness); putln
|
||||
puts("Tint = "); puti(tint); putln
|
||||
puts("Saturation = "); puti(saturation); putln
|
||||
puts("Gamut = ["); puti(gamut[RED]); putc(',')
|
||||
puti(gamut[GRN]); putc(','); puti(gamut[BLU]); puts("]\n")
|
||||
puts("Match = ")
|
||||
if flags & MATCH_NEXT; puts("Next\n")
|
||||
elsif flags & MATCH_CYCLE; puts("Current\n")
|
||||
else; puts("Prev\n"); fin
|
||||
puts("Chroma cycle RGB =\n")
|
||||
for i = 0 to 3
|
||||
putc('[')
|
||||
puti(ntscChroma[i*3 + RED]); putc(',')
|
||||
puti(ntscChroma[i*3 + GRN]); putc(',')
|
||||
puti(ntscChroma[i*3 + BLU]); puts("]\n")
|
||||
next
|
||||
fin
|
||||
if flags & MATCH_NEXT
|
||||
rgbMatch = @rgbMatchNext
|
||||
// Calc pixel RGBs
|
||||
for i = 0 to 15
|
||||
if i & 1
|
||||
pixRed[i] = ntscChroma[RED]
|
||||
pixGrn[i] = ntscChroma[GRN]
|
||||
pixBlu[i] = ntscChroma[BLU]
|
||||
fin
|
||||
if i & 2
|
||||
pixRed[i] = pixRed[i] + ntscChroma[3+RED]
|
||||
pixGrn[i] = pixGrn[i] + ntscChroma[3+GRN]
|
||||
pixBlu[i] = pixBlu[i] + ntscChroma[3+BLU]
|
||||
fin
|
||||
if i & 4
|
||||
pixRed[i] = pixRed[i] + ntscChroma[6+RED]
|
||||
pixGrn[i] = pixGrn[i] + ntscChroma[6+GRN]
|
||||
pixBlu[i] = pixBlu[i] + ntscChroma[6+BLU]
|
||||
fin
|
||||
if i & 8
|
||||
pixRed[i] = pixRed[i] + ntscChroma[9+RED]
|
||||
pixGrn[i] = pixGrn[i] + ntscChroma[9+GRN]
|
||||
pixBlu[i] = pixBlu[i] + ntscChroma[9+BLU]
|
||||
fin
|
||||
next
|
||||
// Adjust error scalng for this strategy
|
||||
errDiv = errDiv * 2
|
||||
elsif flags & MATCH_CYCLE
|
||||
rgbMatch = @rgbMatchCycle
|
||||
// Make up for scaled chroma cycle color match
|
||||
for i = 0 to 11
|
||||
ntscChroma[i] = (ntscChroma[i] * 3) / 2 // * 1.5
|
||||
next
|
||||
else // MATCH_PREV
|
||||
rgbMatch = @rgbMatchPrev
|
||||
fin
|
||||
if flags & MEM_MODE
|
||||
surfMem, surfSpan = dhgrAllocBl7Mem(SCR_WIDTH, SCR_HEIGHT)
|
||||
dhgrSurfMem(OP_XOR, SCR_HEIGHT, surfMem, surfSpan)
|
||||
dhgrOp(OP_SRC) // Force op recalc
|
||||
dcgrColor(CLR_BLACK)
|
||||
dhgrClearBl7(0, 0, surfSpan >> 2, SCR_HEIGHT)
|
||||
else
|
||||
dhgrMode(DHGR_COLOR_MODE)
|
||||
fin
|
||||
end
|
||||
|
||||
def rgbExit#0
|
||||
heaprelease(rgbErr)
|
||||
if not (flags & MEM_MODE)
|
||||
dhgrMode(DHGR_TEXT_MODE)
|
||||
fin
|
||||
end
|
||||
|
||||
def pnmReadElement(refnum, bufptr)#1
|
||||
var lenptr
|
||||
|
||||
lenptr = bufptr
|
||||
repeat
|
||||
^lenptr = 0
|
||||
bufptr = lenptr + 1
|
||||
if fileio:read(refnum, bufptr, 1) == 1 and ^bufptr == '#' // Comment
|
||||
^lenptr++
|
||||
bufptr++
|
||||
while fileio:read(refnum, bufptr, 1) == 1 and ^bufptr >= ' '
|
||||
loop
|
||||
else
|
||||
repeat // Read white space seperated element
|
||||
^lenptr++
|
||||
bufptr++
|
||||
until fileio:read(refnum, bufptr, 1) <> 1 or ^bufptr <= ' ' or ^lenptr > 32
|
||||
fin
|
||||
until ^lenptr and ^(lenptr + 1) <> '#' // Repeat until not comment
|
||||
if flags & DUMP_STATE; puts(lenptr); putc(' '); fin
|
||||
return lenptr
|
||||
end
|
||||
|
||||
def pnmVerifyHeader(refnum)#1
|
||||
byte[128] buf
|
||||
if flags & DUMP_STATE; puts("PNM = "); fin
|
||||
pnmReadElement(refnum, @buf)
|
||||
if buf[0] <> 2 and buf[1] <> 'P' and buf[2] <> '6'
|
||||
puts("Invalid PNM magic #: "); putc(buf[1]); putc(buf[2]); putln
|
||||
return FALSE
|
||||
fin
|
||||
if atoi(pnmReadElement(refnum, @buf)) <> 560
|
||||
puts("Width not 560: "); puts(@buf); putln
|
||||
return FALSE
|
||||
fin
|
||||
if atoi(pnmReadElement(refnum, @buf)) <> 192
|
||||
puts("Height not 192: "); puts(@buf); putln
|
||||
return FALSE
|
||||
fin
|
||||
if atoi(pnmReadElement(refnum, @buf)) <> 255
|
||||
puts("Depth not 255: "); puts(@buf); putln
|
||||
return FALSE
|
||||
fin
|
||||
if flags & DUMP_STATE; putln; fin
|
||||
return TRUE
|
||||
end
|
||||
|
||||
def rgbImportExport(rgbfile, dhgrfile)#0
|
||||
byte refnum, chromaBits
|
||||
var i, j, c, r, g, b
|
||||
var rgbScanline, rgbptr, errptr
|
||||
|
||||
refnum = fileio:open(rgbfile)
|
||||
if refnum
|
||||
if not (flags & RAW_INFILE)
|
||||
if not pnmVerifyHeader(refnum)
|
||||
fileio:close(refnum)
|
||||
return
|
||||
fin
|
||||
fin
|
||||
rgbInit
|
||||
rgbScanline = heapalloc(560 * 3)
|
||||
rgbErr = heapalloc(561 * 3 * 2)
|
||||
if rgbErr and rgbScanline
|
||||
// Init error propogation array
|
||||
memset(rgbErr, 0, 560 * 3 * 2)
|
||||
memset(rgbScanline, 0, 560 * 3)
|
||||
for j = 0 to 191
|
||||
fileio:read(refnum, rgbScanline, 560 * 3)
|
||||
memset(@ntscCycle, GREY_CHROMA, 24) // Reset chroma cycle
|
||||
prevRed, prevGrn, prevBLu = 96, 96, 96 // Reset prev RGB
|
||||
rgbptr = rgbScanline
|
||||
errptr = rgbErr
|
||||
for i = 0 to 139
|
||||
chromaBits = 0
|
||||
for c = 0 to 3
|
||||
// Calc best match
|
||||
r = gammaRed[rgbptr->[RED]]
|
||||
g = gammaGrn[rgbptr->[GRN]]
|
||||
b = gammaBlu[rgbptr->[BLU]]
|
||||
if errDiv
|
||||
r = r + errptr=>[RED] / errDiv
|
||||
g = g + errptr=>[GRN] / errDiv
|
||||
b = b + errptr=>[BLU] / errDiv
|
||||
fin
|
||||
chromaBits = (chromaBits >> 1) | rgbMatch(r, g, b, errptr, c)
|
||||
rgbptr = rgbptr + 3
|
||||
errptr = errptr + 3 * 2
|
||||
next
|
||||
if flags & GREY_HACK
|
||||
// Map GREY1 -> GREY2
|
||||
if chromaBits == $0A // Bits are in reverse order from DCGR color value
|
||||
chromaBits = $05
|
||||
memset(@ntscCycle, GREY_CHROMA, 24) // Grey chroma cycle
|
||||
elsif chromaBits == $05
|
||||
memset(@ntscCycle, GREY_CHROMA, 24) // Grey chroma cycle
|
||||
fin
|
||||
fin
|
||||
dcgrColor(clrRot[chromaBits])
|
||||
dcgrPixel(i, j)
|
||||
next
|
||||
if flags & MEM_MODE; putc('.'); fin
|
||||
if ^$C000 == $83
|
||||
break
|
||||
fin
|
||||
next
|
||||
fileio:close(refnum)
|
||||
if ^dhgrfile
|
||||
if flags & MEM_MODE
|
||||
heaprelease(rgbScanline) // Free up some memory
|
||||
if MACHID & $F0 <> $B0
|
||||
// Use allocated buffer on non 128K //e
|
||||
rgbScanline = heapalloc($2000)
|
||||
else
|
||||
// Use HGR memory (already reserved) on 128K //e
|
||||
rgbScanline = $2000
|
||||
fin
|
||||
if rgbScanline
|
||||
memset(rgbScanline, 0, $2000)
|
||||
fileio:destroy(dhgrfile)
|
||||
fileio:create(dhgrfile, $06, $2000)
|
||||
refnum = fileio:open(dhgrfile)
|
||||
if refnum
|
||||
// Reorder scanlines into HGR format
|
||||
rgbptr = surfMem
|
||||
for i = 0 to SCR_HEIGHT-1
|
||||
memcpy(rgbScanline+hgrScan[i], rgbptr, 40)
|
||||
rgbptr = rgbptr + surfSpan
|
||||
next
|
||||
// Write AUX bytes
|
||||
fileio:write(refnum, rgbScanline, $2000)
|
||||
rgbptr = surfMem + surfSpan / 2
|
||||
for i = 0 to SCR_HEIGHT-1
|
||||
memcpy(rgbScanline+hgrScan[i], rgbptr, 40)
|
||||
rgbptr = rgbptr + surfSpan
|
||||
next
|
||||
// Write MAIN bytes
|
||||
fileio:write(refnum, rgbScanline, $2000)
|
||||
fileio:close(refnum)
|
||||
fin
|
||||
putln
|
||||
fin
|
||||
else
|
||||
screenWrite(dhgrfile)
|
||||
fin
|
||||
fin
|
||||
if not (flags & MEM_MODE); getc; fin
|
||||
rgbExit
|
||||
fin
|
||||
else
|
||||
puts("Unable to open "); puts(rgbfile); putln
|
||||
fin
|
||||
end
|
||||
|
||||
puts("DHGR RGB converter 1.1\n")
|
||||
arg = argNext(argFirst)
|
||||
if ^arg
|
||||
while ^(arg + 1) == '-'
|
||||
when toupper(^(arg + 2))
|
||||
is 'B' // Set brightness
|
||||
if ^arg > 2
|
||||
^(arg + 2) = ^arg - 2
|
||||
brightness = atoi(arg + 2)
|
||||
fin
|
||||
break
|
||||
is 'C' // Disable hack for GREY remapping
|
||||
flags = flags & ~GREY_HACK
|
||||
break
|
||||
is 'D' // Dump internal staet
|
||||
flags = flags | DUMP_STATE
|
||||
break
|
||||
is 'E' // Set error strength
|
||||
if ^arg > 2
|
||||
errDiv = ^(arg + 3) - '0'
|
||||
if ^arg > 3
|
||||
errDiv = errDiv * 10 + ^(arg + 4) - '0'
|
||||
fin
|
||||
fin
|
||||
break
|
||||
is 'G' // Set gamma amount
|
||||
if ^arg > 2
|
||||
^(arg + 2) = ^arg - 2
|
||||
gamma = atoi(arg + 2)
|
||||
fin
|
||||
break
|
||||
is 'M' // Match RGB strategy
|
||||
when toupper(^(arg + 3))
|
||||
is 'N' // Match to next pixel
|
||||
flags = flags | MATCH_NEXT
|
||||
tint = tint - 22
|
||||
break
|
||||
is 'C' // Match to current cycle
|
||||
flags = flags | MATCH_CYCLE
|
||||
break
|
||||
//is 'P' // Match to previous RGB
|
||||
otherwise
|
||||
break
|
||||
wend
|
||||
break
|
||||
is 'P' // RGB phase angle
|
||||
when toupper(^(arg + 3))
|
||||
is 'I' // Use ideal 4 sub-phase angles
|
||||
phase[RED] = RED_PHASE_IDEAL
|
||||
phase[GRN] = GREEN_PHASE_IDEAL
|
||||
phase[BLU] = BLUE_PHASE_IDEAL
|
||||
break
|
||||
is 'E' // Use equal 120 deg phase angles
|
||||
phase[RED] = RED_PHASE_EQUAL
|
||||
phase[GRN] = GREEN_PHASE_EQUAL
|
||||
phase[BLU] = BLUE_PHASE_EQUAL
|
||||
break
|
||||
is 'S' // Use simplified 90 degree and opposite phase angles
|
||||
phase[RED] = RED_PHASE_SIMPLE
|
||||
phase[GRN] = GREEN_PHASE_SIMPLE
|
||||
phase[BLU] = BLUE_PHASE_SIMPLE
|
||||
break
|
||||
//is 'N' // Use theoretical NTSC phase angles
|
||||
otherwise
|
||||
phase[RED] = RED_PHASE_NTSC
|
||||
phase[GRN] = GREEN_PHASE_NTSC
|
||||
phase[BLU] = BLUE_PHASE_NTSC
|
||||
break
|
||||
wend
|
||||
break
|
||||
is 'R' // Raw input mode - no PNM header
|
||||
flags = flags | RAW_INFILE
|
||||
break
|
||||
is 'S' // Adjust saturation
|
||||
if ^arg > 2
|
||||
^(arg + 2) = ^arg - 2
|
||||
saturation = saturation - atoi(arg + 2)
|
||||
fin
|
||||
break
|
||||
is 'T' // Adjust tint
|
||||
if ^arg > 2
|
||||
^(arg + 2) = ^arg - 2
|
||||
tint = tint + atoi(arg + 2)
|
||||
fin
|
||||
break
|
||||
is 'U' // Adjust gamut
|
||||
if ^arg > 3
|
||||
when toupper(^(arg + 3))
|
||||
is 'R'
|
||||
^(arg + 1) = RED
|
||||
break
|
||||
is 'G'
|
||||
^(arg + 1) = GRN
|
||||
break
|
||||
otherwise // B
|
||||
^(arg + 1) = BLU
|
||||
break
|
||||
wend
|
||||
^(arg + 3) = ^arg - 3
|
||||
gamut[^(arg + 1)] = gamut[^(arg + 1)] - atoi(arg + 3)
|
||||
fin
|
||||
break
|
||||
is 'V' // No video output, memory mode only (for portable VM)
|
||||
flags = flags | MEM_MODE
|
||||
break
|
||||
otherwise
|
||||
puts("? option:"); putc(^(arg + 2)); putln
|
||||
wend
|
||||
arg = argNext(arg)
|
||||
loop
|
||||
if ^arg
|
||||
rgbImportExport(arg, argNext(arg))
|
||||
fin
|
||||
return 0
|
||||
fin
|
||||
puts("Usage:\n")
|
||||
puts(" DHGRRGB\n")
|
||||
puts(" [-B#] = Brightness: -255..255\n")
|
||||
puts(" [-C] = Composite output\n")
|
||||
puts(" [-D] = Dump state\n")
|
||||
puts(" [-E#] = Error strength: 1..255\n")
|
||||
puts(" 0 = no err\n")
|
||||
puts(" [-G#] = Gamma: 2, 1, 0, -1, -2\n")
|
||||
puts(" [-M<N,C,P>] = Match: Next, Current\n")
|
||||
puts(" Previous\n")
|
||||
puts(" [-P<I,E,S,N>] = Phase: Ideal, Equal\n")
|
||||
puts(" Simple, NTSC\n")
|
||||
puts(" [-R] = Raw image file, no header\n")
|
||||
puts(" [-S#] = Saturation: -255..255\n")
|
||||
puts(" [-T#] = Tint: -360..360 (in degrees)\n")
|
||||
puts(" [-U<R,G,B>#] = gammUt: Red, Grn, Blu\n")
|
||||
puts(" -255..255\n")
|
||||
puts(" [-V] = no Video output, mem only\n")
|
||||
puts(" IMAGEFILE [DHGRFILE]\n")
|
||||
done
|
||||
Reference in New Issue
Block a user