bg/clr color tweaks, clear borders rework, fc31 depends
[goodguy/cinelerra.git] / cinelerra-5.1 / plugins / edge / edge.C
1 /*
2  * CINELERRA
3  * Copyright (C) 1997-2015 Adam Williams <broadcast at earthling dot net>
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  *
19  */
20
21 #include "affine.h"
22 #include "bcsignals.h"
23 #include "clip.h"
24 #include "filexml.h"
25 #include "edge.h"
26 #include "edgewindow.h"
27 #include "language.h"
28 #include "transportque.inc"
29 #include <string.h>
30
31 REGISTER_PLUGIN(Edge)
32
33 EdgeConfig::EdgeConfig()
34 {
35         amount = 8;
36 }
37
38 int EdgeConfig::equivalent(EdgeConfig &that)
39 {
40         if(this->amount != that.amount) return 0;
41         return 1;
42 }
43
44 void EdgeConfig::copy_from(EdgeConfig &that)
45 {
46         this->amount = that.amount;
47 }
48
49 void EdgeConfig::interpolate( EdgeConfig &prev, EdgeConfig &next,
50                 long prev_frame, long next_frame, long current_frame)
51 {
52         copy_from(next);
53 }
54
55 void EdgeConfig::limits()
56 {
57         CLAMP(amount, 0, 10);
58 }
59
60
61 Edge::Edge(PluginServer *server)
62  : PluginVClient(server)
63 {
64         engine = 0;
65         dst = 0;
66 }
67
68 Edge::~Edge()
69 {
70         delete engine;
71         delete dst;
72 }
73
74 const char* Edge::plugin_title() { return N_("Edge"); }
75 int Edge::is_realtime() { return 1; }
76
77 NEW_WINDOW_MACRO(Edge, EdgeWindow);
78 LOAD_CONFIGURATION_MACRO(Edge, EdgeConfig)
79
80 void Edge::save_data(KeyFrame *keyframe)
81 {
82         FileXML output;
83
84 // cause data to be stored directly in text
85         output.set_shared_output(keyframe->xbuf);
86
87         output.tag.set_title("EDGE");
88         output.tag.set_property("AMOUNT", config.amount);
89         output.append_tag();
90         output.append_newline();
91         output.tag.set_title("/EDGE");
92         output.append_tag();
93         output.append_newline();
94         output.terminate_string();
95 }
96
97 void Edge::read_data(KeyFrame *keyframe)
98 {
99         FileXML input;
100         input.set_shared_input(keyframe->xbuf);
101         int result = 0;
102
103         while( !(result=input.read_tag()) ) {
104                 if(input.tag.title_is("EDGE")) {
105                         config.amount = input.tag.get_property("AMOUNT", config.amount);
106                         config.limits();
107                 }
108                 else if(input.tag.title_is("/EDGE")) {
109                         result = 1;
110                 }
111         }
112
113 }
114
115 void Edge::update_gui()
116 {
117         if( !thread ) return;
118         if( !load_configuration() ) return;
119         thread->window->lock_window("Edge::update_gui");
120         EdgeWindow *window = (EdgeWindow*)thread->window;
121         window->flush();
122         thread->window->unlock_window();
123 }
124
125 int Edge::process_buffer(VFrame *frame, int64_t start_position, double frame_rate)
126 {
127         load_configuration();
128         src = frame;
129         w = src->get_w(), h = src->get_h();
130         color_model = frame->get_color_model();
131         bpp = BC_CModels::calculate_pixelsize(color_model);
132
133         if( dst && (dst->get_w() != w || dst->get_h() != h ||
134             dst->get_color_model() != color_model ) ) {
135                 delete dst;  dst = 0;
136         }
137         if( !dst )
138                 dst = new VFrame(w, h, color_model, 0);
139
140         if( !engine )
141                 engine = new EdgeEngine(this,
142                         PluginClient::get_project_smp() + 1,
143                         PluginClient::get_project_smp() + 1);
144
145         read_frame(frame, 0, start_position, frame_rate, 0);
146         engine->process_packages();
147         frame->copy_from(dst);
148         return 0;
149 }
150
151
152 EdgePackage::EdgePackage()
153  : LoadPackage()
154 {
155 }
156
157 EdgeUnit::EdgeUnit(EdgeEngine *server) : LoadClient(server)
158 {
159         this->server = server;
160 }
161
162 EdgeUnit::~EdgeUnit()
163 {
164 }
165
166 #define EDGE_MACRO(type, max, components, is_yuv) \
167 { \
168         int comps = MIN(components, 3); \
169         float amounts = amount * amount / max; \
170         for( int y=y1; y<y2; ++y ) { \
171                 uint8_t *row0 = input_rows[y], *row1 = input_rows[y+1]; \
172                 uint8_t *outp = output_rows[y]; \
173                 for( int x=x1; x<x2; ++x ) { \
174                         type *r0 = (type *)row0, *r1 = (type *)row1, *op = (type *)outp; \
175                         float h_grad = 0, v_grad = 0; \
176                         for( int i=0; i<comps; ++i,++r0,++r1 ) { \
177                                 float dh = -r0[0] - r0[components] + r1[0] + r1[components]; \
178                                 if( (dh*=dh) > h_grad ) h_grad = dh; \
179                                 float dv =  r0[0] - r0[components] + r1[0] - r1[components]; \
180                                 if( (dv*=dv) > v_grad ) v_grad = dv; \
181                         } \
182                         float v = (h_grad + v_grad) * amounts; \
183                         type t = v > max ? max : v; \
184                         if( is_yuv ) { \
185                                 *op++ = t;  *op++ = 0x80;  *op++ = 0x80; \
186                         } \
187                         else { \
188                                 for( int i=0; i<comps; ++i ) *op++ = t; \
189                         } \
190                         if( components == 4 ) *op = *r0; \
191                         row0 += bpp;  row1 += bpp;  outp += bpp; \
192                 } \
193         } \
194 } break
195
196
197 void EdgeUnit::process_package(LoadPackage *package)
198 {
199         VFrame *src = server->plugin->src;
200         uint8_t **input_rows = src->get_rows();
201         VFrame *dst = server->plugin->dst;
202         uint8_t **output_rows = dst->get_rows();
203         float amount = (float)server->plugin->config.amount;
204         EdgePackage *pkg = (EdgePackage*)package;
205         int x1 = 0, x2 = server->plugin->w-1, bpp = server->plugin->bpp;
206         int y1 = pkg->y1, y2 = pkg->y2;
207
208         switch( server->plugin->color_model ) {
209         case BC_RGB_FLOAT:  EDGE_MACRO(float, 1, 3, 0);
210         case BC_RGBA_FLOAT: EDGE_MACRO(float, 1, 4, 0);
211         case BC_RGB888:     EDGE_MACRO(unsigned char, 0xff, 3, 0);
212         case BC_YUV888:     EDGE_MACRO(unsigned char, 0xff, 3, 1);
213         case BC_RGBA8888:   EDGE_MACRO(unsigned char, 0xff, 4, 0);
214         case BC_YUVA8888:   EDGE_MACRO(unsigned char, 0xff, 4, 1);
215         }
216 }
217
218
219 EdgeEngine::EdgeEngine(Edge *plugin, int total_clients, int total_packages)
220  : LoadServer(total_clients, total_packages)
221 {
222         this->plugin = plugin;
223 }
224
225 EdgeEngine::~EdgeEngine()
226 {
227 }
228
229
230 void EdgeEngine::init_packages()
231 {
232         int y = 0, h1 = plugin->h-1;
233         for(int i = 0; i < get_total_packages(); ) {
234                 EdgePackage *pkg = (EdgePackage*)get_package(i++);
235                 pkg->y1 = y;
236                 y = h1 * i / LoadServer::get_total_packages();
237                 pkg->y2 = y;
238         }
239 }
240
241 LoadClient* EdgeEngine::new_client()
242 {
243         return new EdgeUnit(this);
244 }
245
246 LoadPackage* EdgeEngine::new_package()
247 {
248         return new EdgePackage;
249 }
250