7b964fcf6acdb9fe59d12f3dd19fcf3e7a4a3eca
[goodguy/history.git] / cinelerra-5.1 / 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 _("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.tag.set_title("/SCALE");
132         output.append_tag();
133         output.append_newline();
134         output.terminate_string();
135 // data is now in *text
136 }
137
138 void ScaleMain::read_data(KeyFrame *keyframe)
139 {
140         FileXML input;
141
142         input.set_shared_input(keyframe->get_data(), strlen(keyframe->get_data()));
143
144         int result = 0;
145         config.constrain = 0;
146
147         while(!result)
148         {
149                 result = input.read_tag();
150
151                 if(!result)
152                 {
153                         if(input.tag.title_is("SCALE"))
154                         {
155                                 config.type = input.tag.get_property("TYPE", config.type);
156                                 config.x_factor = input.tag.get_property("X_FACTOR", config.x_factor);
157                                 config.y_factor = input.tag.get_property("Y_FACTOR", config.y_factor);
158                                 config.constrain = input.tag.get_property("CONSTRAIN", config.constrain);
159                                 config.width = input.tag.get_property("WIDTH", config.x_factor);
160                                 config.height = input.tag.get_property("HEIGHT", config.y_factor);
161                         }
162                 }
163         }
164 }
165
166
167
168
169
170
171
172
173 int ScaleMain::process_buffer(VFrame *frame,
174         int64_t start_position,
175         double frame_rate)
176 {
177         VFrame *input, *output;
178         input = output = frame;
179
180         load_configuration();
181         read_frame(frame, 0, start_position, frame_rate, get_use_opengl());
182
183 // No scaling
184         if( config.type == FIXED_SCALE ?
185                 config.x_factor == 1 && config.y_factor == 1 :
186                 config.width == frame->get_w() && config.height == frame->get_h() )
187                 return 0;
188
189         if(get_use_opengl()) return run_opengl();
190
191         VFrame *temp_frame = new_temp(frame->get_w(), frame->get_h(),
192                         frame->get_color_model());
193         temp_frame->copy_from(frame);
194         input = temp_frame;
195
196         if(!overlayer)
197         {
198                 overlayer = new OverlayFrame(PluginClient::get_project_smp() + 1);
199         }
200
201
202 // Perform scaling
203         float in_x1, in_x2, in_y1, in_y2, out_x1, out_x2, out_y1, out_y2;
204         calculate_transfer(output,
205                 in_x1, in_x2, in_y1, in_y2,
206                 out_x1, out_x2, out_y1, out_y2);
207         output->clear_frame();
208
209 // printf("ScaleMain::process_realtime 3 output=%p input=%p config.x_factor=%f config.y_factor=%f"
210 //      " config.width=%d config.height=%d config.type=%d   %f %f %f %f -> %f %f %f %f\n",
211 //      output, input, config.x_factor, config.y_factor, config.width, config.height, config.type,
212 //      in_x1, in_y1, in_x2, in_y2, out_x1, out_y1, out_x2, out_y2);
213         overlayer->overlay(output, input,
214                 in_x1, in_y1, in_x2, in_y2,
215                 out_x1, out_y1, out_x2, out_y2,
216                 1, TRANSFER_REPLACE, get_interpolation_type());
217
218         return 0;
219 }
220
221 void ScaleMain::calculate_transfer(VFrame *frame,
222         float &in_x1, float &in_x2, float &in_y1, float &in_y2,
223         float &out_x1, float &out_x2, float &out_y1, float &out_y2)
224 {
225         float fw = (float)frame->get_w();
226         float fh = (float)frame->get_h();
227         in_x1 = in_y1 = 0;
228         in_x2 = fw;
229         in_y2 = fh;
230         float x_factor = config.type == FIXED_SCALE ? config.x_factor :
231                 in_x2 > 0. ? (float)config.width / in_x2 : 0;
232         float y_factor = config.type == FIXED_SCALE ? config.y_factor :
233                 in_y2 > 0. ? (float)config.height / in_y2 : 0;
234
235         float fw2 = fw/2, fw2s = fw2*x_factor;
236         float fh2 = fh/2, fh2s = fh2*y_factor;
237         out_x1 = fw2 - fw2s;
238         out_x2 = fw2 + fw2s;
239         out_y1 = fh2 - fh2s;
240         out_y2 = fh2 + fh2s;
241
242         if(out_x1 < 0) {
243                 in_x1 = x_factor>0 ? in_x1 - out_x1/x_factor : 0;
244                 out_x1 = 0;
245         }
246
247         if(out_x2 > frame->get_w()) {
248                 in_x2 = x_factor>0 ? in_x2 - (out_x2-frame->get_w())/x_factor : 0;
249                 out_x2 = frame->get_w();
250         }
251
252         if(out_y1 < 0) {
253                 in_y1 = y_factor>0 ? in_y1 - out_y1/y_factor : 0;
254                 out_y1 = 0;
255         }
256
257         if(out_y2 > frame->get_h()) {
258                 in_y2 = y_factor>0 ? in_y2 - (out_y2-frame->get_h())/y_factor : 0;
259                 out_y2 = frame->get_h();
260         }
261 }
262
263 int ScaleMain::handle_opengl()
264 {
265 #ifdef HAVE_GL
266         float in_x1, in_x2, in_y1, in_y2, out_x1, out_x2, out_y1, out_y2;
267         calculate_transfer(get_output(),
268                 in_x1, in_x2, in_y1, in_y2,
269                 out_x1, out_x2, out_y1, out_y2);
270
271         get_output()->to_texture();
272         get_output()->enable_opengl();
273         get_output()->init_screen();
274         get_output()->clear_pbuffer();
275         get_output()->bind_texture(0);
276         get_output()->draw_texture(
277                 in_x1, in_y1, in_x2, in_y2,
278                 out_x1, out_y1, out_x2, out_y2);
279         get_output()->set_opengl_state(VFrame::SCREEN);
280 #endif
281         return 0;
282 }
283
284
285
286 NEW_WINDOW_MACRO(ScaleMain, ScaleWin)
287
288 void ScaleMain::update_gui()
289 {
290         if(thread)
291         {
292                 load_configuration();
293                 thread->window->lock_window();
294                 set_type(config.type);
295                 ScaleWin *swin = (ScaleWin *)thread->window;
296                 swin->x_factor->update(config.x_factor);
297                 swin->y_factor->update(config.y_factor);
298                 swin->width->update((int64_t)config.width);
299                 swin->height->update((int64_t)config.height);
300                 swin->constrain->update(config.constrain);
301                 thread->window->unlock_window();
302         }
303 }
304
305
306