hard edges rework, add hard edge in gwdw, config.ac nv/cuda tweaks, message log warn...
[goodguy/cinelerra.git] / cinelerra-5.1 / plugins / mandelcuda / mandelbrot.C
1 /*
2  * CINELERRA
3  * Copyright (C) 1997-2014 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 "clip.h"
22 #include "filexml.h"
23 #include "mandelbrot.h"
24 #include "mandelbrotwindow.h"
25 #include "language.h"
26 #include "mutex.h"
27
28 #include "cwindow.h"
29 #include "cwindowgui.h"
30 #include "mwindow.h"
31 #include "pluginserver.h"
32 #include "playback3d.h"
33
34 REGISTER_PLUGIN(Mandelbrot)
35
36
37 MandelbrotConfig::MandelbrotConfig()
38 {
39 }
40
41 int MandelbrotConfig::equivalent(MandelbrotConfig &that)
42 {
43         return is_julia == that.is_julia && scale == that.scale &&
44                 x_off == that.x_off && y_off == that.y_off &&
45                 x_julia == that.x_julia && y_julia == that.y_julia &&
46                 color == that.color && crunch == that.crunch &&
47                 step == that.step;
48 }
49
50 void MandelbrotConfig::copy_from(MandelbrotConfig &that)
51 {
52         is_julia = that.is_julia;
53         x_off = that.x_off;
54         y_off = that.y_off;
55         scale = that.scale;
56         x_julia = that.x_julia;
57         y_julia = that.y_julia;
58         color = that.color;
59         crunch = that.crunch;
60         step = that.step;
61 }
62
63 void MandelbrotConfig::interpolate( MandelbrotConfig &prev, MandelbrotConfig &next, 
64         long prev_frame, long next_frame, long current_frame)
65 {
66         copy_from(prev);
67         double u = (double)(next_frame - current_frame) / (next_frame - prev_frame);
68         double v = 1. - u;
69         this->x_off = u*prev.x_off + v*next.x_off;
70         this->y_off = u*prev.y_off + v*next.y_off;
71         this->scale = u*prev.scale + v*next.scale;
72         this->x_julia = u*prev.x_julia + v*next.x_julia;
73         this->y_julia = u*prev.y_julia + v*next.y_julia;
74 }
75
76 void MandelbrotConfig::limits()
77 {
78         bclamp(scale, -1.e4, 1.e4);
79         bclamp(crunch, 1, 0x10000);
80 }
81
82
83 Mandelbrot::Mandelbrot(PluginServer *server)
84  : PluginVClient(server)
85 {
86         config.reset();
87         config.startJulia();
88         vfrm = 0;
89         img_w = img_h = 0;
90         pbo_id = -1;
91         animation_frame = 0;
92 }
93
94 Mandelbrot::~Mandelbrot()
95 {
96         delete vfrm;
97 }
98
99 const char* Mandelbrot::plugin_title() { return N_("Mandelbrot"); }
100 int Mandelbrot::is_realtime() { return 1; }
101 int Mandelbrot::is_synthesis() { return 1; }
102
103 NEW_WINDOW_MACRO(Mandelbrot, MandelbrotWindow);
104 LOAD_CONFIGURATION_MACRO(Mandelbrot, MandelbrotConfig)
105
106 void Mandelbrot::save_data(KeyFrame *keyframe)
107 {
108         FileXML output;
109         output.set_shared_output(keyframe->xbuf);
110         output.tag.set_title("MANDELCUDA");
111         output.tag.set_property("IS_JULIA", config.is_julia);
112         output.tag.set_property("SCALE", config.scale);
113         output.tag.set_property("X_OFF", config.x_off);
114         output.tag.set_property("Y_OFF", config.y_off);
115         output.tag.set_property("X_JULIA", config.x_julia);
116         output.tag.set_property("Y_JULIA", config.y_julia);
117         output.tag.set_property("COLOR", config.color);
118         output.tag.set_property("CRUNCH", config.crunch);
119         output.tag.set_property("STEP", config.step);
120         output.append_tag();
121         output.append_newline();
122         output.tag.set_title("/MANDELCUDA");
123         output.append_tag();
124         output.append_newline();
125         output.terminate_string();
126 }
127
128 void Mandelbrot::read_data(KeyFrame *keyframe)
129 {
130         FileXML input;
131         input.set_shared_input(keyframe->xbuf);
132
133         int result = 0;
134         while( !(result = input.read_tag()) ) {
135                 if( input.tag.title_is("MANDELCUDA") ) {
136                         config.is_julia = input.tag.get_property("IS_JULIA", config.is_julia);
137                         config.scale = input.tag.get_property("SCALE", config.scale);
138                         config.x_off = input.tag.get_property("X_OFF", config.x_off);
139                         config.y_off = input.tag.get_property("Y_OFF", config.y_off);
140                         config.x_julia = input.tag.get_property("X_JULIA", config.x_julia);
141                         config.y_julia = input.tag.get_property("Y_JULIA", config.y_julia);
142                         config.color = input.tag.get_property("COLOR", config.color);
143                         config.crunch = input.tag.get_property("CRUNCH", config.crunch);
144                         config.step = input.tag.get_property("STEP", config.step);
145                 }
146         }
147         config.limits();
148 }
149
150 void Mandelbrot::update_gui()
151 {
152         if( !thread ) return;
153         if( !load_configuration() ) return;
154         thread->window->lock_window("Mandelbrot::update_gui");
155         MandelbrotWindow *window = (MandelbrotWindow*)thread->window;
156         window->update_gui();
157         window->flush();
158         window->unlock_window();
159 }
160
161 void MandelbrotConfig::reset()
162 {
163         is_julia = 0;
164         x_julia = 0.0;
165         y_julia = 0.0;
166         x_off = -0.5;
167         y_off = 0.0;
168         scale = 3.2;
169         color = 0x00030507;
170         crunch = 512;
171         step = 0;
172 }
173
174 void MandelbrotConfig::startJulia()
175 {
176         is_julia = 1;
177         x_julia = -0.172400;
178         y_julia = -0.652693;
179         x_off = -0.085760;
180         y_off = 0.007040;
181 }
182
183 // Get a sub-pixel sample location
184 void Mandelbrot::GetSample(int sampleIndex, float &x, float &y)
185 {
186         static const unsigned char pairData[128][2] = {
187                 {64, 64}, {0, 0}, {1, 63}, {63, 1}, {96, 32}, {97, 95}, {36, 96}, {30, 31},
188                 {95, 127}, {4, 97}, {33, 62}, {62, 33}, {31, 126}, {67, 99}, {99, 65}, {2, 34},
189                 {81, 49}, {19, 80}, {113, 17}, {112, 112}, {80, 16}, {115, 81}, {46, 15}, {82, 79},
190                 {48, 78}, {16, 14}, {49, 113}, {114, 48}, {45, 45}, {18, 47}, {20, 109}, {79, 115},
191                 {65, 82}, {52, 94}, {15, 124}, {94, 111}, {61, 18}, {47, 30}, {83, 100}, {98, 50},
192                 {110, 2}, {117, 98}, {50, 59}, {77, 35}, {3, 114}, {5, 77}, {17, 66}, {32, 13},
193                 {127, 20}, {34, 76}, {35, 110}, {100, 12}, {116, 67}, {66, 46}, {14, 28}, {23, 93},
194                 {102, 83}, {86, 61}, {44, 125}, {76, 3}, {109, 36}, {6, 51}, {75, 89}, {91, 21},
195                 {60, 117}, {29, 43}, {119, 29}, {74, 70}, {126, 87}, {93, 75}, {71, 24}, {106, 102},
196                 {108, 58}, {89, 9}, {103, 23}, {72, 56}, {120, 8}, {88, 40}, {11, 88}, {104, 120},
197                 {57, 105}, {118, 122}, {53, 6}, {125, 44}, {43, 68}, {58, 73}, {24, 22}, {22, 5},
198                 {40, 86}, {122, 108}, {87, 90}, {56, 42}, {70, 121}, {8, 7}, {37, 52}, {25, 55},
199                 {69, 11}, {10, 106}, {12, 38}, {26, 69}, {27, 116}, {38, 25}, {59, 54}, {107, 72},
200                 {121, 57}, {39, 37}, {73, 107}, {85, 123}, {28, 103}, {123, 74}, {55, 85}, {101, 41},
201                 {42, 104}, {84, 27}, {111, 91}, {9, 19}, {21, 39}, {90, 53}, {41, 60}, {54, 26},
202                 {92, 119}, {51, 71}, {124, 101}, {68, 92}, {78, 10}, {13, 118}, {7, 84}, {105, 4}
203         };
204
205         x = (1.0f / 128.0f) * (0.5f + (float) pairData[sampleIndex][0]);
206         y = (1.0f / 128.0f) * (0.5f + (float) pairData[sampleIndex][1]);
207 } // GetSample
208
209 // render Mandelbrot image using CUDA
210 void Mandelbrot::renderImage()
211 {
212         float xs, ys;
213         // Get the anti-alias sub-pixel sample location
214         GetSample(pass & 127, xs, ys);
215
216         // Get the pixel scale and offset
217         double s = config.scale / (float) img_w;
218         double x  = (xs - (double) img_w * 0.5f) * s + config.x_off;
219         double y  = (ys - (double) img_h * 0.5f) * s + config.y_off;
220
221         uchar4 colors;
222         colors.w = (config.color>>24) & 0xff;
223         colors.x = (config.color>>16) & 0xff;
224         colors.y = (config.color>>8)  & 0xff;
225         colors.z = (config.color>>0)  & 0xff;
226
227         cuda.Run(vfrm->get_data(), img_w*img_h*4, config.is_julia, config.crunch,
228                 x, y, config.x_julia, config.y_julia, s, colors, pass, animation_frame);
229         ++pass;
230 }
231
232 void Mandelbrot::displayFunc()
233 {
234         if( config.step ) {
235                 animation_frame += config.step;
236                 pass = 0;
237         }
238         // render the Mandelbrot image
239         renderImage();
240 }
241
242 void Mandelbrot::init()
243 {
244         animation_frame = 0;
245         pass = 0;
246 }
247
248 int Mandelbrot::process_buffer(VFrame *frame, int64_t start_position, double frame_rate)
249 {
250
251         int need_reconfigure = load_configuration();
252         if( need_reconfigure ) pass = 0;
253         output = get_output(0);
254         color_model = output->get_color_model();
255         img_w = output->get_w();
256         img_h = output->get_h();
257         if( !start_position )
258                 init();
259         if( vfrm &&
260             (vfrm->get_w() != img_w || vfrm->get_h() != img_h) ) {
261                 delete vfrm;  vfrm = 0;
262         }
263         if( !vfrm )
264                 vfrm = new VFrame(img_w, img_h, BC_RGBA8888);
265
266         if( get_use_opengl() )
267                 return run_opengl();
268 // always use_opengl
269         Canvas *canvas = server->mwindow->cwindow->gui->canvas;
270         return server->mwindow->playback_3d->run_plugin(canvas, this);
271 }
272
273 // opengl from here down
274
275 void Mandelbrot::init_cuda()
276 {
277         cuda.init_dev();
278         GLuint pbo[1];
279         glGenBuffers(1, pbo);
280         glBindBuffer(GL_ARRAY_BUFFER, pbo_id=*pbo);
281         glBufferData(GL_ARRAY_BUFFER, img_w*img_h*4, 0, GL_STATIC_DRAW);
282         cuda.init(pbo_id, img_w, img_h);
283         glBindBuffer(GL_ARRAY_BUFFER, 0);
284 }
285 void Mandelbrot::finish_cuda()
286 {
287         cuda.finish();
288         GLuint pbo[1];  *pbo = pbo_id;
289         glDeleteBuffers(1, pbo);
290         pbo_id = -1;
291 }
292
293 int Mandelbrot::handle_opengl()
294 {
295         vfrm->enable_opengl();
296         vfrm->init_screen();
297         init_cuda();
298         displayFunc();
299         output->transfer_from(vfrm);
300         finish_cuda();
301         return 0;
302 }
303