92
86
Scanline = lists:duplicate(trunc(Xr - Xl + 1), <<R:8,G:8,B:8>>),
93
87
resulting_scanline(RLSs, Width, [Scanline|Scanlines]).
95
%print_line_spans([]) -> io:format("~n"), ok;
96
%print_line_spans([{_,Xl,Xr,_}|LSs]) ->
97
% io:format("[~p,~p]", [Xl,Xr]),
98
% print_line_spans(LSs).
100
%check_binary(Bin, {_,_,W, _}) ->
101
% Size = erlang:size(erlang:list_to_binary(Bin)),
102
% ScanlineWidth = trunc(Size/3),
104
% ScanlineWidth =/= W + 1 ->
105
% io:format("check_binary: Image width ~p vs. Scanline width ~p~n", [W+1,ScanlineWidth]),
110
%check_line_spans([]) -> ok;
111
%check_line_spans([_]) -> ok;
112
%check_line_spans([LSa, LSb | LSs]) ->
113
% {_,Xal,_Xar,_} = LSa,
114
% {_,_Xbl,Xbr,_} = LSb,
115
% Overlap = do_lines_overlap(LSa,LSb),
116
% LLSa = ls_length(LSa),
117
% LLSb = ls_length(LSb),
121
% io:format("check_line_spans:~p ~n", [Overlap]),
122
% debug_print_ls_states([{ls_left, LSa},{ls_right, LSb}]),
123
% throw({bad_length, ls_left});
125
% io:format("check_line_spans:~p ~n", [Overlap]),
126
% debug_print_ls_states([{ls_left, LSa},{ls_right, LSb}]),
127
% throw({bad_length, ls_right});
128
% Overlap =/= false ->
129
% io:format("check_line_spans:~p ~n", [Overlap]),
130
% debug_print_ls_states([{ls_left, LSa},{ls_right, LSb}]),
131
% throw(overlap_error);
133
% io:format("check_line_spans:~p~n", [Overlap]),
134
% debug_print_ls_states([{ls_left, LSa},{ls_right, LSb}]),
135
% throw(contiuation_error);
136
% true -> check_line_spans([LSb|LSs])
139
% resulting_line_spans
141
% LineIntervals = [line_span_data()]
145
% Reduce line spans. This function handles the overlapping color spans on a line.
146
% Måste troligen ha en sorterad lista med object, där översta objecte ligger först i stacken.
147
% FÖr varje object måste man titta under och se vilka den överlappar och antingen,
149
% Ta bort de som täcks eller dela upp underliggande span från det överlappande.
153
resulting_line_spans([], _, MLSs) -> MLSs;
154
resulting_line_spans([LS|LSs], Type, MLSs) ->
155
resulting_line_spans(LSs, Type, merge_line_spans(LS, MLSs, Type)).
159
% In: merge_line_spans/3
160
% CLS :: line_span_data(), current line span
161
% MLSs :: [line_span_data()] (non overlapping, continious, unsorted)
162
% Type :: alpha | opaque (render engine, color blending or not)
163
% In: merge_line_spans/3
164
% CLSs :: [line_span_data()], current line spans
165
% LMLSs :: [line_span_data()], left merged line spans (iter)
166
% RMLSs :: [line_span_data()], right merged line spans (iter)
167
% Type :: alpha | opaque (render engine, color blending or not)
169
% [line_span_data()] (non overlapping, continious, unsorted)
171
% Entwines color intervals with non overlapping color intervals,
172
% Remember: CLS may split and become several CLSs (at least two) -> handle it.
175
merge_line_spans(CLS, MLSs, Type) ->
176
merge_line_spans([CLS], [], MLSs, Type). % init
177
merge_line_spans(CLS, [], [], _Type) ->
178
CLS; % If it is the first line span of MLSs
179
merge_line_spans(CLSs, MLSs, [], _Type) ->
180
lists:flatten([CLSs|MLSs]); % Here we have iterated through all MLSs; add CLSs.
181
merge_line_spans([], LMLSs, RMLSs, _Type) ->
182
lists:flatten([LMLSs|RMLSs]); % FIXME: optimize? all CLSs is shadowed (in opaque)
183
merge_line_spans(CLSs, LMLSs, [ILS|RMLSs], Type) ->
184
merge_line_spans([], CLSs, LMLSs, ILS, RMLSs, Type).
186
merge_line_spans(LCLSs, [], LMLSs, ILS, RMLSs, Type) ->
187
merge_line_spans(LCLSs, [ILS|LMLSs], RMLSs, Type);
188
merge_line_spans(LCLSs, [{Zc,Xcl,Xcr,Cc}=CLS|RCLSs], LMLSs, {_Zi,Xil,Xir,_Ci}=ILS, RMLSs, opaque) ->
189
% Compare the current line span with the iterating one and see if
190
% something shines through the overlapping object.
191
% Think: How does each RMLS affect the CLS object if they overlap?
193
% ILS ------------ (upper)
194
% CLS ------------ (lower)
195
case do_lines_overlap(CLS,ILS) of
196
% the current line span is ...
197
left_partial -> % cut it
198
CLS0 = {Zc, Xcl, Xil - 1, Cc},
199
merge_line_spans([CLS0|LCLSs], RCLSs, LMLSs, ILS, RMLSs, opaque);
200
right_partial -> % cut it
201
CLS0 = {Zc, Xir + 1, Xcr, Cc},
202
merge_line_spans([CLS0|LCLSs], RCLSs, LMLSs, ILS, RMLSs, opaque);
203
outspaced -> % split and cut it
204
CLS0l = {Zc, Xcl, Xil - 1, Cc},
205
CLS0r = {Zc, Xir + 1, Xcr, Cc},
206
% Are we not supposed to put CLS0r in RCLSs to view it with other
207
% MLSs? Seems to work now though...
208
merge_line_spans([CLS0l, CLS0r | LCLSs], RCLSs, LMLSs, ILS, RMLSs, opaque);
209
shadowed -> % drop it
210
merge_line_spans(LCLSs, RCLSs, LMLSs, ILS, RMLSs, opaque);
212
merge_line_spans([CLS|LCLSs], RCLSs, LMLSs, ILS, RMLSs, opaque) % do the same for the next CLS
214
merge_line_spans(LCLSs, [{Zc,Xcl,Xcr,Cc}=CLS|RCLSs], LMLSs, {Zi,Xil,Xir,Ci}=ILS, RMLSs, alpha) ->
215
% ILS ------------ (upper)
216
% CLS ------------ (lower)
217
case do_lines_overlap(CLS,ILS) of
218
% the current line span is ...
219
left_partial -> % cut it
222
CLS0 = {Zc, Xcl, Xil - 1, Cc}, % Cut current line span
223
ALS = {Zi, Xil, Xcr, alpha_blend(Ci,Cc)}, % alphalized part of iterating line span
224
ILS0 = {Zi, Xcr + 1, Xir, Ci}, % Cut part of iterating line span
225
% ok = check_line_spans([ILS0, ALS, CLS0]),
226
merge_line_spans([CLS0|LCLSs], RCLSs, LMLSs, ALS, [ILS0|RMLSs], alpha);
228
CLS0 = {Zc, Xcl, Xil - 1, Cc}, % Cut current line span
229
ALS = {Zi, Xil, Xcr, alpha_blend(Ci,Cc)}, % alphalized part of iterating line span
230
% ok = check_line_spans([ALS, CLS0]),
231
merge_line_spans([CLS0|LCLSs], RCLSs, LMLSs, ALS, RMLSs, alpha)
233
right_partial -> % cut it
236
ILS0 = {Zi, Xil, Xcl - 1, Ci}, % Cut part of iterating line span
237
ALS = {Zi, Xcl, Xir, alpha_blend(Ci,Cc)}, % alphalized part of iterating line span
238
CLS0 = {Zc, Xir + 1, Xcr, Cc}, % Cut current line span
239
% ok = check_line_spans([CLS0, ALS, ILS0]),
240
merge_line_spans([CLS0|LCLSs], RCLSs, LMLSs, ILS0, [ALS|RMLSs],alpha);
242
ALS = {Zi, Xcl, Xir, alpha_blend(Ci,Cc)}, % alphalized part of iterating line span
243
CLS0 = {Zc, Xir + 1, Xcr, Cc}, % Cut current line span
244
% ok = check_line_spans([CLS0, ALS]),
245
merge_line_spans([CLS0|LCLSs], RCLSs, LMLSs, ALS, RMLSs, alpha)
247
outspaced -> % split and cut it
248
CLS0l = {Zc, Xcl, Xil - 1, Cc},
249
ALS = {Zi, Xil, Xir, alpha_blend(Ci,Cc)},
250
CLS0r = {Zc, Xir + 1, Xcr, Cc},
251
% ok = check_line_spans([CLS0r, ALS, CLS0l]),
252
merge_line_spans([CLS0l,CLS0r | LCLSs], RCLSs, LMLSs, ALS, RMLSs, alpha);
253
shadowed -> % dont drop it, alpha it
255
Xil == Xcl , Xir == Xcr ->
256
ALS = {Zi, Xil, Xir, alpha_blend(Ci,Cc)},
257
merge_line_spans(LCLSs, RCLSs, LMLSs, ALS, RMLSs, alpha);
259
ALS = {Zi, Xil, Xcr, alpha_blend(Ci,Cc)},
260
ILSr = {Zi, Xcr + 1, Xir, Ci},
261
% ok = check_line_spans([ILSr, ALS]),
262
merge_line_spans(LCLSs, RCLSs, LMLSs, ALS, [ILSr|RMLSs], alpha);
264
ILSl = {Zi, Xil, Xcl - 1, Ci},
265
ALS = {Zi, Xcl, Xcr, alpha_blend(Ci,Cc)},
266
% ok = check_line_spans([ALS,ILSl]),
267
merge_line_spans(LCLSs, RCLSs, LMLSs, ILSl, [ALS|RMLSs], alpha);
269
ILS0l = {Zi, Xil, Xcl - 1, Ci},
270
ALS = {Zc, Xcl, Xcr, alpha_blend(Ci,Cc)},
271
ILS0r = {Zi, Xcr + 1, Xir, Ci},
272
% ok = check_line_spans([ILS0r, ALS, ILS0l]),
273
merge_line_spans(LCLSs, RCLSs, LMLSs, ILS0l, [ILS0r,ALS|RMLSs], alpha)
276
merge_line_spans([CLS|LCLSs], RCLSs, LMLSs, ILS, RMLSs, alpha) % do the same for the next CLS
89
resulting_line_spans(LSs,Type) ->
90
%% Build a list of "transitions" from left to right.
91
Trans = line_spans_to_trans(LSs),
92
%% Convert list of "transitions" to linespans.
93
trans_to_line_spans(Trans,Type).
95
line_spans_to_trans(LSs) ->
97
line_spans_to_trans(LSs,Trans,0).
99
line_spans_to_trans([],Db,_) ->
101
line_spans_to_trans([{_,L,R,C}|LSs],Db,Z) ->
102
line_spans_to_trans(LSs,[{{L,Z,start},C},{{R+1,Z,stop},C}|Db],Z+1).
104
trans_to_line_spans(Trans,Type) ->
105
trans_to_line_spans(simplify_trans(Trans,Type,[],{0,0,0,0},[])).
107
trans_to_line_spans(SimpleTrans) ->
108
trans_to_line_spans1(SimpleTrans,[]).
110
trans_to_line_spans1([],Spans) ->
112
trans_to_line_spans1([_],Spans) ->
114
trans_to_line_spans1([{L1,_},{L2,C2}|SimpleTrans],Spans) ->
115
%% We are going backwards now...
116
trans_to_line_spans1([{L2,C2}|SimpleTrans],[{?DummyC,L2,L1-1,C2}|Spans]).
118
simplify_trans([],_,_,_,Acc) ->
120
simplify_trans([{{L,_,_},_}|_] = Trans,Type,Layers,OldC,Acc) ->
121
{NextTrans,RestTrans} =
122
lists:splitwith(fun({{L1,_,_},_}) when L1 == L ->
127
{C,NewLayers} = color(NextTrans,Layers,Type,OldC),
129
C -> %% No change in color, so transition unnecessary.
130
simplify_trans(RestTrans,Type,NewLayers,OldC,Acc);
132
simplify_trans(RestTrans,Type,NewLayers,C,[{L,C}|Acc])
135
color(Trans,Layers,Type,OldC) ->
136
case modify_layers(Layers,Trans) of
140
{color(NewLayers,Type),NewLayers}
143
color([],_) -> {0,0,0,0};
144
color([{_,C}|_],opaque) -> C;
145
color(Layers,alpha) -> color1({0,0,0,0},Layers).
147
color1(Color,[]) -> Color;
148
color1(Color,[{_,C}|Layers]) -> color1(blend(Color,C),Layers).
150
blend(C1,C2) -> alpha_blend(C1,C2).
152
modify_layers(Layers,[]) -> Layers;
153
modify_layers(Layers,[{{_,Z,Op},C}|Trans]) ->
154
modify_layers(case Op of
156
add_layer(Layers,Z,C);
158
remove_layer(Layers,Z,C)
162
add_layer([{Z1,_}=H|Layers],Z,C) when Z1 > Z ->
163
[H|add_layer(Layers,Z,C)];
164
add_layer(Layers,Z,C) ->
167
remove_layer(Layers,Z,C) ->
281
171
alpha_blend({R1,G1,B1,A1}, {R2,G2,B2,A2}) ->
282
172
Beta = A2*(1 - A1),