initial commit
[goodguy/history.git] / cinelerra-5.0 / plugins / scale / scale.C
1
2 /*
3  * CINELERRA
4  * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
5  * 
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  * 
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  * 
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  * 
20  */
21
22 #include "clip.h"
23 #include "filexml.h"
24 #include "language.h"
25 #include "mwindow.h"
26 #include "pluginserver.h"
27 #include "scale.h"
28 #include "scalewin.h"
29
30 #include <string.h>
31
32
33 REGISTER_PLUGIN(ScaleMain)
34
35
36
37 ScaleConfig::ScaleConfig()
38 {
39         type = FIXED_SCALE;
40         x_factor = y_factor = 1;
41         width = height = 0;
42         constrain = 0;
43 }
44
45 void ScaleConfig::copy_from(ScaleConfig &src)
46 {
47         type = src.type;
48         x_factor = src.x_factor;
49         y_factor = src.y_factor;
50         constrain = src.constrain;
51         width = src.width;
52         height = src.height;
53 }
54 int ScaleConfig::equivalent(ScaleConfig &src)
55 {
56         return type != src.type ? 0 : type == FIXED_SCALE ? 
57                 EQUIV(x_factor, src.x_factor) && EQUIV(y_factor, src.y_factor) &&
58                         constrain == src.constrain :
59                 width == src.width && height == src.height;
60 }
61
62 void ScaleConfig::interpolate(ScaleConfig &prev, ScaleConfig &next, 
63         int64_t prev_frame, int64_t next_frame, int64_t current_frame)
64 {
65         double u = (double)(next_frame - current_frame) / (next_frame - prev_frame);
66         double v = 1. - u;
67
68         this->type = prev.type;
69         this->x_factor = u*prev.x_factor + v*next.x_factor;
70         this->y_factor = u*prev.y_factor + v*next.y_factor;
71         this->constrain = prev.constrain;
72         this->width = u*prev.width + v*next.width;
73         this->height = u*prev.height + v*next.height;
74 }
75
76
77
78 ScaleMain::ScaleMain(PluginServer *server)
79  : PluginVClient(server)
80 {
81         this->server = server;
82         overlayer = 0;
83 }
84
85 ScaleMain::~ScaleMain()
86 {
87         if(overlayer) delete overlayer;
88 }
89
90 const char* ScaleMain::plugin_title() { return N_("Scale"); }
91 int ScaleMain::is_realtime() { return 1; }
92
93
94
95 LOAD_CONFIGURATION_MACRO(ScaleMain, ScaleConfig)
96
97
98 void ScaleMain::set_type(int type)
99 {
100         if( type != config.type ) {
101                 config.type = type;
102                 ScaleWin *swin = (ScaleWin *)thread->window;
103                 int fixed_scale = type == FIXED_SCALE ? 1 : 0;
104                 swin->use_scale->update(fixed_scale);
105                 swin->x_factor->enabled = fixed_scale;
106                 swin->y_factor->enabled = fixed_scale;
107                 int fixed_size = 1 - fixed_scale;
108                 swin->use_size->update(fixed_size);
109                 swin->width->enabled = fixed_size;
110                 swin->height->enabled = fixed_size;
111                 send_configure_change();
112         }
113 }
114
115 void ScaleMain::save_data(KeyFrame *keyframe)
116 {
117         FileXML output;
118
119 // cause data to be stored directly in text
120         output.set_shared_output(keyframe->get_data(), MESSAGESIZE);
121
122 // Store data
123         output.tag.set_title("SCALE");
124         output.tag.set_property("TYPE", config.type);
125         output.tag.set_property("X_FACTOR", config.x_factor);
126         output.tag.set_property("Y_FACTOR", config.y_factor);
127         output.tag.set_property("WIDTH", config.width);
128         output.tag.set_property("HEIGHT", config.height);
129         output.tag.set_property("CONSTRAIN", config.constrain);
130         output.append_tag();
131         output.terminate_string();
132 // data is now in *text
133 }
134
135 void ScaleMain::read_data(KeyFrame *keyframe)
136 {
137         FileXML input;
138
139         input.set_shared_input(keyframe->get_data(), strlen(keyframe->get_data()));
140
141         int result = 0;
142         config.constrain = 0;
143
144         while(!result)
145         {
146                 result = input.read_tag();
147
148                 if(!result)
149                 {
150                         if(input.tag.title_is("SCALE"))
151                         {
152                                 config.type = input.tag.get_property("TYPE", config.type);
153                                 config.x_factor = input.tag.get_property("X_FACTOR", config.x_factor);
154                                 config.y_factor = input.tag.get_property("Y_FACTOR", config.y_factor);
155                                 config.constrain = input.tag.get_property("CONSTRAIN", config.constrain);
156                                 config.width = input.tag.get_property("WIDTH", config.x_factor);
157                                 config.height = input.tag.get_property("HEIGHT", config.y_factor);
158                         }
159                 }
160         }
161 }
162
163
164
165
166
167
168
169
170 int ScaleMain::process_buffer(VFrame *frame,
171         int64_t start_position,
172         double frame_rate)
173 {
174         VFrame *input, *output;
175         input = output = frame;
176
177         load_configuration();
178         read_frame(frame, 0, start_position, frame_rate, get_use_opengl());
179
180 // No scaling
181         if( config.type == FIXED_SCALE ?
182                 config.x_factor == 1 && config.y_factor == 1 :
183                 config.width == frame->get_w() && config.height == frame->get_h() )
184                 return 0;
185
186         if(get_use_opengl()) return run_opengl();
187
188         VFrame *temp_frame = new_temp(frame->get_w(), frame->get_h(),
189                         frame->get_color_model());
190         temp_frame->copy_from(frame);
191         input = temp_frame;
192
193         if(!overlayer)
194         {
195                 overlayer = new OverlayFrame(PluginClient::get_project_smp() + 1);
196         }
197
198
199 // Perform scaling
200         float in_x1, in_x2, in_y1, in_y2, out_x1, out_x2, out_y1, out_y2;
201         calculate_transfer(output,
202                 in_x1, in_x2, in_y1, in_y2, 
203                 out_x1, out_x2, out_y1, out_y2);
204         output->clear_frame();
205
206 // printf("ScaleMain::process_realtime 3 output=%p input=%p config.x_factor=%f config.y_factor=%f"
207 //      " config.width=%d config.height=%d config.type=%d   %f %f %f %f -> %f %f %f %f\n", 
208 //      output, input, config.x_factor, config.y_factor, config.width, config.height, config.type,
209 //      in_x1, in_y1, in_x2, in_y2, out_x1, out_y1, out_x2, out_y2);
210         overlayer->overlay(output, input,
211                 in_x1, in_y1, in_x2, in_y2,
212                 out_x1, out_y1, out_x2, out_y2, 
213                 1, TRANSFER_REPLACE, get_interpolation_type());
214
215         return 0;
216 }
217
218 void ScaleMain::calculate_transfer(VFrame *frame,
219         float &in_x1, float &in_x2, float &in_y1, float &in_y2, 
220         float &out_x1, float &out_x2, float &out_y1, float &out_y2)
221 {
222         float fw = (float)frame->get_w();
223         float fh = (float)frame->get_h();
224         in_x1 = in_y1 = 0;
225         in_x2 = fw;
226         in_y2 = fh;
227         float x_factor = config.type == FIXED_SCALE ? config.x_factor :
228                 in_x2 > 0. ? (float)config.width / in_x2 : 0;
229         float y_factor = config.type == FIXED_SCALE ? config.y_factor :
230                 in_y2 > 0. ? (float)config.height / in_y2 : 0;
231
232         float fw2 = fw/2, fw2s = fw2*x_factor;
233         float fh2 = fh/2, fh2s = fh2*y_factor;
234         out_x1 = fw2 - fw2s;
235         out_x2 = fw2 + fw2s;
236         out_y1 = fh2 - fh2s;
237         out_y2 = fh2 + fh2s;
238
239         if(out_x1 < 0) {
240                 in_x1 = x_factor>0 ? in_x1 - out_x1/x_factor : 0;
241                 out_x1 = 0;
242         }
243
244         if(out_x2 > frame->get_w()) {
245                 in_x2 = x_factor>0 ? in_x2 - (out_x2-frame->get_w())/x_factor : 0;
246                 out_x2 = frame->get_w();
247         }
248
249         if(out_y1 < 0) {
250                 in_y1 = y_factor>0 ? in_y1 - out_y1/config.y_factor : 0;
251                 out_y1 = 0;
252         }
253
254         if(out_y2 > frame->get_h()) {
255                 in_y2 = y_factor>0 ? in_y2 - (out_y2-frame->get_h())/y_factor : 0;
256                 out_y2 = frame->get_h();
257         }
258 }
259
260 int ScaleMain::handle_opengl()
261 {
262 #ifdef HAVE_GL
263         float in_x1, in_x2, in_y1, in_y2, out_x1, out_x2, out_y1, out_y2;
264         calculate_transfer(get_output(),
265                 in_x1, in_x2, in_y1, in_y2, 
266                 out_x1, out_x2, out_y1, out_y2);
267
268         get_output()->to_texture();
269         get_output()->enable_opengl();
270         get_output()->init_screen();
271         get_output()->clear_pbuffer();
272         get_output()->bind_texture(0);
273         get_output()->draw_texture(
274                 in_x1, in_y1, in_x2, in_y2, 
275                 out_x1, out_y1, out_x2, out_y2);
276         get_output()->set_opengl_state(VFrame::SCREEN);
277 #endif
278         return 0;
279 }
280
281
282
283 NEW_WINDOW_MACRO(ScaleMain, ScaleWin)
284
285 void ScaleMain::update_gui()
286 {
287         if(thread) 
288         {
289                 load_configuration();
290                 thread->window->lock_window();
291                 set_type(config.type);
292                 ScaleWin *swin = (ScaleWin *)thread->window;
293                 swin->x_factor->update(config.x_factor);
294                 swin->y_factor->update(config.y_factor);
295                 swin->width->update((int64_t)config.width);
296                 swin->height->update((int64_t)config.height);
297                 swin->constrain->update(config.constrain);
298                 thread->window->unlock_window();
299         }
300 }
301
302
303