CHECK_WITH([shuttle],[shuttle device],[SHUTTLE],[yes])
CHECK_WITH([vaapi],[video acceleration api],[VAAPI],[yes])
CHECK_WITH([vdpau],[video decode+presentation api for unix],[VDPAU],[yes])
+CHECK_WITH([nv],[video acceleration api],[NV],[yes])
+CHECK_WITH([cuda],[video decode+presentation api for unix],[CUDA],[auto])
if test "x$WANT_LV2" != "xno"; then
GTK2_LIBS=`pkg-config --libs gtk+-2.0`
[ usr/local/lib*/libwebp*.a ],
[ usr/local/include ])
+PKG_3RD([ffnvcodec],[auto],
+ [ffnvcodec],
+ [ ],
+ [ . ])
+
AC_SUBST(STATIC_PKGS)
AC_DEFUN([CHECK_ENABLE], [
CHECK_HEADERS([vaapi_drm], [va drm headers], [va/va_drm.h])
CHECK_LIB([vaapi_drm], [va-drm], [vaGetDisplayDRM])
fi
+#CHECK_LIB([NVENC], [nvidia-encode], [NvEncodeAPICreateInstance])
#if test "x$HAVE_mjpegtools" = "xyes"; then
#CFG_CFLAGS+=" -I/usr/include/mjpegtools -I/usr/local/include/mjpegtools"
if test "x$WANT_$1" = "xyes" ; then
AC_MSG_ERROR([required for $1 support.])
fi
- echo "=== want $1 Failed."
WANT_$1=no
elif test "x$WANT_$1" = "xauto" ; then
WANT_$1=yes
CHECK_HEADERS([lv2], [suil headers], [suil/suil.h])
CFLAGS="$saved_CFLAGS"])
+CHECK_WANT([CUDA], [auto], [build cuda plugins], [
+ CHECK_HEADERS([CUDA], [cuda sdk], [/usr/local/cuda/include/cuda.h])])
+
CHECK_WANT([DL], [auto], [system has libdl], [
CHECK_LIB([DL], [dl], [dlopen])])
PKG_PROVIDE([serd], [$WANT_LV2])
PKG_PROVIDE([sord], [$WANT_LV2])
PKG_PROVIDE([suil], [$WANT_LV2])
+PKG_PROVIDE([ffnvcodec], [$WANT_NV])
if test "x$WANT_LV2" = "xyes"; then
if test "x$HAVE_lv2" = "xyes" -a "x$BUILD_lilv" = "x0"; then
echo " using: with-commerical = $WANT_COMMERCIAL"
echo " using: with-vaapi = $WANT_VAAPI"
echo " using: with-vdpau = $WANT_VDPAU"
+echo " using: with-nv = $WANT_NV"
+echo " using: with-cuda = $WANT_CUDA"
echo ""
echo " using: thirdparty build = $WANT_CIN_3RDPARTY"
echo " using: single-user = $WANT_CINBIN_BUILD"
WANT_VDPAU="yes"
CFG_WANTS+=" VDPAU"
fi
+if test "x$WANT_NV" != "xno"; then
+ WANT_NV="yes"
+ CFG_WANTS+=" NV"
+fi
if test "x$HAVE_DL" = "xyes"; then
EXTRA_LIBS+=' -ldl'
--- /dev/null
+mp4 h264_nvenc
+# encode for nvidia graphics hw only
+preset medium
+profile main
--- /dev/null
+mp4 hevc_nvenc
+# encode for nvidia graphics hw only
+preset medium
+profile main
--- /dev/null
+#cuda compile
+
+CUDA_PATH ?= /usr/local/cuda-10.1
+TARGET_SIZE := 64 # 32
+HOST_COMPILER ?= g++
+NVCC := $(CUDA_PATH)/bin/nvcc -ccbin $(HOST_COMPILER)
+NVCCFLAGS := -m${TARGET_SIZE} -Xcompiler -fPIC -Xcompiler -fno-omit-frame-pointer -g
+LDFLAGS = -lcuda -L /usr/local/cuda/targets/x86_64-linux/lib -lcudart
+
+SMS ?= 30 35 37 50 52 60 61 70 75
+$(foreach sm,$(SMS),$(eval GENCODE_FLAGS += -gencode arch=compute_$(sm),code=sm_$(sm)))
+HIGHEST_SM := $(lastword $(sort $(SMS)))
+GENCODE_FLAGS += -gencode arch=compute_$(HIGHEST_SM),code=compute_$(HIGHEST_SM)
+
+# samples source access BEWARE!
+# contains includes which conflict: search /usr/include first
+CFLAGS += -I/usr/include -I/usr/local/cuda/samples
+CFLAGS += -I/usr/local/cuda/samples/common/inc
+CFLAGS += -I/usr/local/cuda/targets/x86_64-linux/include
+CFLAGS += -Wno-unused-function
+
+INCLUDES += -I$(TOPDIR)/cinelerra -I$(TOPDIR)/guicast
+INCLUDES += -I/usr/local/cuda/samples
+INCLUDES += -I/usr/local/cuda/samples/common/inc
+INCLUDES += -I/usr/local/cuda/targets/x86_64-linux/include
+
+CUFLAGS := $(INCLUDES) $(NVCCFLAGS) $(GENCODE_FLAGS)
+$(shell mkdir -p $(OBJDIR))
+$(shell echo $(CUFLAGS) > $(OBJDIR)/cu_flags)
+
+$(OBJDIR)/%.o: %.cu
+ $(NVCC) `cat $(OBJDIR)/cu_flags` $(BFLAGS) -DMSGQUAL=$* -c $< -o $@
theme_suv \
theme_neophyte \
theme_unflat \
+ theme_cakewalk \
plugin_dirs += video
video := \
motionblur \
motion-cv \
motion-hv \
+ mandelcuda \
+ nbodycuda \
oil \
overlay \
perspective \
OPENCV_OBJS := findobj flowobj gaborobj moveobj stylizeobj puzzleobj
$(OPENCV_OBJS): opencv
endif
+ifneq ($(WANT_CUDA), no)
+CUDA_OBJS := mandelcuda nbodycuda
+endif
# burn must come before any other effecttv plugin
# colors must come before any plugin
# motion must come before perspective
DIRS = $(OPENCV_OBJS) \
+ $(CUDA_OBJS) \
1080to480 \
1080to540 \
720to480 \
--- /dev/null
+TOPDIR?=../..
+include $(TOPDIR)/plugin_defs
+include $(TOPDIR)/plugin_cuda
+
+PLUGIN = mandelcuda
+
+OBJS := \
+ $(OBJDIR)/mandelbrot.o \
+ $(OBJDIR)/mandelbrotwindow.o \
+ $(OBJDIR)/mandelcuda.o \
+
+include $(TOPDIR)/plugin_config
+
+$(OBJDIR)/mandelbrot.o: mandelbrot.C mandelbrot.h
+$(OBJDIR)/mandelbrotwindow.o: mandelbrotwindow.C mandelbrotwindow.h
+$(OBJDIR)/mandelcuda.o: mandelcuda.cu mandelcuda.h
+
--- /dev/null
+/*
+ * CINELERRA
+ * Copyright (C) 1997-2014 Adam Williams <broadcast at earthling dot net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include "clip.h"
+#include "filexml.h"
+#include "mandelbrot.h"
+#include "mandelbrotwindow.h"
+#include "language.h"
+#include "mutex.h"
+
+#include "cwindow.h"
+#include "cwindowgui.h"
+#include "mwindow.h"
+#include "pluginserver.h"
+#include "playback3d.h"
+
+REGISTER_PLUGIN(Mandelbrot)
+
+
+MandelbrotConfig::MandelbrotConfig()
+{
+}
+
+int MandelbrotConfig::equivalent(MandelbrotConfig &that)
+{
+ return is_julia == that.is_julia && scale == that.scale &&
+ x_off == that.x_off && y_off == that.y_off &&
+ x_julia == that.x_julia && y_julia == that.y_julia &&
+ color == that.color && crunch == that.crunch &&
+ step == that.step;
+}
+
+void MandelbrotConfig::copy_from(MandelbrotConfig &that)
+{
+ is_julia = that.is_julia;
+ x_off = that.x_off;
+ y_off = that.y_off;
+ scale = that.scale;
+ x_julia = that.x_julia;
+ y_julia = that.y_julia;
+ color = that.color;
+ crunch = that.crunch;
+ step = that.step;
+}
+
+void MandelbrotConfig::interpolate( MandelbrotConfig &prev, MandelbrotConfig &next,
+ long prev_frame, long next_frame, long current_frame)
+{
+ copy_from(prev);
+ double u = (double)(next_frame - current_frame) / (next_frame - prev_frame);
+ double v = 1. - u;
+ this->x_off = u*prev.x_off + v*next.x_off;
+ this->y_off = u*prev.y_off + v*next.y_off;
+ this->scale = u*prev.scale + v*next.scale;
+ this->x_julia = u*prev.x_julia + v*next.x_julia;
+ this->y_julia = u*prev.y_julia + v*next.y_julia;
+}
+
+void MandelbrotConfig::limits()
+{
+ bclamp(scale, -1.e4, 1.e4);
+ bclamp(crunch, 1, 0x10000);
+}
+
+
+Mandelbrot::Mandelbrot(PluginServer *server)
+ : PluginVClient(server)
+{
+ config.reset();
+ config.startJulia();
+ vfrm = 0;
+ img_w = img_h = 0;
+ pbo_id = -1;
+ animation_frame = 0;
+}
+
+Mandelbrot::~Mandelbrot()
+{
+ delete vfrm;
+}
+
+const char* Mandelbrot::plugin_title() { return N_("Mandelbrot"); }
+int Mandelbrot::is_realtime() { return 1; }
+int Mandelbrot::is_synthesis() { return 1; }
+
+NEW_WINDOW_MACRO(Mandelbrot, MandelbrotWindow);
+LOAD_CONFIGURATION_MACRO(Mandelbrot, MandelbrotConfig)
+
+void Mandelbrot::save_data(KeyFrame *keyframe)
+{
+ FileXML output;
+ output.set_shared_output(keyframe->xbuf);
+ output.tag.set_title("MANDELCUDA");
+ output.tag.set_property("IS_JULIA", config.is_julia);
+ output.tag.set_property("SCALE", config.scale);
+ output.tag.set_property("X_OFF", config.x_off);
+ output.tag.set_property("Y_OFF", config.y_off);
+ output.tag.set_property("X_JULIA", config.x_julia);
+ output.tag.set_property("Y_JULIA", config.y_julia);
+ output.tag.set_property("COLOR", config.color);
+ output.tag.set_property("CRUNCH", config.crunch);
+ output.tag.set_property("STEP", config.step);
+ output.append_tag();
+ output.append_newline();
+ output.tag.set_title("/MANDELCUDA");
+ output.append_tag();
+ output.append_newline();
+ output.terminate_string();
+}
+
+void Mandelbrot::read_data(KeyFrame *keyframe)
+{
+ FileXML input;
+ input.set_shared_input(keyframe->xbuf);
+
+ int result = 0;
+ while( !(result = input.read_tag()) ) {
+ if( input.tag.title_is("MANDELCUDA") ) {
+ config.is_julia = input.tag.get_property("IS_JULIA", config.is_julia);
+ config.scale = input.tag.get_property("SCALE", config.scale);
+ config.x_off = input.tag.get_property("X_OFF", config.x_off);
+ config.y_off = input.tag.get_property("Y_OFF", config.y_off);
+ config.x_julia = input.tag.get_property("X_JULIA", config.x_julia);
+ config.y_julia = input.tag.get_property("Y_JULIA", config.y_julia);
+ config.color = input.tag.get_property("COLOR", config.color);
+ config.crunch = input.tag.get_property("CRUNCH", config.crunch);
+ config.step = input.tag.get_property("STEP", config.step);
+ }
+ }
+ config.limits();
+}
+
+void Mandelbrot::update_gui()
+{
+ if( !thread ) return;
+ if( !load_configuration() ) return;
+ thread->window->lock_window("Mandelbrot::update_gui");
+ MandelbrotWindow *window = (MandelbrotWindow*)thread->window;
+ window->update_gui();
+ window->flush();
+ window->unlock_window();
+}
+
+void MandelbrotConfig::reset()
+{
+ is_julia = 0;
+ x_julia = 0.0;
+ y_julia = 0.0;
+ x_off = -0.5;
+ y_off = 0.0;
+ scale = 3.2;
+ color = 0x00030507;
+ crunch = 512;
+ step = 0;
+}
+
+void MandelbrotConfig::startJulia()
+{
+ is_julia = 1;
+ x_julia = -0.172400;
+ y_julia = -0.652693;
+ x_off = -0.085760;
+ y_off = 0.007040;
+}
+
+// Get a sub-pixel sample location
+void Mandelbrot::GetSample(int sampleIndex, float &x, float &y)
+{
+ static const unsigned char pairData[128][2] = {
+ {64, 64}, {0, 0}, {1, 63}, {63, 1}, {96, 32}, {97, 95}, {36, 96}, {30, 31},
+ {95, 127}, {4, 97}, {33, 62}, {62, 33}, {31, 126}, {67, 99}, {99, 65}, {2, 34},
+ {81, 49}, {19, 80}, {113, 17}, {112, 112}, {80, 16}, {115, 81}, {46, 15}, {82, 79},
+ {48, 78}, {16, 14}, {49, 113}, {114, 48}, {45, 45}, {18, 47}, {20, 109}, {79, 115},
+ {65, 82}, {52, 94}, {15, 124}, {94, 111}, {61, 18}, {47, 30}, {83, 100}, {98, 50},
+ {110, 2}, {117, 98}, {50, 59}, {77, 35}, {3, 114}, {5, 77}, {17, 66}, {32, 13},
+ {127, 20}, {34, 76}, {35, 110}, {100, 12}, {116, 67}, {66, 46}, {14, 28}, {23, 93},
+ {102, 83}, {86, 61}, {44, 125}, {76, 3}, {109, 36}, {6, 51}, {75, 89}, {91, 21},
+ {60, 117}, {29, 43}, {119, 29}, {74, 70}, {126, 87}, {93, 75}, {71, 24}, {106, 102},
+ {108, 58}, {89, 9}, {103, 23}, {72, 56}, {120, 8}, {88, 40}, {11, 88}, {104, 120},
+ {57, 105}, {118, 122}, {53, 6}, {125, 44}, {43, 68}, {58, 73}, {24, 22}, {22, 5},
+ {40, 86}, {122, 108}, {87, 90}, {56, 42}, {70, 121}, {8, 7}, {37, 52}, {25, 55},
+ {69, 11}, {10, 106}, {12, 38}, {26, 69}, {27, 116}, {38, 25}, {59, 54}, {107, 72},
+ {121, 57}, {39, 37}, {73, 107}, {85, 123}, {28, 103}, {123, 74}, {55, 85}, {101, 41},
+ {42, 104}, {84, 27}, {111, 91}, {9, 19}, {21, 39}, {90, 53}, {41, 60}, {54, 26},
+ {92, 119}, {51, 71}, {124, 101}, {68, 92}, {78, 10}, {13, 118}, {7, 84}, {105, 4}
+ };
+
+ x = (1.0f / 128.0f) * (0.5f + (float) pairData[sampleIndex][0]);
+ y = (1.0f / 128.0f) * (0.5f + (float) pairData[sampleIndex][1]);
+} // GetSample
+
+// render Mandelbrot image using CUDA
+void Mandelbrot::renderImage()
+{
+ float xs, ys;
+ // Get the anti-alias sub-pixel sample location
+ GetSample(pass & 127, xs, ys);
+
+ // Get the pixel scale and offset
+ double s = config.scale / (float) img_w;
+ double x = (xs - (double) img_w * 0.5f) * s + config.x_off;
+ double y = (ys - (double) img_h * 0.5f) * s + config.y_off;
+
+ uchar4 colors;
+ colors.w = (config.color>>24) & 0xff;
+ colors.x = (config.color>>16) & 0xff;
+ colors.y = (config.color>>8) & 0xff;
+ colors.z = (config.color>>0) & 0xff;
+
+ cuda.Run(vfrm->get_data(), img_w*img_h*4, config.is_julia, config.crunch,
+ x, y, config.x_julia, config.y_julia, s, colors, pass, animation_frame);
+ ++pass;
+}
+
+void Mandelbrot::displayFunc()
+{
+ if( config.step ) {
+ animation_frame += config.step;
+ pass = 0;
+ }
+ // render the Mandelbrot image
+ renderImage();
+}
+
+void Mandelbrot::init()
+{
+ animation_frame = 0;
+ pass = 0;
+}
+
+int Mandelbrot::process_buffer(VFrame *frame, int64_t start_position, double frame_rate)
+{
+
+ int need_reconfigure = load_configuration();
+ if( need_reconfigure ) pass = 0;
+ output = get_output(0);
+ color_model = output->get_color_model();
+ img_w = output->get_w();
+ img_h = output->get_h();
+ if( !start_position )
+ init();
+ if( vfrm &&
+ (vfrm->get_w() != img_w || vfrm->get_h() != img_h) ) {
+ delete vfrm; vfrm = 0;
+ }
+ if( !vfrm )
+ vfrm = new VFrame(img_w, img_h, BC_RGBA8888);
+
+ if( get_use_opengl() )
+ return run_opengl();
+// always use_opengl
+ Canvas *canvas = server->mwindow->cwindow->gui->canvas;
+ return server->mwindow->playback_3d->run_plugin(canvas, this);
+}
+
+// opengl from here down
+
+void Mandelbrot::init_cuda()
+{
+ cuda.init_dev();
+ GLuint pbo[1];
+ glGenBuffers(1, pbo);
+ glBindBuffer(GL_ARRAY_BUFFER, pbo_id=*pbo);
+ glBufferData(GL_ARRAY_BUFFER, img_w*img_h*4, 0, GL_STATIC_DRAW);
+ cuda.init(pbo_id, img_w, img_h);
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+}
+void Mandelbrot::finish_cuda()
+{
+ cuda.finish();
+ GLuint pbo[1]; *pbo = pbo_id;
+ glDeleteBuffers(1, pbo);
+ pbo_id = -1;
+}
+
+int Mandelbrot::handle_opengl()
+{
+ vfrm->enable_opengl();
+ vfrm->init_screen();
+ init_cuda();
+ displayFunc();
+ output->transfer_from(vfrm);
+ finish_cuda();
+ return 0;
+}
+
--- /dev/null
+/*
+ * CINELERRA
+ * Copyright (C) 1997-2014 Adam Williams <broadcast at earthling dot net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef MANDELCUDA_H
+#define MANDELCUDA_H
+
+#include "pluginvclient.h"
+
+typedef struct {
+ unsigned char x, y, z, w;
+} uchar4;
+
+#include "mandelcuda.h"
+
+class MandelbrotConfig;
+class Mandelbrot;
+
+class MandelbrotConfig
+{
+public:
+ MandelbrotConfig();
+
+ int equivalent(MandelbrotConfig &that);
+ void copy_from(MandelbrotConfig &that);
+ void interpolate(MandelbrotConfig &prev, MandelbrotConfig &next,
+ long prev_frame, long next_frame, long current_frame);
+
+ int is_julia;
+ float x_off, y_off, scale;
+ float x_julia, y_julia;
+ int color, crunch, step;
+
+ void limits();
+ void reset();
+ void startJulia();
+};
+
+class Mandelbrot : public PluginVClient
+{
+public:
+ Mandelbrot(PluginServer *server);
+ ~Mandelbrot();
+ PLUGIN_CLASS_MEMBERS2(MandelbrotConfig)
+ int is_realtime();
+ int is_synthesis();
+ void update_gui();
+ void save_data(KeyFrame *keyframe);
+ void read_data(KeyFrame *keyframe);
+ int process_buffer(VFrame *frame, int64_t start_position, double frame_rate);
+ int handle_opengl();
+
+ void GetSample(int sampleIndex, float &x, float &y);
+ void renderImage();
+ void displayFunc();
+ void initData();
+ void init();
+
+ VFrame *output, *vfrm;
+ int color_model, pass;
+ int img_w, img_h;
+ int pbo_id;
+ int animation_frame;
+ MandelCuda cuda;
+
+ void init_cuda();
+ void finish_cuda();
+};
+
+#endif
--- /dev/null
+/*
+ * CINELERRA
+ * Copyright (C) 2014 Adam Williams <broadcast at earthling dot net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include "bcdisplayinfo.h"
+#include "clip.h"
+#include "cwindow.h"
+#include "cwindowgui.h"
+#include "edl.h"
+#include "edlsession.h"
+#include "language.h"
+#include "mandelbrot.h"
+#include "mandelbrotwindow.h"
+#include "mwindow.h"
+#include "mwindowgui.h"
+#include "pluginserver.h"
+#include "theme.h"
+
+MandelbrotWindow::MandelbrotWindow(Mandelbrot *plugin)
+ : PluginClientWindow(plugin, 180, 130, 180, 130, 0)
+{
+ this->plugin = plugin;
+ press_x = press_y = 0;
+ button_no = 0;
+ pending_config = 0;
+}
+
+MandelbrotWindow::~MandelbrotWindow()
+{
+}
+
+void MandelbrotWindow::create_objects()
+{
+ int x = 10, y = 10, pad = 5;
+ BC_Title *title;
+ add_subwindow(title = new BC_Title(x,y, _("Mandelbrot:"), MEDIUMFONT, YELLOW));
+ y += title->get_h() + pad;
+ add_subwindow(is_julia = new MandelbrotIsJulia(this, x, y));
+ y += is_julia->get_h() + pad;
+ add_subwindow(drag = new MandelbrotDrag(this, x, y));
+ y += drag->get_h() + pad;
+ add_subwindow(reset = new MandelbrotReset(this, x, y));
+ show_window();
+}
+
+void MandelbrotWindow::update_gui()
+{
+}
+
+
+void MandelbrotWindow::send_configure_change()
+{
+ pending_config = 0;
+ plugin->send_configure_change();
+}
+
+int MandelbrotWindow::grab_event(XEvent *event)
+{
+ int ret = do_grab_event(event);
+ if( pending_config && !grab_event_count() )
+ send_configure_change();
+ return ret;
+}
+
+int MandelbrotWindow::do_grab_event(XEvent *event)
+{
+ switch( event->type ) {
+ case ButtonPress: break;
+ case ButtonRelease: break;
+ case MotionNotify: break;
+ default:
+ return 0;
+ }
+
+ MWindow *mwindow = plugin->server->mwindow;
+ CWindowGUI *cwindow_gui = mwindow->cwindow->gui;
+ CWindowCanvas *canvas = cwindow_gui->canvas;
+ int cursor_x, cursor_y;
+ cwindow_gui->get_relative_cursor(cursor_x, cursor_y);
+ cursor_x -= canvas->view_x;
+ cursor_y -= canvas->view_y;
+ float output_x = cursor_x, output_y = cursor_y;
+ canvas->canvas_to_output(mwindow->edl, 0, output_x, output_y);
+
+ if( !button_no ) {
+ if( cursor_x < 0 || cursor_x >= canvas->view_w ||
+ cursor_y < 0 || cursor_y >= canvas->view_h )
+ return 0;
+ }
+
+ switch( event->type ) {
+ case ButtonPress:
+ if( button_no ) return 0;
+ press_x = output_x; press_y = output_y;
+ button_no = event->xbutton.button;
+ break;
+ case ButtonRelease:
+ if( !button_no ) return 0;
+ button_no = 0;
+ return 1;
+ case MotionNotify: {
+ if( !button_no ) return 0;
+ EDL *edl = plugin->get_edl();
+ double dx = 0, dy = 0, jx = 0, jy = 0, ds = 1;
+ double out_w = edl->session->output_w, out_h = edl->session->output_h;
+ double fx = (double)(press_x - output_x) / (2. * out_w);
+ double fy = (double)(press_y - output_y) / (2. * out_h);
+ press_x = output_x; press_y = output_y;
+ switch( button_no ) {
+ case LEFT_BUTTON: {
+ dx = fx * plugin->config.scale;
+ dy = fy * plugin->config.scale;
+ break; }
+ case MIDDLE_BUTTON: {
+ ds = fy >= 0.f ? 1-fy : 1/(1+fy);
+ bclamp(ds, 1-0.05f, 1+0.05f);
+ break; }
+ case RIGHT_BUTTON: {
+ jx = fx;
+ jy = fy;
+ break; }
+ }
+ plugin->config.x_off += dx;
+ plugin->config.y_off += dy;
+ plugin->config.x_julia += jx;
+ plugin->config.y_julia += jy;
+ plugin->config.scale *= ds;
+ pending_config = 1;
+ break; }
+ default:
+ return 0;
+ }
+
+ return 1;
+}
+
+void MandelbrotWindow::done_event(int result)
+{
+ ungrab(client->server->mwindow->cwindow->gui);
+}
+MandelbrotDrag::MandelbrotDrag(MandelbrotWindow *gui, int x, int y)
+ : BC_CheckBox(x, y, 0, _("Drag"))
+{
+ this->gui = gui;
+}
+int MandelbrotDrag::handle_event()
+{
+ CWindowGUI *cwindow_gui = gui->plugin->server->mwindow->cwindow->gui;
+ int value = get_value();
+ if( value ) {
+ if( !gui->grab(cwindow_gui) ) {
+ update(value = 0);
+ flicker(10,50);
+ }
+ }
+ else
+ gui->ungrab(cwindow_gui);
+ return 1;
+}
+
+MandelbrotIsJulia::MandelbrotIsJulia(MandelbrotWindow *gui, int x, int y)
+ : BC_CheckBox(x, y, gui->plugin->config.is_julia, _("Julia"))
+{
+ this->gui = gui;
+}
+MandelbrotIsJulia::~MandelbrotIsJulia()
+{
+}
+
+int MandelbrotIsJulia::handle_event()
+{
+ Mandelbrot *plugin = gui->plugin;
+ plugin->config.is_julia = get_value();
+ gui->send_configure_change();
+ return 1;
+}
+
+MandelbrotReset::MandelbrotReset(MandelbrotWindow *gui, int x, int y)
+ : BC_GenericButton(x, y, _("Reset"))
+{
+ this->gui = gui;
+}
+MandelbrotReset::~MandelbrotReset()
+{
+}
+
+int MandelbrotReset::handle_event()
+{
+ Mandelbrot *plugin = gui->plugin;
+ int is_julia = plugin->config.is_julia;
+ plugin->config.reset();
+ if( is_julia )
+ plugin->config.startJulia();
+ gui->send_configure_change();
+ return 1;
+}
+
+
+
--- /dev/null
+/*
+ * CINELERRA
+ * Copyright (C) 2008-2014 Adam Williams <broadcast at earthling dot net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#ifndef MANDELCUDAWINDOW_H
+#define MANDELCUDAWINDOW_H
+
+
+#include "guicast.h"
+#include "mandelbrot.h"
+
+class Mandelbrot;
+class MandelbrotIsJulia;
+class MandelbrotDrag;
+class MandelbrotWindow;
+
+class MandelbrotIsJulia : public BC_CheckBox
+{
+public:
+ MandelbrotIsJulia(MandelbrotWindow *gui, int x, int y);
+ ~MandelbrotIsJulia();
+ int handle_event();
+
+ MandelbrotWindow *gui;
+};
+
+class MandelbrotReset : public BC_GenericButton
+{
+public:
+ MandelbrotReset(MandelbrotWindow *gui, int x, int y);
+ ~MandelbrotReset();
+ int handle_event();
+
+ MandelbrotWindow *gui;
+};
+
+class MandelbrotDrag : public BC_CheckBox
+{
+public:
+ MandelbrotDrag(MandelbrotWindow *gui, int x, int y);
+
+ int handle_event();
+ MandelbrotWindow *gui;
+};
+
+class MandelbrotWindow : public PluginClientWindow
+{
+public:
+ MandelbrotWindow(Mandelbrot *plugin);
+ ~MandelbrotWindow();
+ void create_objects();
+ void update_gui();
+
+ int grab_event(XEvent *event);
+ int do_grab_event(XEvent *event);
+ void done_event(int result);
+ void send_configure_change();
+
+ Mandelbrot *plugin;
+ MandelbrotIsJulia *is_julia;
+ MandelbrotDrag *drag;
+ MandelbrotReset *reset;
+ int press_x, press_y;
+ int button_no, pending_config;
+};
+
+#endif
--- /dev/null
+#include "mandelcuda.h"
+#include <cuda_runtime.h>
+#include <cuda_gl_interop.h>
+#include "helper_cuda.h"
+#include "helper_gl.h"
+
+// The dimensions of the thread block
+#define BLOCKDIM_X 16
+#define BLOCKDIM_Y 16
+#define ABS(n) ((n) < 0 ? -(n) : (n))
+
+void MandelCuda::init_dev()
+{
+ if( numSMs ) return;
+// int dev_id = findCudaDevice(argc, (const char **)argv);
+ int dev_id = gpuGetMaxGflopsDeviceId();
+ checkCudaErrors(cudaSetDevice(dev_id));
+ cudaDeviceProp deviceProp;
+ checkCudaErrors(cudaGetDeviceProperties(&deviceProp, dev_id));
+printf("GPU Device %d: \"%s\" with compute capability %d.%d\n",
+ dev_id, deviceProp.name, deviceProp.major, deviceProp.minor);
+ version = deviceProp.major * 10 + deviceProp.minor;
+ numSMs = deviceProp.multiProcessorCount;
+ if( !numSMs ) numSMs = -1;
+}
+
+void MandelCuda::init(int pbo, int pw, int ph)
+{
+ if( pbo_id >= 0 ) return;
+ pbo_id = pbo; pbo_w = pw; pbo_h = ph;
+ checkCudaErrors(cudaGraphicsGLRegisterBuffer(&cuda_pbo, pbo_id, cudaGraphicsMapFlagsNone));
+ checkCudaErrors(cudaGraphicsMapResources(1, &cuda_pbo, 0));
+ size_t pbo_bytes = 0;
+ checkCudaErrors(cudaGraphicsResourceGetMappedPointer(&pbo_mem, &pbo_bytes, cuda_pbo));
+}
+
+void MandelCuda::finish()
+{
+ pbo_id = -1;
+ pbo_w = pbo_h = 0;
+ checkCudaErrors(cudaGraphicsUnmapResources(1, &cuda_pbo));
+ pbo_mem = 0;
+ cudaGraphicsUnregisterResource(cuda_pbo); cuda_pbo = 0;
+}
+
+
+MandelCuda::MandelCuda()
+{
+ version = 0;
+ numSMs = 0;
+ pbo_id = -1;
+ pbo_w = pbo_h = 0;
+ cuda_pbo = 0;
+ pbo_mem = 0;
+}
+MandelCuda::~MandelCuda()
+{
+}
+
+static inline int iDivUp(int a, int b)
+{
+ int v = a / b;
+ return a % b ? v+1 : v;
+}
+
+// Determine if two pixel colors are within tolerance
+__device__ inline int CheckColors(const uchar4 &color0, const uchar4 &color1)
+{
+ int x = color1.x - color0.x;
+ if( ABS(x) > 10 ) return 1;
+ int y = color1.y - color0.y;
+ if( ABS(y) > 10 ) return 1;
+ int z = color1.z - color0.z;
+ if( ABS(z) > 10 ) return 1;
+ return 0;
+}
+
+
+// The core MandelCuda calculation function template
+template<class T> __device__
+inline int CalcCore(const int n, T ix, T iy, T xC, T yC)
+{
+ T x = ix, y = iy;
+ T xx = x * x, yy = y * y;
+ int i = n;
+ while( --i && (xx + yy < 4.0f) ) {
+ y = x * y + x * y + yC ; // 2*x*y + yC
+ x = xx - yy + xC ;
+ yy = y * y;
+ xx = x * x;
+ }
+
+ return i;
+}
+
+template<class T> __global__
+void Calc(uchar4 *dst, const int img_w, const int img_h, const int is_julia,
+ const int crunch, const int gridWidth, const int numBlocks,
+ const T x_off, const T y_off, const T x_julia, const T y_julia, const T scale,
+ const uchar4 colors, const int frame, const int animationFrame)
+{
+ // loop until all blocks completed
+ for( unsigned int bidx=blockIdx.x; bidx<numBlocks; bidx+=gridDim.x ) {
+ unsigned int blockX = bidx % gridWidth;
+ unsigned int blockY = bidx / gridWidth;
+ const int x = blockDim.x * blockX + threadIdx.x;
+ const int y = blockDim.y * blockY + threadIdx.y;
+ if( x >= img_w || y >= img_h ) continue;
+ int pi = img_w*y + x, n = !frame ? 1 : 0;
+ uchar4 pixel = dst[pi];
+ if( !n && x > 0 )
+ n += CheckColors(pixel, dst[pi-1]);
+ if( !n && x+1 < img_w )
+ n += CheckColors(pixel, dst[pi+1]);
+ if( !n && y > 0 )
+ n += CheckColors(pixel, dst[pi-img_w]);
+ if( !n && y+1 < img_h )
+ n += CheckColors(pixel, dst[pi+img_w]);
+ if( !n ) continue;
+
+ const T tx = T(x) * scale + x_off;
+ const T ty = T(y) * scale + y_off;
+ const T ix = is_julia ? tx : 0;
+ const T iy = is_julia ? ty : 0;
+ const T xC = is_julia ? x_julia : tx;
+ const T yC = is_julia ? y_julia : ty;
+ int m = CalcCore(crunch, ix,iy, xC,yC);
+ m = m > 0 ? crunch - m : 0;
+ if( m ) m += animationFrame;
+
+ uchar4 color;
+ color.x = m * colors.x;
+ color.y = m * colors.y;
+ color.z = m * colors.z;
+ color.w = 0;
+
+ int frame1 = frame+1, frame2 = frame1/2;
+ color.x = (pixel.x * frame + color.x + frame2) / frame1;
+ color.y = (pixel.y * frame + color.y + frame2) / frame1;
+ color.z = (pixel.z * frame + color.z + frame2) / frame1;
+ dst[pi] = color; // Output the pixel
+ }
+}
+
+
+void MandelCuda::Run(unsigned char *data, unsigned int size, int is_julia, int crunch,
+ double x_off, double y_off, double x_julia, double y_julia, double scale,
+ uchar4 colors, int pass, int animationFrame)
+{
+ if( numSMs < 0 ) return;
+ checkCudaErrors(cudaMemcpy(pbo_mem, data, size, cudaMemcpyHostToDevice));
+ dim3 threads(BLOCKDIM_X, BLOCKDIM_Y);
+ dim3 grid(iDivUp(pbo_w, BLOCKDIM_X), iDivUp(pbo_h, BLOCKDIM_Y));
+ Calc<float><<<numSMs, threads>>>((uchar4 *)pbo_mem, pbo_w, pbo_h,
+ is_julia, crunch, grid.x, grid.x*grid.y,
+ float(x_off), float(y_off), float(x_julia), float(y_julia), float(scale),
+ colors, pass, animationFrame);
+ checkCudaErrors(cudaMemcpy(data, pbo_mem, size, cudaMemcpyDeviceToHost));
+}
+
--- /dev/null
+#ifndef __MANDELCUDA_CUH__
+#define __MANDELCUDA_CUH__
+
+class MandelCuda
+{
+public:
+ MandelCuda();
+ ~MandelCuda();
+
+ void init_dev();
+ void Run(unsigned char *data, unsigned int size, int is_julia, int crunch,
+ double x, double y, double jx, double jy, double scale,
+ uchar4 color, int pass, int animationFrame);
+ void init(int pbo, int pw, int ph);
+ void finish();
+
+ int version, numSMs;
+ int pbo_id, pbo_w, pbo_h;
+ struct cudaGraphicsResource *cuda_pbo;
+ void *pbo_mem;
+};
+
+#endif
--- /dev/null
+TOPDIR?=../..
+include $(TOPDIR)/plugin_defs
+include $(TOPDIR)/plugin_cuda
+
+PLUGIN = nbodycuda
+
+OBJS := \
+ $(OBJDIR)/nbody.o \
+ $(OBJDIR)/nbodywindow.o \
+ $(OBJDIR)/nbodycuda.o \
+ $(OBJDIR)/bodysys.o \
+ $(OBJDIR)/renders.o \
+
+include $(TOPDIR)/plugin_config
+
+$(OBJDIR)/nbody.o: nbody.C nbody.h
+$(OBJDIR)/nbodywindow.o: nbodywindow.C nbodywindow.h
+$(OBJDIR)/nbodycuda.o: nbodycuda.cu nbodycuda.h
+$(OBJDIR)/bodysys.o: bodysys.cu
+$(OBJDIR)/renders.o: renders.C
--- /dev/null
+#include "5_Simulations/nbody/bodysystemcuda.cu"
--- /dev/null
+/*
+ * CINELERRA
+ * Copyright (C) 1997-2014 Adam Williams <broadcast at earthling dot net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#define GL_GLEXT_PROTOTYPES
+#include <GL/gl.h>
+#include <GL/glu.h>
+#include <GL/glext.h>
+
+#include "clip.h"
+#include "filexml.h"
+#include "language.h"
+#include "mutex.h"
+
+#include "cwindow.h"
+#include "cwindowgui.h"
+#include "mwindow.h"
+#include "pluginserver.h"
+#include "playback3d.h"
+
+#include "nbody.h"
+#include "nbodycuda.h"
+#include "nbodywindow.h"
+
+
+static struct N_BodyParams demoParams[] = {
+ { 0.016f, 1.54f, 8.0f, 0.1f, 1.0f, 1.0f, 0, -2, -100},
+ { 0.016f, 0.68f, 20.0f, 0.1f, 1.0f, 0.8f, 0, -2, -30},
+ { 0.0006f, 0.16f, 1000.0f, 1.0f, 1.0f, 0.07f, 0, 0, -1.5f},
+ { 0.0006f, 0.16f, 1000.0f, 1.0f, 1.0f, 0.07f, 0, 0, -1.5f},
+ { 0.0019f, 0.32f, 276.0f, 1.0f, 1.0f, 0.07f, 0, 0, -5},
+ { 0.0016f, 0.32f, 272.0f, 0.145f, 1.0f, 0.08f, 0, 0, -5},
+ { 0.0160f, 6.04f, 0.0f, 1.0f, 1.0f, 0.76f, 0, 0, -50},
+};
+const int N_BodyParams::num_demos = sizeof(demoParams)/sizeof(*demoParams);
+
+
+REGISTER_PLUGIN(N_BodyMain)
+
+void N_BodyConfig::reset(int i)
+{
+ *(N_BodyParams*)this = demoParams[i];
+ trans[0] = trans_lag[0] = m_x;
+ trans[1] = trans_lag[1] = m_y;
+ trans[2] = trans_lag[2] = m_z;
+ rot[0] = rot_lag[0] = 0;
+ rot[1] = rot_lag[1] = 0;
+ rot[2] = rot_lag[2] = 0;
+ mode = ParticleRenderer::PARTICLE_SPRITES_COLOR;
+ numBodies = 4096;
+ inertia = 0.1;
+}
+
+N_BodyConfig::N_BodyConfig()
+{
+ reset();
+}
+
+int N_BodyConfig::equivalent(N_BodyConfig &that)
+{
+ return m_timestep == that.m_timestep &&
+ m_clusterScale == that.m_clusterScale &&
+ m_velocityScale == that.m_velocityScale &&
+ m_softening == that. m_softening &&
+ m_damping == that.m_damping &&
+ m_pointSize == that.m_pointSize &&
+ m_x == that.m_x &&
+ m_y == that.m_y &&
+ m_z == that.m_z &&
+ trans[0] == that.trans[0] &&
+ trans[1] == that.trans[1] &&
+ trans[2] == that.trans[2] &&
+ trans_lag[0] == that.trans_lag[0] &&
+ trans_lag[1] == that.trans_lag[1] &&
+ trans_lag[2] == that.trans_lag[2] &&
+ rot[0] == that.rot[0] &&
+ rot[1] == that.rot[1] &&
+ rot[2] == that.rot[2] &&
+ rot_lag[0] == that.rot_lag[0] &&
+ rot_lag[1] == that.rot_lag[1] &&
+ rot_lag[2] == that.rot_lag[2] &&
+ inertia == that.inertia &&
+ numBodies == that.numBodies;
+ return 1;
+}
+
+void N_BodyConfig::copy_from(N_BodyConfig &that)
+{
+ m_timestep = that.m_timestep;
+ m_clusterScale = that.m_clusterScale;
+ m_velocityScale = that.m_velocityScale;
+ m_softening = that. m_softening;
+ m_damping = that.m_damping;
+ m_pointSize = that.m_pointSize;
+ m_x = that.m_x;
+ m_y = that.m_y;
+ m_z = that.m_z;
+ trans[0] = that.trans[0];
+ trans[1] = that.trans[1];
+ trans[2] = that.trans[2];
+ trans_lag[0] = that.trans_lag[0];
+ trans_lag[1] = that.trans_lag[1];
+ trans_lag[2] = that.trans_lag[2];
+ rot[0] = that.rot[0];
+ rot[1] = that.rot[1];
+ rot[2] = that.rot[2];
+ rot_lag[0] = that.rot_lag[0];
+ rot_lag[1] = that.rot_lag[1];
+ rot_lag[2] = that.rot_lag[2];
+ inertia = that.inertia;
+ numBodies = that.numBodies;
+}
+
+void N_BodyConfig::interpolate( N_BodyConfig &prev, N_BodyConfig &next,
+ long prev_frame, long next_frame, long current_frame)
+{
+ copy_from(next);
+}
+
+void N_BodyConfig::limits()
+{
+ if( m_damping < 0.001 ) m_damping = 0.001;
+ if( trans[2] < 0.005 ) trans[2] = 0.005;
+ int n = 1;
+ while( n < numBodies ) n <<= 1;
+ bclamp(n, 0x0010, 0x4000);
+ numBodies = n;
+ bclamp(inertia, 0.f,1.f);
+ bclamp(mode, 0, (int)ParticleRenderer::PARTICLE_NUM_MODES-1);
+}
+
+
+N_BodyMain::N_BodyMain(PluginServer *server)
+ : PluginVClient(server)
+{
+ cuda = 0;
+ blockSize = 256;
+
+ m_nbody = 0;
+ m_renderer = 0;
+ m_hPos = 0;
+ m_hVel = 0;
+ m_hColor = 0;
+
+ curr_position = -1;
+ new_position = -1;
+}
+
+N_BodyMain::~N_BodyMain()
+{
+ delete cuda;
+}
+
+void N_BodyMain::init(int numBodies)
+{
+ selectDemo(0);
+ delete m_nbody; m_nbody = new N_BodySystem(numBodies, 1, blockSize);
+ int sz = numBodies*4;
+ delete [] m_hPos; m_hPos = new float[sz];
+ delete [] m_hVel; m_hVel = new float[sz];
+ delete [] m_hColor; m_hColor = new float[sz];
+ delete m_renderer; m_renderer = new ParticleRenderer;
+// config here
+ m_nbody->setSoftening(config.m_softening);
+ m_nbody->setDamping(config.m_damping);
+ reset(numBodies, NBODY_CONFIG_RANDOM);
+ resetRenderer();
+}
+
+void N_BodyMain::reset(int numBodies, NBodyConfig cfg)
+{
+ randomizeBodies(cfg, m_hPos, m_hVel, m_hColor,
+ config.m_clusterScale, config.m_velocityScale,
+ numBodies, true);
+ setArrays(m_hPos, m_hVel);
+}
+
+void N_BodyMain::resetRenderer()
+{
+ float color[4] = { 1.0f, 0.6f, 0.3f, 1.0f};
+ m_renderer->setBaseColor(color);
+ m_renderer->setColors(m_hColor, m_nbody->getNumBodies());
+ m_renderer->setSpriteSize(config.m_pointSize);
+}
+
+void N_BodyMain::selectDemo(int index)
+{
+ config.reset(index);
+}
+
+void N_BodyMain::finalize()
+{
+ delete [] m_hPos; m_hPos = 0;
+ delete [] m_hVel; m_hVel = 0;
+ delete [] m_hColor; m_hColor = 0;
+ delete m_nbody; m_nbody = 0;
+ delete m_renderer; m_renderer = 0;
+}
+
+void N_BodyMain::draw()
+{
+ cuda->draw_event();
+ glClearColor(0.,0.,0.,1.);
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+ glColor4f(1.,1.,1.,1.);
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+ float inertia = config.inertia;
+ for( int c=0; c<3; ++c ) {
+ config.trans_lag[c] += (config.trans[c] - config.trans_lag[c]) * inertia;
+ config.rot_lag[c] += (config.rot[c] - config.rot_lag[c]) * inertia;
+ }
+
+ glTranslatef(config.trans_lag[0], config.trans_lag[1], config.trans_lag[2]);
+ glRotatef(config.rot_lag[0], 1.0, 0.0, 0.0);
+ glRotatef(config.rot_lag[1], 0.0, 1.0, 0.0);
+ glDisable(GL_TEXTURE_2D);
+ display();
+}
+
+
+const char* N_BodyMain::plugin_title() { return N_("N_Body"); }
+int N_BodyMain::is_realtime() { return 1; }
+int N_BodyMain::is_synthesis() { return 1; }
+
+NEW_WINDOW_MACRO(N_BodyMain, N_BodyWindow);
+LOAD_CONFIGURATION_MACRO(N_BodyMain, N_BodyConfig)
+
+void N_BodyMain::save_data(KeyFrame *keyframe)
+{
+ FileXML output;
+
+// cause data to be stored directly in text
+ output.set_shared_output(keyframe->xbuf);
+ output.tag.set_title("NBODYCUDA");
+ output.tag.set_property("TIMESTEP", config.m_timestep);
+ output.tag.set_property("CLUSTER_SCALE", config.m_clusterScale);
+ output.tag.set_property("VELOCITY_SCALE", config.m_velocityScale);
+ output.tag.set_property("SOFTENING", config.m_softening);
+ output.tag.set_property("DAMPING", config.m_damping);
+ output.tag.set_property("POINT_SIZE", config.m_pointSize);
+ output.tag.set_property("X", config.m_x);
+ output.tag.set_property("Y", config.m_y);
+ output.tag.set_property("Z", config.m_z);
+ output.tag.set_property("TRANS_X",config.trans[0]);
+ output.tag.set_property("TRANS_Y",config.trans[1]);
+ output.tag.set_property("TRANS_Z",config.trans[2]);
+ output.tag.set_property("TRANS_LAG_X",config.trans_lag[0]);
+ output.tag.set_property("TRANS_LAG_Y",config.trans_lag[1]);
+ output.tag.set_property("TRANS_LAG_Z",config.trans_lag[2]);
+ output.tag.set_property("ROT_X",config.rot[0]);
+ output.tag.set_property("ROT_Y",config.rot[1]);
+ output.tag.set_property("ROT_Z",config.rot[2]);
+ output.tag.set_property("ROT_LAG_X",config.rot_lag[0]);
+ output.tag.set_property("ROT_LAG_Y",config.rot_lag[1]);
+ output.tag.set_property("ROT_LAG_Z",config.rot_lag[2]);
+ output.tag.set_property("INERTIA", config.inertia);
+ output.tag.set_property("MODE", config.mode);
+ output.tag.set_property("NUM_BODIES", config.numBodies);
+ output.append_tag();
+ output.append_newline();
+ output.tag.set_title("/NBODYCUDA");
+ output.append_tag();
+ output.append_newline();
+ output.terminate_string();
+}
+
+void N_BodyMain::read_data(KeyFrame *keyframe)
+{
+ FileXML input;
+ input.set_shared_input(keyframe->xbuf);
+
+ int result = 0;
+ while( !(result = input.read_tag()) ) {
+ if( input.tag.title_is("NBODYCUDA") ) {
+ config.m_timestep = input.tag.get_property("TIMESTEP", config.m_timestep);
+ config.m_clusterScale = input.tag.get_property("CLUSTER_SCALE", config.m_clusterScale);
+ config.m_velocityScale = input.tag.get_property("VELOCITY_SCALE", config.m_velocityScale);
+ config.m_softening = input.tag.get_property("SOFTENING", config.m_softening);
+ config.m_damping = input.tag.get_property("DAMPING", config.m_damping);
+ config.m_pointSize = input.tag.get_property("POINT_SIZE", config.m_pointSize);
+ config.m_x = input.tag.get_property("X", config.m_x);
+ config.m_y = input.tag.get_property("Y", config.m_y);
+ config.m_z = input.tag.get_property("Z", config.m_z);
+ config.trans[0] = input.tag.get_property("TRANS_X", config.trans[0]);
+ config.trans[1] = input.tag.get_property("TRANS_Y", config.trans[1]);
+ config.trans[2] = input.tag.get_property("TRANS_Z", config.trans[2]);
+ config.trans_lag[0] = input.tag.get_property("TRANS_LAG_X", config.trans_lag[0]);
+ config.trans_lag[1] = input.tag.get_property("TRANS_LAG_Y", config.trans_lag[1]);
+ config.trans_lag[2] = input.tag.get_property("TRANS_LAG_Z", config.trans_lag[2]);
+ config.rot[0] = input.tag.get_property("ROT_X", config.rot[0]);
+ config.rot[1] = input.tag.get_property("ROT_Y", config.rot[1]);
+ config.rot[2] = input.tag.get_property("ROT_Z", config.rot[2]);
+ config.rot_lag[0] = input.tag.get_property("ROT_LAG_X", config.rot_lag[0]);
+ config.rot_lag[1] = input.tag.get_property("ROT_LAG_Y", config.rot_lag[1]);
+ config.rot_lag[2] = input.tag.get_property("ROT_LAG_Z", config.rot_lag[2]);
+ config.inertia = input.tag.get_property("INERTIA", config.inertia);
+ config.mode = input.tag.get_property("MODE", config.mode);
+ config.numBodies = input.tag.get_property("NUM_BODIES", config.numBodies);
+ }
+ }
+ config.limits();
+}
+
+void N_BodyMain::update_gui()
+{
+ if( !thread ) return;
+ if( !load_configuration() ) return;
+ thread->window->lock_window("N_BodyMain::update_gui");
+ N_BodyWindow *window = (N_BodyWindow*)thread->window;
+ window->update_gui();
+ window->flush();
+ window->unlock_window();
+}
+
+int N_BodyMain::process_buffer(VFrame *frame, int64_t start_position, double frame_rate)
+{
+
+ //int need_reconfigure =
+ load_configuration();
+ new_position = start_position;
+ output = get_output(0);
+ color_model = output->get_color_model();
+ if( get_use_opengl() )
+ return run_opengl();
+// always use_opengl
+ Canvas *canvas = server->mwindow->cwindow->gui->canvas;
+ return server->mwindow->playback_3d->run_plugin(canvas, this);
+}
+
+// cuda
+
+N_BodyCuda::N_BodyCuda()
+{
+ version = 0;
+ numSMs = 0;
+}
+N_BodyCuda::~N_BodyCuda()
+{
+}
+
+// opengl from here down
+
+void N_BodyMain::init_cuda()
+{
+ if( !cuda ) {
+ cuda = new N_BodyCuda();
+ cuda->init_dev();
+ }
+ cuda->init();
+}
+void N_BodyMain::finish_cuda()
+{
+ cuda->finish();
+}
+
+int N_BodyMain::handle_opengl()
+{
+ output->enable_opengl();
+ output->init_screen();
+ if( !m_nbody || get_source_position() == 0 ||
+ (int)m_nbody->getNumBodies() != config.numBodies )
+ init(config.numBodies);
+ init_cuda();
+ if( curr_position != new_position ) {
+ updateSimulation();
+ curr_position = new_position;
+ }
+ draw();
+ finish_cuda();
+ output->set_opengl_state(VFrame::SCREEN);
+ if( !get_use_opengl() ) // rendering
+ output->screen_to_ram();
+ return 0;
+}
+
--- /dev/null
+/*
+ * CINELERRA
+ * Copyright (C) 1997-2014 Adam Williams <broadcast at earthling dot net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef NBODYCUDA_H
+#define NBODYCUDA_H
+
+#include "pluginvclient.h"
+
+#include <cuda_runtime.h>
+#include <cuda_gl_interop.h>
+#include <helper_cuda.h>
+#include <helper_functions.h>
+
+#include <5_Simulations/nbody/bodysystemcuda.h>
+#include <5_Simulations/nbody/render_particles.h>
+#include "nbodycuda.h"
+
+class N_BodyConfig;
+class N_BodyMain;
+class N_BodyCuda;
+
+
+class N_BodyParams
+{
+public:
+ float m_timestep, m_clusterScale, m_velocityScale;
+ float m_softening, m_damping, m_pointSize;
+ float m_x, m_y, m_z;
+ static const int num_demos;
+};
+class N_BodyCamera
+{
+public:
+ float trans[3];
+ float rot[3];
+ float trans_lag[3];
+ float rot_lag[3];
+};
+
+class N_BodyConfig : public N_BodyParams, public N_BodyCamera
+{
+public:
+ N_BodyConfig();
+ void reset(int i=0);
+ int mode;
+ float inertia;
+ int numBodies;
+
+ int equivalent(N_BodyConfig &that);
+ void copy_from(N_BodyConfig &that);
+ void interpolate(N_BodyConfig &prev, N_BodyConfig &next,
+ long prev_frame, long next_frame, long current_frame);
+ void limits();
+};
+
+class N_BodyMain : public PluginVClient
+{
+public:
+ N_BodyMain(PluginServer *server);
+ ~N_BodyMain();
+ PLUGIN_CLASS_MEMBERS2(N_BodyConfig)
+ int is_realtime();
+ int is_synthesis();
+ void update_gui();
+ void save_data(KeyFrame *keyframe);
+ void read_data(KeyFrame *keyframe);
+ int process_buffer(VFrame *frame, int64_t start_position, double frame_rate);
+ void initData();
+ void reset();
+ int handle_opengl();
+
+ int color_model, pass;
+ VFrame *output;
+ N_BodyCuda *cuda;
+
+ void init_cuda();
+ void finish_cuda();
+
+ BodySystem<float> *m_nbody;
+ ParticleRenderer *m_renderer;
+
+ float *m_hPos, *m_hVel;
+ float *m_hColor;
+
+ char deviceName[100];
+ enum { M_VIEW = 0, M_MOVE };
+ int blockSize;
+
+ int activeDemo;
+ int64_t curr_position, new_position;
+
+ void init(int numBodies);
+ void reset(int numBodies, NBodyConfig cfg);
+ void resetRenderer();
+ void selectDemo(int index);
+ void updateParams() {
+ m_nbody->setSoftening(config.m_softening);
+ m_nbody->setDamping(config.m_damping);
+ }
+
+ void updateSimulation() {
+ m_nbody->update(config.m_timestep);
+ }
+
+ void display() { // display particles
+ m_renderer->setSpriteSize(config.m_pointSize);
+ m_renderer->setPBO(m_nbody->getCurrentReadBuffer(),
+ m_nbody->getNumBodies(), (sizeof(float) > 4));
+ m_renderer->display((ParticleRenderer::DisplayMode)config.mode);
+ }
+ void draw();
+
+ void getArrays(float *pos, float *vel) {
+ float *_pos = m_nbody->getArray(BODYSYSTEM_POSITION);
+ float *_vel = m_nbody->getArray(BODYSYSTEM_VELOCITY);
+ memcpy(pos, _pos, m_nbody->getNumBodies() * 4 * sizeof(float));
+ memcpy(vel, _vel, m_nbody->getNumBodies() * 4 * sizeof(float));
+ }
+
+ void setArrays(const float *pos, const float *vel) {
+ int sz = config.numBodies * 4 * sizeof(float);
+ if (pos != m_hPos)
+ memcpy(m_hPos, pos, sz);
+ if (vel != m_hVel)
+ memcpy(m_hVel, vel, sz);
+ m_nbody->setArray(BODYSYSTEM_POSITION, m_hPos);
+ m_nbody->setArray(BODYSYSTEM_VELOCITY, m_hVel);
+ resetRenderer();
+ }
+
+ void finalize();
+};
+
+#endif
--- /dev/null
+#include <cuda_runtime.h>
+#include <cuda_gl_interop.h>
+#include "helper_cuda.h"
+#include "helper_gl.h"
+
+#include "nbodycuda.h"
+
+void N_BodyCuda::init()
+{
+ checkCudaErrors(cudaEventCreate(&startEvent));
+ checkCudaErrors(cudaEventCreate(&stopEvent));
+ checkCudaErrors(cudaEventCreate(&hostMemSyncEvent));
+}
+
+void N_BodyCuda::init_dev()
+{
+// int dev_id = findCudaDevice(argc, (const char **)argv);
+ int dev_id = gpuGetMaxGflopsDeviceId();
+ checkCudaErrors(cudaSetDevice(dev_id));
+ cudaDeviceProp deviceProp;
+ checkCudaErrors(cudaGetDeviceProperties(&deviceProp, dev_id));
+printf("GPU Device %d: \"%s\" with compute capability %d.%d\n",
+ dev_id, deviceProp.name, deviceProp.major, deviceProp.minor);
+ version = deviceProp.major * 10 + deviceProp.minor;
+ numSMs = deviceProp.multiProcessorCount;
+}
+
+
+void N_BodyCuda::finish()
+{
+ checkCudaErrors(cudaEventDestroy(startEvent));
+ checkCudaErrors(cudaEventDestroy(stopEvent));
+ checkCudaErrors(cudaEventDestroy(hostMemSyncEvent));
+}
+
--- /dev/null
+#ifndef __NBODYCUDA_H__
+#define __NBODYCUDA_H__
+
+#include <vector>
+template <typename T>
+void read_tipsy_file(std::vector<T> &bodyPositions, std::vector<T> &bodyVelocities,
+ std::vector<int> &bodiesIDs, const std::string &fileName,
+ int &NTotal, int &NFirst, int &NSecond, int &NThird)
+{
+}
+
+#include <5_Simulations/nbody/bodysystem.h>
+#include <5_Simulations/nbody/bodysystemcuda.h>
+
+class N_BodyCuda
+{
+public:
+ N_BodyCuda();
+ ~N_BodyCuda();
+ void init_dev();
+ void init();
+ void finish();
+
+ int version, numSMs;
+
+ cudaEvent_t startEvent, stopEvent, hostMemSyncEvent;
+ void start_event() { cudaEventRecord(startEvent, 0); }
+ void stop_event() { cudaEventRecord(stopEvent, 0); }
+ void draw_event() { cudaEventRecord(hostMemSyncEvent, 0); }
+};
+
+class N_BodySystem : public BodySystemCUDA<float>
+{
+public:
+ N_BodySystem(int n_bodies, int n_devs, int blockSize)
+ : BodySystemCUDA<float>(n_bodies, n_devs, blockSize, 1) {}
+ N_BodySystem() {};
+ virtual void loadTipsyFile(const std::string &filename) {}
+};
+
+#endif
--- /dev/null
+/*
+ * CINELERRA
+ * Copyright (C) 2014 Adam Williams <broadcast at earthling dot net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include "bcdisplayinfo.h"
+#include "clip.h"
+#include "cwindow.h"
+#include "cwindowgui.h"
+#include "language.h"
+#include "nbody.h"
+#include "nbodywindow.h"
+#include "mwindow.h"
+#include "mwindowgui.h"
+#include "pluginserver.h"
+#include "theme.h"
+
+static const char *display_modes[] = {
+ N_("point"),
+ N_("sprite"),
+ N_("color"),
+};
+static const int num_display_modes = sizeof(display_modes)/sizeof(*display_modes);
+
+N_BodyWindow::N_BodyWindow(N_BodyMain *plugin)
+ : PluginClientWindow(plugin, 240, 200, 240, 200, 0)
+{
+ this->plugin = plugin;
+ press_x = press_y = 0;
+ button_no = 0;
+ pending_config = 0;
+}
+
+N_BodyWindow::~N_BodyWindow()
+{
+}
+
+void N_BodyWindow::create_objects()
+{
+ int x = 10, y = 10, pad = 5;
+ int x1 = 100;
+ BC_Title *title;
+ add_subwindow(title = new BC_Title(x,y, _("NBody"), MEDIUMFONT, YELLOW));
+ y += title->get_h() + 2*pad;
+ add_subwindow(title = new BC_Title(x,y, _("set demo:")));
+ set_demo = new N_BodySetDemo(this, x1,y, "0");
+ set_demo->create_objects();
+ y += set_demo->get_h() + pad;
+ add_subwindow(title = new BC_Title(x,y, _("draw mode:")));
+ set_mode = new N_BodySetMode(this, x1,y, _(display_modes[plugin->config.mode]));
+ set_mode->create_objects();
+ y += set_mode->get_h() + pad;
+ add_subwindow(title = new BC_Title(x,y, _("numBodies:")));
+ char text[BCSTRLEN];
+ sprintf(text, "%d", plugin->config.numBodies);
+ num_bodies = new N_BodyNumBodies(this, x1,y, text);
+ num_bodies->create_objects();
+ y += num_bodies->get_h() + pad;
+ add_subwindow(drag = new N_BodyDrag(this, x, y));
+ y += drag->get_h() + pad;
+ add_subwindow(reset = new N_BodyReset(this, x, y));
+ show_window();
+}
+
+void N_BodyWindow::update_gui()
+{
+ set_mode->update(_(display_modes[plugin->config.mode]));
+ char text[BCSTRLEN];
+ sprintf(text, "%d", plugin->config.numBodies);
+ num_bodies->update(text);
+}
+
+
+void N_BodyWindow::send_configure_change()
+{
+ pending_config = 0;
+ plugin->send_configure_change();
+}
+
+int N_BodyWindow::grab_event(XEvent *event)
+{
+ int ret = do_grab_event(event);
+ if( pending_config && !grab_event_count() )
+ send_configure_change();
+ return ret;
+}
+
+int N_BodyWindow::do_grab_event(XEvent *event)
+{
+ switch( event->type ) {
+ case ButtonPress: break;
+ case ButtonRelease: break;
+ case MotionNotify: break;
+ default:
+ return 0;
+ }
+
+ MWindow *mwindow = plugin->server->mwindow;
+ CWindowGUI *cwindow_gui = mwindow->cwindow->gui;
+ CWindowCanvas *canvas = cwindow_gui->canvas;
+ int cursor_x, cursor_y;
+ cwindow_gui->get_relative_cursor(cursor_x, cursor_y);
+ cursor_x -= canvas->view_x;
+ cursor_y -= canvas->view_y;
+ float output_x = cursor_x, output_y = cursor_y;
+ canvas->canvas_to_output(mwindow->edl, 0, output_x, output_y);
+
+ if( !button_no ) {
+ if( cursor_x < 0 || cursor_x >= canvas->view_w ||
+ cursor_y < 0 || cursor_y >= canvas->view_h )
+ return 0;
+ }
+
+ switch( event->type ) {
+ case ButtonPress:
+ if( button_no ) return 0;
+ press_x = output_x; press_y = output_y;
+ button_no = event->xbutton.button;
+ break;
+ case ButtonRelease:
+ if( !button_no ) return 0;
+ button_no = 0;
+ return 1;
+ case MotionNotify: {
+ if( !button_no ) return 0;
+ N_BodyConfig &config = plugin->config;
+ double dx = (double)(press_x - output_x);
+ double dy = (double)(press_y - output_y);
+ press_x = output_x; press_y = output_y;
+ switch( button_no ) {
+ case LEFT_BUTTON: {
+ config.trans[0] += dx / 5.0f;
+ config.trans[1] -= dy / 5.0f;
+ break; }
+ case MIDDLE_BUTTON: {
+ double s = 0.5f * fabs(config.trans[2]);
+ if( s < 0.1 ) s = 0.1;
+ config.trans[2] += (dy / 100.0f) * s;
+ break; }
+ case RIGHT_BUTTON: {
+ config.rot[0] += dy / 5.0f;
+ config.rot[1] += dx / 5.0f;
+ break; }
+ }
+ pending_config = 1;
+ break; }
+ default:
+ return 0;
+ }
+
+ return 1;
+}
+
+void N_BodyWindow::done_event(int result)
+{
+ ungrab(client->server->mwindow->cwindow->gui);
+}
+
+N_BodyDrag::N_BodyDrag(N_BodyWindow *gui, int x, int y)
+ : BC_CheckBox(x, y, 0, _("Drag"))
+{
+ this->gui = gui;
+}
+int N_BodyDrag::handle_event()
+{
+ CWindowGUI *cwindow_gui = gui->plugin->server->mwindow->cwindow->gui;
+ int value = get_value();
+ if( value ) {
+ if( !gui->grab(cwindow_gui) ) {
+ update(value = 0);
+ flicker(10,50);
+ }
+ }
+ else
+ gui->ungrab(cwindow_gui);
+ return 1;
+}
+
+N_BodySetMode::N_BodySetMode(N_BodyWindow *gui, int x, int y, const char *text)
+ : BC_PopupTextBox(gui, 0, text, x, y, 100, 160)
+{
+ this->gui = gui;
+}
+
+void N_BodySetMode::create_objects()
+{
+ BC_PopupTextBox::create_objects();
+ for( int i=0; i<num_display_modes; ++i )
+ mode_items.append(new BC_ListBoxItem(_(display_modes[i])));
+ update_list(&mode_items);
+}
+
+int N_BodySetMode::handle_event()
+{
+ N_BodyMain *plugin = gui->plugin;
+ plugin->config.mode = get_number();
+ plugin->send_configure_change();
+ return 1;
+}
+
+
+N_BodySetDemo::N_BodySetDemo(N_BodyWindow *gui, int x, int y, const char *text)
+ : BC_PopupTextBox(gui, 0, text, x, y, 100, 160)
+{
+ this->gui = gui;
+}
+
+void N_BodySetDemo::create_objects()
+{
+ BC_PopupTextBox::create_objects();
+ for( int i=0; i<N_BodyParams::num_demos; ++i ) {
+ char text[BCSTRLEN]; sprintf(text,"%d",i);
+ demo_items.append(new BC_ListBoxItem(text));
+ }
+ update_list(&demo_items);
+}
+
+int N_BodySetDemo::handle_event()
+{
+ N_BodyMain *plugin = gui->plugin;
+ plugin->selectDemo(get_number());
+ gui->update_gui();
+ plugin->send_configure_change();
+ return 1;
+}
+
+N_BodyNumBodies::N_BodyNumBodies(N_BodyWindow *gui, int x, int y, const char *text)
+ : BC_PopupTextBox(gui, 0, text, x, y, 100, 160)
+{
+ this->gui = gui;
+}
+
+void N_BodyNumBodies::create_objects()
+{
+ BC_PopupTextBox::create_objects();
+ for( int i=0; i<8; ++i ) {
+ char text[BCSTRLEN]; sprintf(text,"%d",1<<(i+6));
+ num_body_items.append(new BC_ListBoxItem(text));
+ }
+ update_list(&num_body_items);
+}
+
+int N_BodyNumBodies::handle_event()
+{
+ N_BodyMain *plugin = gui->plugin;
+ int i = get_number();
+ int n = i >= 0 ? (1 << (i+6)) : atoi(get_text());
+ bclamp(n, 0x10,0x4000);
+ plugin->config.numBodies = n;
+ plugin->send_configure_change();
+ return 1;
+}
+
+N_BodyReset::N_BodyReset(N_BodyWindow *gui, int x, int y)
+ : BC_GenericButton(x, y, _("Reset"))
+{
+ this->gui = gui;
+}
+N_BodyReset::~N_BodyReset()
+{
+}
+
+int N_BodyReset::handle_event()
+{
+ N_BodyMain *plugin = gui->plugin;
+ plugin->config.reset();
+ gui->update_gui();
+ gui->send_configure_change();
+ return 1;
+}
+
--- /dev/null
+/*
+ * CINELERRA
+ * Copyright (C) 2008-2014 Adam Williams <broadcast at earthling dot net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#ifndef NBODYCUDAWINDOW_H
+#define NBODYCUDAWINDOW_H
+
+
+#include "guicast.h"
+#include "nbody.h"
+
+class N_BodyDrag;
+class N_BodyReset;
+class NBodyModeItems;
+class N_BodySetMode;
+class NBodyDemoItems;
+class N_BodySetDemo;
+class NBodyNumBodyItems;
+class N_BodyNumBodies;
+class N_BodyWindow;
+
+class N_BodyDrag : public BC_CheckBox
+{
+public:
+ N_BodyDrag(N_BodyWindow *gui, int x, int y);
+
+ int handle_event();
+ N_BodyWindow *gui;
+};
+
+class N_BodyReset : public BC_GenericButton
+{
+public:
+ N_BodyReset(N_BodyWindow *gui, int x, int y);
+ ~N_BodyReset();
+ int handle_event();
+
+ N_BodyWindow *gui;
+};
+
+class NBodyModeItems : public ArrayList<BC_ListBoxItem*>
+{
+public:
+ NBodyModeItems() {}
+ ~NBodyModeItems() { remove_all_objects(); }
+};
+
+class N_BodySetMode : public BC_PopupTextBox
+{
+public:
+ N_BodySetMode(N_BodyWindow *gui, int x, int y, const char *text);
+ void create_objects();
+ int handle_event();
+
+ N_BodyWindow *gui;
+ NBodyModeItems mode_items;
+};
+
+class NBodyDemoItems : public ArrayList<BC_ListBoxItem*>
+{
+public:
+ NBodyDemoItems() {}
+ ~NBodyDemoItems() { remove_all_objects(); }
+};
+
+class N_BodySetDemo : public BC_PopupTextBox
+{
+public:
+ N_BodySetDemo(N_BodyWindow *gui, int x, int y, const char *text);
+ void create_objects();
+ int handle_event();
+
+ N_BodyWindow *gui;
+ NBodyDemoItems demo_items;
+};
+
+class NBodyNumBodyItems : public ArrayList<BC_ListBoxItem*>
+{
+public:
+ NBodyNumBodyItems() {}
+ ~NBodyNumBodyItems() { remove_all_objects(); }
+};
+
+class N_BodyNumBodies : public BC_PopupTextBox
+{
+public:
+ N_BodyNumBodies(N_BodyWindow *gui, int x, int y, const char *text);
+ void create_objects();
+ int handle_event();
+
+ N_BodyWindow *gui;
+ NBodyNumBodyItems num_body_items;
+};
+
+
+class N_BodyWindow : public PluginClientWindow
+{
+public:
+ N_BodyWindow(N_BodyMain *plugin);
+ ~N_BodyWindow();
+
+ void create_objects();
+ void update_gui();
+
+ int grab_event(XEvent *event);
+ int do_grab_event(XEvent *event);
+ void done_event(int result);
+ void send_configure_change();
+
+ N_BodyMain *plugin;
+ N_BodySetMode *set_mode;
+ N_BodySetDemo *set_demo;
+ N_BodyNumBodies *num_bodies;
+ N_BodyDrag *drag;
+ N_BodyReset *reset;
+
+ int press_x, press_y;
+ int button_no, pending_config;
+};
+
+#endif
--- /dev/null
+#include "5_Simulations/nbody/render_particles.cpp"
--enable-pthreads --enable-gpl --disable-ffplay \
$(if $(WANT_VAAPI),--enable-vaapi,--disable-vaapi) \
$(if $(WANT_VDPAU),--enable-vdpau,--disable-vdpau) \
+ $(if $(WANT_NV), --enable-nvenc --enable-nvdec) \
$(call if_pkg,twolame,--enable-libtwolame) \
$(call if_pkg,openjpeg,--enable-libopenjpeg) \
$(call if_pkg,lame,--enable-libmp3lame) \
$(call if_pkg,x264,--enable-libx264) \
$(call if_pkg,x265,--enable-libx265) \
--extra-cflags="\
+ $(if $(WANT_NV), $(inc_ffnvcodec)) \
$(call inc_path,twolame,libtwolame) \
$(call inc_path,lame,include) \
$(call inc_path,libaom,usr/local/include) \
$(call rules,$(call std-build,audiofile))
$(call rules,$(call std-build,encore))
$(call rules,$(call std-build,esound,audiofile))
-$(call rules,$(call std-build,ffmpeg, twolame lame openjpeg opus libtheora x264 x265 libvpx libaom libwebp))
+$(call rules,$(call std-build,ffmpeg, twolame lame openjpeg opus \
+ libtheora x264 x265 libvpx libaom libwebp \
+ $(if $(WANT_NV), ffnvcodec)))
$(call rules,$(call std-build,fftw))
$(call rules,$(call std-build,flac,libogg))
$(call rules,$(call std-build,giflib))
$(call rules,$(call std-build,sratom, serd sord lv2))
$(call rules,$(call std-build,lilv, lv2 sratom serd sord))
$(call rules,$(call std-build,suil, lv2))
+$(call rules,$(call std-build,ffnvcodec))
# specialize festival, multiple tarballs
festival:
https://archive.mozilla.org/pub/opus/opus-1.3.tar.gz
https://github.com/webmproject/libwebp = libwebp-1.0.2
https://github.com/mozilla/aom = libaom-v1.0.0
+git clone https://git.videolan.org/git/ffmpeg/nv-codec-headers.git
https://gitlab.com/drobilla/lv2/-/archive/v1.16.0/lv2-v1.16.0.tar.gz
http://download.drobilla.net/suil-0.10.2.tar.bz2