add igors mask svgs, add composer clear_color pref, remove key DEL for mask gui,...
[goodguy/cinelerra.git] / cinelerra-5.1 / plugins / nbodycuda / nbody.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 #define GL_GLEXT_PROTOTYPES
22 #include <GL/gl.h>
23 #include <GL/glu.h>
24 #include <GL/glext.h>
25
26 #include "clip.h"
27 #include "filexml.h"
28 #include "language.h"
29 #include "mutex.h"
30
31 #include "cwindow.h"
32 #include "cwindowgui.h"
33 #include "mwindow.h"
34 #include "pluginserver.h"
35 #include "playback3d.h"
36
37 #include "nbody.h"
38 #include "nbodycuda.h"
39 #include "nbodywindow.h"
40
41
42 static struct N_BodyParams demoParams[] = {
43         { 0.016f, 1.54f, 8.0f,      0.1f, 1.0f, 1.0f,     0, -2, -100},
44         { 0.016f, 0.68f, 20.0f,     0.1f, 1.0f, 0.8f,     0, -2, -30},
45         { 0.0006f, 0.16f, 1000.0f,  1.0f, 1.0f, 0.07f,    0, 0, -1.5f},
46         { 0.0006f, 0.16f, 1000.0f,  1.0f, 1.0f, 0.07f,    0, 0, -1.5f},
47         { 0.0019f, 0.32f, 276.0f,   1.0f, 1.0f, 0.07f,    0, 0, -5},
48         { 0.0016f, 0.32f, 272.0f,   0.145f, 1.0f, 0.08f,  0, 0, -5},
49         { 0.0160f, 6.04f, 0.0f,     1.0f, 1.0f, 0.76f,    0, 0, -50},
50 };
51 const int N_BodyParams::num_demos = sizeof(demoParams)/sizeof(*demoParams);
52
53
54 REGISTER_PLUGIN(N_BodyMain)
55
56 void N_BodyConfig::reset(int i)
57 {
58         *(N_BodyParams*)this = demoParams[i];
59         trans[0] = trans_lag[0] = m_x;
60         trans[1] = trans_lag[1] = m_y;
61         trans[2] = trans_lag[2] = m_z;
62         rot[0] = rot_lag[0] = 0;
63         rot[1] = rot_lag[1] = 0;
64         rot[2] = rot_lag[2] = 0;
65         mode = ParticleRenderer::PARTICLE_SPRITES_COLOR;
66         numBodies = 4096;
67         inertia = 0.1;
68 }
69
70 N_BodyConfig::N_BodyConfig()
71 {
72         reset();
73 }
74
75 int N_BodyConfig::equivalent(N_BodyConfig &that)
76 {
77         return m_timestep == that.m_timestep &&
78                 m_clusterScale == that.m_clusterScale &&
79                 m_velocityScale == that.m_velocityScale &&
80                 m_softening == that. m_softening &&
81                 m_damping == that.m_damping &&
82                 m_pointSize == that.m_pointSize &&
83                 m_x == that.m_x &&
84                 m_y == that.m_y &&
85                 m_z == that.m_z &&
86                 trans[0] == that.trans[0] &&
87                 trans[1] == that.trans[1] &&
88                 trans[2] == that.trans[2] &&
89                 trans_lag[0] == that.trans_lag[0] &&
90                 trans_lag[1] == that.trans_lag[1] &&
91                 trans_lag[2] == that.trans_lag[2] &&
92                 rot[0] == that.rot[0] &&
93                 rot[1] == that.rot[1] &&
94                 rot[2] == that.rot[2] &&
95                 rot_lag[0] == that.rot_lag[0] &&
96                 rot_lag[1] == that.rot_lag[1] &&
97                 rot_lag[2] == that.rot_lag[2] &&
98                 inertia == that.inertia &&
99                 numBodies == that.numBodies;
100         return 1;
101 }
102
103 void N_BodyConfig::copy_from(N_BodyConfig &that)
104 {
105         m_timestep = that.m_timestep;
106         m_clusterScale = that.m_clusterScale;
107         m_velocityScale = that.m_velocityScale;
108         m_softening = that. m_softening;
109         m_damping = that.m_damping;
110         m_pointSize = that.m_pointSize;
111         m_x = that.m_x;
112         m_y = that.m_y;
113         m_z = that.m_z;
114         trans[0] = that.trans[0];
115         trans[1] = that.trans[1];
116         trans[2] = that.trans[2];
117         trans_lag[0] = that.trans_lag[0];
118         trans_lag[1] = that.trans_lag[1];
119         trans_lag[2] = that.trans_lag[2];
120         rot[0] = that.rot[0];
121         rot[1] = that.rot[1];
122         rot[2] = that.rot[2];
123         rot_lag[0] = that.rot_lag[0];
124         rot_lag[1] = that.rot_lag[1];
125         rot_lag[2] = that.rot_lag[2];
126         inertia = that.inertia;
127         numBodies = that.numBodies;
128 }
129
130 void N_BodyConfig::interpolate( N_BodyConfig &prev, N_BodyConfig &next, 
131         long prev_frame, long next_frame, long current_frame)
132 {
133         copy_from(next);
134 }
135
136 void N_BodyConfig::limits()
137 {
138         if( m_damping < 0.001 ) m_damping = 0.001;
139         if( trans[2] < 0.005 ) trans[2] = 0.005;
140         int n = 1;
141         while( n < numBodies ) n <<= 1;
142         bclamp(n, 0x0010, 0x4000);
143         numBodies = n;
144         bclamp(inertia, 0.f,1.f);
145         bclamp(mode, 0, (int)ParticleRenderer::PARTICLE_NUM_MODES-1);
146 }
147
148
149 N_BodyMain::N_BodyMain(PluginServer *server)
150  : PluginVClient(server)
151 {
152         cuda = 0;
153         blockSize = 256;
154
155         m_nbody = 0;
156         m_renderer = 0;
157         m_hPos = 0;
158         m_hVel = 0;
159         m_hColor = 0;
160
161         curr_position = -1;
162         new_position = -1;
163 }
164
165 N_BodyMain::~N_BodyMain()
166 {
167         delete cuda;
168 }
169
170 void N_BodyMain::init(int numBodies)
171 {
172         selectDemo(0);
173         delete m_nbody;      m_nbody = new N_BodySystem(numBodies, 1, blockSize);
174         int sz = numBodies*4;
175         delete [] m_hPos;    m_hPos = new float[sz];
176         delete [] m_hVel;    m_hVel = new float[sz];
177         delete [] m_hColor;  m_hColor = new float[sz];
178         delete m_renderer;   m_renderer = new ParticleRenderer;
179 // config here
180         m_nbody->setSoftening(config.m_softening);
181         m_nbody->setDamping(config.m_damping);
182         reset(numBodies, NBODY_CONFIG_RANDOM);
183         resetRenderer();
184 }
185
186 void N_BodyMain::reset(int numBodies, NBodyConfig cfg)
187 {
188         randomizeBodies(cfg, m_hPos, m_hVel, m_hColor,
189                 config.m_clusterScale, config.m_velocityScale,
190                 numBodies, true);
191         setArrays(m_hPos, m_hVel);
192 }
193
194 void N_BodyMain::resetRenderer()
195 {
196         float color[4] = { 1.0f, 0.6f, 0.3f, 1.0f};
197         m_renderer->setBaseColor(color);
198         m_renderer->setColors(m_hColor, m_nbody->getNumBodies());
199         m_renderer->setSpriteSize(config.m_pointSize);
200 }
201
202 void N_BodyMain::selectDemo(int index)
203 {
204         config.reset(index);
205 }
206
207 void N_BodyMain::finalize()
208 {
209         delete [] m_hPos;    m_hPos = 0;
210         delete [] m_hVel;    m_hVel = 0;
211         delete [] m_hColor;  m_hColor = 0;
212         delete m_nbody;      m_nbody = 0;
213         delete m_renderer;   m_renderer = 0;
214 }
215
216 void N_BodyMain::draw()
217 {
218         cuda->draw_event();
219         glClearColor(0.,0.,0.,1.);
220         glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
221         glColor4f(1.,1.,1.,1.);
222         glMatrixMode(GL_MODELVIEW);
223         glLoadIdentity();
224         float inertia = config.inertia;
225         for( int c=0; c<3; ++c ) {
226                 config.trans_lag[c] += (config.trans[c] - config.trans_lag[c]) * inertia;
227                 config.rot_lag[c] += (config.rot[c] - config.rot_lag[c]) * inertia;
228         }
229
230         glTranslatef(config.trans_lag[0], config.trans_lag[1], config.trans_lag[2]);
231         glRotatef(config.rot_lag[0], 1.0, 0.0, 0.0);
232         glRotatef(config.rot_lag[1], 0.0, 1.0, 0.0);
233         glDisable(GL_TEXTURE_2D);
234         display();
235 }
236
237
238 const char* N_BodyMain::plugin_title() { return N_("N_Body"); }
239 int N_BodyMain::is_realtime() { return 1; }
240 int N_BodyMain::is_synthesis() { return 1; }
241
242 NEW_WINDOW_MACRO(N_BodyMain, N_BodyWindow);
243 LOAD_CONFIGURATION_MACRO(N_BodyMain, N_BodyConfig)
244
245 void N_BodyMain::save_data(KeyFrame *keyframe)
246 {
247         FileXML output;
248
249 // cause data to be stored directly in text
250         output.set_shared_output(keyframe->xbuf);
251         output.tag.set_title("NBODYCUDA");
252         output.tag.set_property("TIMESTEP", config.m_timestep);
253         output.tag.set_property("CLUSTER_SCALE", config.m_clusterScale);
254         output.tag.set_property("VELOCITY_SCALE", config.m_velocityScale);
255         output.tag.set_property("SOFTENING", config.m_softening);
256         output.tag.set_property("DAMPING", config.m_damping);
257         output.tag.set_property("POINT_SIZE", config.m_pointSize);
258         output.tag.set_property("X", config.m_x);
259         output.tag.set_property("Y", config.m_y);
260         output.tag.set_property("Z", config.m_z);
261         output.tag.set_property("TRANS_X",config.trans[0]);
262         output.tag.set_property("TRANS_Y",config.trans[1]);
263         output.tag.set_property("TRANS_Z",config.trans[2]);
264         output.tag.set_property("TRANS_LAG_X",config.trans_lag[0]);
265         output.tag.set_property("TRANS_LAG_Y",config.trans_lag[1]);
266         output.tag.set_property("TRANS_LAG_Z",config.trans_lag[2]);
267         output.tag.set_property("ROT_X",config.rot[0]);
268         output.tag.set_property("ROT_Y",config.rot[1]);
269         output.tag.set_property("ROT_Z",config.rot[2]);
270         output.tag.set_property("ROT_LAG_X",config.rot_lag[0]);
271         output.tag.set_property("ROT_LAG_Y",config.rot_lag[1]);
272         output.tag.set_property("ROT_LAG_Z",config.rot_lag[2]);
273         output.tag.set_property("INERTIA", config.inertia);
274         output.tag.set_property("MODE", config.mode);
275         output.tag.set_property("NUM_BODIES", config.numBodies);
276         output.append_tag();
277         output.append_newline();
278         output.tag.set_title("/NBODYCUDA");
279         output.append_tag();
280         output.append_newline();
281         output.terminate_string();
282 }
283
284 void N_BodyMain::read_data(KeyFrame *keyframe)
285 {
286         FileXML input;
287         input.set_shared_input(keyframe->xbuf);
288
289         int result = 0;
290         while( !(result = input.read_tag()) ) {
291                 if( input.tag.title_is("NBODYCUDA") ) {
292                         config.m_timestep = input.tag.get_property("TIMESTEP", config.m_timestep);
293                         config.m_clusterScale = input.tag.get_property("CLUSTER_SCALE", config.m_clusterScale);
294                         config.m_velocityScale = input.tag.get_property("VELOCITY_SCALE", config.m_velocityScale);
295                         config.m_softening = input.tag.get_property("SOFTENING", config.m_softening);
296                         config.m_damping = input.tag.get_property("DAMPING", config.m_damping);
297                         config.m_pointSize = input.tag.get_property("POINT_SIZE", config.m_pointSize);
298                         config.m_x = input.tag.get_property("X", config.m_x);
299                         config.m_y = input.tag.get_property("Y", config.m_y);
300                         config.m_z = input.tag.get_property("Z", config.m_z);
301                         config.trans[0] = input.tag.get_property("TRANS_X", config.trans[0]);
302                         config.trans[1] = input.tag.get_property("TRANS_Y", config.trans[1]);
303                         config.trans[2] = input.tag.get_property("TRANS_Z", config.trans[2]);
304                         config.trans_lag[0] = input.tag.get_property("TRANS_LAG_X", config.trans_lag[0]);
305                         config.trans_lag[1] = input.tag.get_property("TRANS_LAG_Y", config.trans_lag[1]);
306                         config.trans_lag[2] = input.tag.get_property("TRANS_LAG_Z", config.trans_lag[2]);
307                         config.rot[0] = input.tag.get_property("ROT_X", config.rot[0]);
308                         config.rot[1] = input.tag.get_property("ROT_Y", config.rot[1]);
309                         config.rot[2] = input.tag.get_property("ROT_Z", config.rot[2]);
310                         config.rot_lag[0] = input.tag.get_property("ROT_LAG_X", config.rot_lag[0]);
311                         config.rot_lag[1] = input.tag.get_property("ROT_LAG_Y", config.rot_lag[1]);
312                         config.rot_lag[2] = input.tag.get_property("ROT_LAG_Z", config.rot_lag[2]);
313                         config.inertia = input.tag.get_property("INERTIA", config.inertia);
314                         config.mode = input.tag.get_property("MODE", config.mode);
315                         config.numBodies = input.tag.get_property("NUM_BODIES", config.numBodies);
316                 }
317         }
318         config.limits();
319 }
320
321 void N_BodyMain::update_gui()
322 {
323         if( !thread ) return;
324         if( !load_configuration() ) return;
325         thread->window->lock_window("N_BodyMain::update_gui");
326         N_BodyWindow *window = (N_BodyWindow*)thread->window;
327         window->update_gui();
328         window->flush();
329         window->unlock_window();
330 }
331
332 int N_BodyMain::process_buffer(VFrame *frame, int64_t start_position, double frame_rate)
333 {
334
335         //int need_reconfigure =
336         load_configuration();
337         new_position = start_position;
338         output = get_output(0);
339         color_model = output->get_color_model();
340         if( get_use_opengl() )
341                 return run_opengl();
342 // always use_opengl
343         Canvas *canvas = server->mwindow->cwindow->gui->canvas;
344         return server->mwindow->playback_3d->run_plugin(canvas, this);
345 }
346
347 // cuda
348
349 N_BodyCuda::N_BodyCuda()
350 {
351         version = 0;
352         numSMs = 0;
353 }
354 N_BodyCuda::~N_BodyCuda()
355 {
356 }
357
358 // opengl from here down
359
360 void N_BodyMain::init_cuda()
361 {
362         if( !cuda ) {
363                 cuda = new N_BodyCuda();
364                 cuda->init_dev();
365         }
366         cuda->init();
367 }
368 void N_BodyMain::finish_cuda()
369 {
370         cuda->finish();
371 }
372
373 int N_BodyMain::handle_opengl()
374 {
375         output->enable_opengl();
376         output->init_screen();
377         if( !m_nbody || get_source_position() == 0 ||
378             (int)m_nbody->getNumBodies() != config.numBodies )
379                 init(config.numBodies);
380         init_cuda();
381         if( curr_position != new_position ) {
382                 updateSimulation();
383                 curr_position = new_position;
384         }
385         draw();
386         finish_cuda();
387         output->set_opengl_state(VFrame::SCREEN);
388         if( !get_use_opengl() ) // rendering
389                 output->screen_to_ram();
390         return 0;
391 }
392