Subversion Repositories eduke32

Rev

Rev 4262 | Rev 4308 | 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
 
4301 helixhorne 21
const char *getblendtab(int32_t blend);
22
void setblendtab(int32_t blend, const char *tab);
23
 
4236 helixhorne 24
int32_t setpalookup(int32_t palnum, const uint8_t *shtab);
25
]]
26
 
27
----------
28
 
4242 helixhorne 29
 
4236 helixhorne 30
-- The API table
31
local engine = {}
32
 
4242 helixhorne 33
 
34
local shtab_t  -- forward-decl
35
 
4301 helixhorne 36
local function cast_u8ptr(sth)
37
    return ffi.cast("uint8_t *", sth)
4242 helixhorne 38
end
39
 
40
local shtab_methods = {
41
    -- Remap consecutive blocks of 16 color indices and return this new shade
42
    -- table.
43
    --
4256 helixhorne 44
    -- <idxs16>: table with idxs16[0] .. idxs16[15] >= 0 and <= 15
45
    --  (i.e. 0-based indices of such 16-tuples)
4242 helixhorne 46
    --
47
    -- For example, the table
48
    --  { [0]=0,1, 2,3, 5,4, 6,7, 8,13, 10,11, 12,9, 14,15 }
49
    -- TODO (...)
50
    remap16 = function(sht, idxs16)
51
        if (type(idxs16) ~= "table" or idxs16[0]==nil or #idxs16 ~= 15) then
52
            error("invalid argument #2: must be a [0]-table with 16 elements", 2)
53
        end
54
 
55
        for i=0,15 do
56
            if (not (idxs16[i] >= 0 and idxs16[i] <= 15)) then
57
                error("invalid reordering table: elements must be in [0 .. 15]", 2)
58
            end
59
        end
60
 
61
        local newsht = shtab_t()
62
        for sh=0,31 do
63
            for i=0,15 do
64
                ffi.copy(cast_u8ptr(newsht[sh]) + 16*i,
65
                         cast_u8ptr(sht[sh]) + 16*idxs16[i], 16)
66
            end
67
        end
68
        return newsht
69
    end,
70
}
71
 
72
local function shtab_mt__index(sht, idx)
73
    local method = shtab_methods[idx]
74
    if (method) then
75
        return method
76
    end
77
end
78
 
4301 helixhorne 79
local pal256_t = bcarray.new("uint8_t", 256, "color index 256-tuple")
4236 helixhorne 80
-- The shade table type, effectively a bound-checked uint8_t [32][256]:
4242 helixhorne 81
shtab_t = bcarray.new(pal256_t, 32, "shade table", nil, nil, { __index = shtab_mt__index })
4236 helixhorne 82
local SIZEOF_SHTAB = ffi.sizeof(shtab_t)
83
 
4301 helixhorne 84
local blendtab_t = bcarray.new(pal256_t, 256, "blending table")
85
local SIZEOF_BLENDTAB = ffi.sizeof(blendtab_t)
86
 
4236 helixhorne 87
local RESERVEDPALS = 8  -- KEEPINSYNC build.h: assure that ours is >= theirs
88
engine.RESERVEDPALS = RESERVEDPALS
89
 
4301 helixhorne 90
local MAXBLENDTABS = 256  -- KEEPINSYNC build.h
91
 
4236 helixhorne 92
local function check_palidx(i)
93
    if (type(i) ~= "number" or not (i >= 0 and i <= 255-RESERVEDPALS)) then
4262 helixhorne 94
        error("invalid argument #1: palette swap index must be in the range [0 .. "..255-RESERVEDPALS.."]", 3)
4236 helixhorne 95
    end
96
end
97
 
4301 helixhorne 98
local function check_blendidx(i)
99
    if (type(i) ~= "number" or not (i >= 0 and i <= MAXBLENDTABS-1)) then
100
        error("invalid argument #1: blending table index must be in the range [0 .. ".. MAXBLENDTABS-1 .."]", 3)
101
    end
102
end
103
 
4236 helixhorne 104
local function err_uncommon_shade_table(ret)
105
    if (ret == -1) then
106
        error("loaded engine shade tables don't have 32 gradients of shade", 3)
107
    end
108
end
109
 
110
local function palookup_isdefault(palnum)  -- KEEPINSYNC engine.c
111
    return (C.palookup[palnum] == nil or (palnum ~= 0 and C.palookup[palnum] == C.palookup[0]))
112
end
113
 
114
function engine.shadetab()
115
    return shtab_t()
116
end
117
 
4301 helixhorne 118
function engine.blendtab()
119
    return blendtab_t()
120
end
121
 
4236 helixhorne 122
function engine.getshadetab(palidx)
123
    check_palidx(palidx)
124
    if (palookup_isdefault(palidx)) then
125
        return nil
126
    end
127
 
128
    local ret = C.setpalookup(palidx, nil)
129
    err_uncommon_shade_table(ret)
130
 
131
    local sht = shtab_t()
132
    ffi.copy(sht, C.palookup[palidx], SIZEOF_SHTAB)
133
    return sht
134
end
135
 
4301 helixhorne 136
function engine.getblendtab(blendidx)
137
    check_blendidx(blendidx)
138
 
139
    local ptr = C.getblendtab(blendidx)
140
    if (ptr == nil) then
141
        return nil
142
    end
143
 
144
    local tab = blendtab_t()
145
    ffi.copy(tab, ptr, SIZEOF_BLENDTAB)
146
    return tab
147
end
148
 
149
 
150
local function check_first_time()
4236 helixhorne 151
    if (not ismapster32 and C.g_elFirstTime == 0) then
4301 helixhorne 152
        error("may be called only while LUNATIC_FIRST_TIME is true", 3)
4236 helixhorne 153
    end
4301 helixhorne 154
end
4236 helixhorne 155
 
4301 helixhorne 156
function engine.setshadetab(palidx, shtab)
157
    check_first_time()
4236 helixhorne 158
    check_palidx(palidx)
4301 helixhorne 159
 
160
    if (not ffi.istype(shtab_t, shtab)) then
4236 helixhorne 161
        error("invalid argument #2: must be a shade table obtained by shadetab()", 2)
162
    end
163
 
164
    if (not ismapster32 and not palookup_isdefault(palidx)) then
165
        error("attempt to override already defined shade table", 2)
166
    end
167
 
4301 helixhorne 168
    local ret = C.setpalookup(palidx, cast_u8ptr(shtab))
4236 helixhorne 169
    err_uncommon_shade_table(ret)
170
end
171
 
4301 helixhorne 172
function engine.setblendtab(blendidx, tab)
173
    check_first_time()
174
    check_blendidx(blendidx)
4236 helixhorne 175
 
4301 helixhorne 176
    if (not ffi.istype(blendtab_t, tab)) then
177
        error("invalid argument #2: must be a blending table obtained by blendtab()", 2)
178
    end
179
 
180
    if (not ismapster32 and C.getblendtab(blendidx) ~= nil) then
181
        error("attempt to override already defined blending table", 2)
182
    end
183
 
184
    C.setblendtab(blendidx, cast_u8ptr(tab))
185
end
186
 
187
 
4236 helixhorne 188
local function check_colcomp(a)
189
    if (type(a) ~= "number" or not (a >= 0 and a <= 63)) then
190
        error("color component must be in the range [0 .. 63]", 3)
191
    end
192
end
193
 
194
 
195
-- TODO: other base palettes?
196
function engine.getrgb(colidx)
197
    if (type(colidx) ~= "number" or not (colidx >= 0 and colidx <= 255)) then
198
        error("color index must be in the range [0 .. 255]", 2)
199
    end
200
 
4301 helixhorne 201
    -- NOTE: In the game, palette[255*{0..2}] is set to 0 in
202
    -- G_LoadExtraPalettes() via G_Startup(). However, that's after Lua state
203
    -- initialization (i.e. when LUNATIC_FIRST_TIME would be true), and in the
204
    -- editor, it's never changed from the purple color. Therefore, I think
205
    -- it's more useful to always return the fully black color here.
206
    if (colidx == 255) then
207
        return 0, 0, 0
208
    end
209
 
4236 helixhorne 210
    local rgbptr = C.palette + 3*colidx
211
    return rgbptr[0], rgbptr[1], rgbptr[2]
212
end
213
 
214
-- TODO: flag whether fullbrights are OK
215
function engine.nearcolor(r, g, b)
216
    check_colcomp(r)
217
    check_colcomp(g)
218
    check_colcomp(b)
219
    return C.getclosestcol(r, g, b)
220
end
221
 
222
 
223
-- Done!
224
return engine