Subversion Repositories eduke32

Rev

Rev 4256 | Rev 4301 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
4236 helixhorne 1
 
2
local ffi = require("ffi")
3
local C = ffi.C
4
 
5
local bcarray = require("bcarray")
6
 
7
local error = error
8
local type = type
9
 
10
local decl = assert(decl)  -- comes from above (defs.ilua or defs_m32.lua)
11
 
12
local ismapster32 = (C.LUNATIC_CLIENT == C.LUNATIC_CLIENT_MAPSTER32)
13
 
14
----------
15
 
16
decl[[
17
int32_t getclosestcol(int32_t r, int32_t g, int32_t b);
18
char *palookup[256];  // MAXPALOOKUPS
19
uint8_t palette[768];
20
 
21
int32_t setpalookup(int32_t palnum, const uint8_t *shtab);
22
]]
23
 
24
----------
25
 
4242 helixhorne 26
 
4236 helixhorne 27
-- The API table
28
local engine = {}
29
 
4242 helixhorne 30
 
31
local shtab_t  -- forward-decl
32
 
33
local function cast_u8ptr(pal256)
34
    return ffi.cast("uint8_t *", pal256)
35
end
36
 
37
local shtab_methods = {
38
    -- Remap consecutive blocks of 16 color indices and return this new shade
39
    -- table.
40
    --
4256 helixhorne 41
    -- <idxs16>: table with idxs16[0] .. idxs16[15] >= 0 and <= 15
42
    --  (i.e. 0-based indices of such 16-tuples)
4242 helixhorne 43
    --
44
    -- For example, the table
45
    --  { [0]=0,1, 2,3, 5,4, 6,7, 8,13, 10,11, 12,9, 14,15 }
46
    -- TODO (...)
47
    remap16 = function(sht, idxs16)
48
        if (type(idxs16) ~= "table" or idxs16[0]==nil or #idxs16 ~= 15) then
49
            error("invalid argument #2: must be a [0]-table with 16 elements", 2)
50
        end
51
 
52
        for i=0,15 do
53
            if (not (idxs16[i] >= 0 and idxs16[i] <= 15)) then
54
                error("invalid reordering table: elements must be in [0 .. 15]", 2)
55
            end
56
        end
57
 
58
        local newsht = shtab_t()
59
        for sh=0,31 do
60
            for i=0,15 do
61
                ffi.copy(cast_u8ptr(newsht[sh]) + 16*i,
62
                         cast_u8ptr(sht[sh]) + 16*idxs16[i], 16)
63
            end
64
        end
65
        return newsht
66
    end,
67
}
68
 
69
local function shtab_mt__index(sht, idx)
70
    local method = shtab_methods[idx]
71
    if (method) then
72
        return method
73
    end
74
end
75
 
4236 helixhorne 76
local pal256_t = bcarray.new("uint8_t", 256, "shade table 256-tuple")
77
-- The shade table type, effectively a bound-checked uint8_t [32][256]:
4242 helixhorne 78
shtab_t = bcarray.new(pal256_t, 32, "shade table", nil, nil, { __index = shtab_mt__index })
4236 helixhorne 79
local SIZEOF_SHTAB = ffi.sizeof(shtab_t)
80
 
81
local RESERVEDPALS = 8  -- KEEPINSYNC build.h: assure that ours is >= theirs
82
engine.RESERVEDPALS = RESERVEDPALS
83
 
84
local function check_palidx(i)
85
    if (type(i) ~= "number" or not (i >= 0 and i <= 255-RESERVEDPALS)) then
4262 helixhorne 86
        error("invalid argument #1: palette swap index must be in the range [0 .. "..255-RESERVEDPALS.."]", 3)
4236 helixhorne 87
    end
88
end
89
 
90
local function err_uncommon_shade_table(ret)
91
    if (ret == -1) then
92
        error("loaded engine shade tables don't have 32 gradients of shade", 3)
93
    end
94
end
95
 
96
local function palookup_isdefault(palnum)  -- KEEPINSYNC engine.c
97
    return (C.palookup[palnum] == nil or (palnum ~= 0 and C.palookup[palnum] == C.palookup[0]))
98
end
99
 
100
function engine.shadetab()
101
    return shtab_t()
102
end
103
 
104
function engine.getshadetab(palidx)
105
    check_palidx(palidx)
106
    if (palookup_isdefault(palidx)) then
107
        return nil
108
    end
109
 
110
    local ret = C.setpalookup(palidx, nil)
111
    err_uncommon_shade_table(ret)
112
 
113
    local sht = shtab_t()
114
    ffi.copy(sht, C.palookup[palidx], SIZEOF_SHTAB)
115
    return sht
116
end
117
 
118
function engine.setshadetab(palidx, shtab)
119
    if (not ismapster32 and C.g_elFirstTime == 0) then
120
        error("setshadetab() may be run only while LUNATIC_FIRST_TIME is true", 2)
121
    end
122
 
123
    check_palidx(palidx)
124
    if (not ffi.istype(shtab_t, shtab_t)) then
125
        error("invalid argument #2: must be a shade table obtained by shadetab()", 2)
126
    end
127
 
128
    if (not ismapster32 and not palookup_isdefault(palidx)) then
129
        error("attempt to override already defined shade table", 2)
130
    end
131
 
132
    local ret = C.setpalookup(palidx, ffi.cast("uint8_t *", shtab))
133
    err_uncommon_shade_table(ret)
134
end
135
 
136
 
137
local function check_colcomp(a)
138
    if (type(a) ~= "number" or not (a >= 0 and a <= 63)) then
139
        error("color component must be in the range [0 .. 63]", 3)
140
    end
141
end
142
 
143
 
144
-- TODO: other base palettes?
145
function engine.getrgb(colidx)
146
    if (type(colidx) ~= "number" or not (colidx >= 0 and colidx <= 255)) then
147
        error("color index must be in the range [0 .. 255]", 2)
148
    end
149
 
150
    local rgbptr = C.palette + 3*colidx
151
    return rgbptr[0], rgbptr[1], rgbptr[2]
152
end
153
 
154
-- TODO: flag whether fullbrights are OK
155
function engine.nearcolor(r, g, b)
156
    check_colcomp(r)
157
    check_colcomp(g)
158
    check_colcomp(b)
159
    return C.getclosestcol(r, g, b)
160
end
161
 
162
 
163
-- Done!
164
return engine