From b1649fe7b38cfb4bbec58b19fb8dda2daa0ce520 Mon Sep 17 00:00:00 2001 From: Good Guy Date: Sun, 16 Jun 2019 12:45:39 -0600 Subject: [PATCH] configure.ac add with-cuda/nv, update cakewalk theme, add cuda/plugins=mandel+nbody, add nvenc formats --- cinelerra-5.1/configure.ac | 19 +- cinelerra-5.1/ffmpeg/video/h264_nvenc.mp4 | 4 + cinelerra-5.1/ffmpeg/video/h265_nvenc.mp4 | 4 + cinelerra-5.1/plugin_cuda | 32 ++ cinelerra-5.1/plugin_defs | 3 + cinelerra-5.1/plugins/Makefile | 4 + cinelerra-5.1/plugins/mandelcuda/.swp | Bin 0 -> 12288 bytes cinelerra-5.1/plugins/mandelcuda/Makefile | 17 + cinelerra-5.1/plugins/mandelcuda/mandelbrot.C | 303 ++++++++++++++ cinelerra-5.1/plugins/mandelcuda/mandelbrot.h | 85 ++++ .../plugins/mandelcuda/mandelbrotwindow.C | 215 ++++++++++ .../plugins/mandelcuda/mandelbrotwindow.h | 83 ++++ .../plugins/mandelcuda/mandelcuda.cu | 160 +++++++ cinelerra-5.1/plugins/mandelcuda/mandelcuda.h | 23 + cinelerra-5.1/plugins/nbodycuda/.swp | Bin 0 -> 12288 bytes cinelerra-5.1/plugins/nbodycuda/Makefile | 20 + cinelerra-5.1/plugins/nbodycuda/bodysys.cu | 1 + cinelerra-5.1/plugins/nbodycuda/nbody.C | 392 ++++++++++++++++++ cinelerra-5.1/plugins/nbodycuda/nbody.h | 150 +++++++ cinelerra-5.1/plugins/nbodycuda/nbodycuda.cu | 35 ++ cinelerra-5.1/plugins/nbodycuda/nbodycuda.h | 41 ++ cinelerra-5.1/plugins/nbodycuda/nbodywindow.C | 286 +++++++++++++ cinelerra-5.1/plugins/nbodycuda/nbodywindow.h | 137 ++++++ cinelerra-5.1/plugins/nbodycuda/renders.C | 1 + .../theme_cakewalk/data/cin_icon_rec.png | Bin 3826 -> 3827 bytes .../theme_cakewalk/data/cin_icon_vwin.png | Bin 3310 -> 3311 bytes .../theme_cakewalk/data/heroine_icon.png | Bin 4135 -> 3918 bytes .../theme_cakewalk/data/in_checked.png | Bin 347 -> 372 bytes .../theme_cakewalk/data/in_checkedhi.png | Bin 347 -> 389 bytes .../plugins/theme_cakewalk/data/in_dn.png | Bin 336 -> 391 bytes .../plugins/theme_cakewalk/data/in_hi.png | Bin 245 -> 295 bytes .../plugins/theme_cakewalk/data/in_up.png | Bin 362 -> 385 bytes .../plugins/theme_cakewalk/data/inpoint.png | Bin 233 -> 281 bytes .../theme_cakewalk/data/label_checked.png | Bin 397 -> 384 bytes .../theme_cakewalk/data/label_checkedhi.png | Bin 456 -> 440 bytes .../theme_cakewalk/data/labeltoggle_dn.png | Bin 557 -> 545 bytes .../theme_cakewalk/data/labeltoggle_up.png | Bin 459 -> 455 bytes .../theme_cakewalk/data/labeltoggle_uphi.png | Bin 440 -> 432 bytes .../theme_cakewalk/data/out_checked.png | Bin 349 -> 389 bytes .../theme_cakewalk/data/out_checkedhi.png | Bin 238 -> 296 bytes .../plugins/theme_cakewalk/data/out_dn.png | Bin 341 -> 402 bytes .../plugins/theme_cakewalk/data/out_hi.png | Bin 374 -> 419 bytes .../plugins/theme_cakewalk/data/out_up.png | Bin 362 -> 399 bytes .../plugins/theme_cakewalk/data/outpoint.png | Bin 352 -> 400 bytes .../plugins/theme_cakewalk/data/pot_dn.png | Bin 1322 -> 1313 bytes .../plugins/theme_cakewalk/data/pot_hi.png | Bin 1317 -> 1426 bytes .../plugins/theme_cakewalk/data/pot_up.png | Bin 1550 -> 1530 bytes cinelerra-5.1/thirdparty/Makefile | 7 +- cinelerra-5.1/thirdparty/downloads.txt | 1 + cinelerra-5.1/thirdparty/src/ffnvcodec.tar.xz | Bin 0 -> 48588 bytes 50 files changed, 2021 insertions(+), 2 deletions(-) create mode 100644 cinelerra-5.1/ffmpeg/video/h264_nvenc.mp4 create mode 100644 cinelerra-5.1/ffmpeg/video/h265_nvenc.mp4 create mode 100644 cinelerra-5.1/plugin_cuda create mode 100644 cinelerra-5.1/plugins/mandelcuda/.swp create mode 100644 cinelerra-5.1/plugins/mandelcuda/Makefile create mode 100644 cinelerra-5.1/plugins/mandelcuda/mandelbrot.C create mode 100644 cinelerra-5.1/plugins/mandelcuda/mandelbrot.h create mode 100644 cinelerra-5.1/plugins/mandelcuda/mandelbrotwindow.C create mode 100644 cinelerra-5.1/plugins/mandelcuda/mandelbrotwindow.h create mode 100644 cinelerra-5.1/plugins/mandelcuda/mandelcuda.cu create mode 100644 cinelerra-5.1/plugins/mandelcuda/mandelcuda.h create mode 100644 cinelerra-5.1/plugins/nbodycuda/.swp create mode 100644 cinelerra-5.1/plugins/nbodycuda/Makefile create mode 100644 cinelerra-5.1/plugins/nbodycuda/bodysys.cu create mode 100644 cinelerra-5.1/plugins/nbodycuda/nbody.C create mode 100644 cinelerra-5.1/plugins/nbodycuda/nbody.h create mode 100644 cinelerra-5.1/plugins/nbodycuda/nbodycuda.cu create mode 100644 cinelerra-5.1/plugins/nbodycuda/nbodycuda.h create mode 100644 cinelerra-5.1/plugins/nbodycuda/nbodywindow.C create mode 100644 cinelerra-5.1/plugins/nbodycuda/nbodywindow.h create mode 100644 cinelerra-5.1/plugins/nbodycuda/renders.C create mode 100644 cinelerra-5.1/thirdparty/src/ffnvcodec.tar.xz diff --git a/cinelerra-5.1/configure.ac b/cinelerra-5.1/configure.ac index 90048a29..0f8c6e41 100644 --- a/cinelerra-5.1/configure.ac +++ b/cinelerra-5.1/configure.ac @@ -58,6 +58,8 @@ CHECK_WITH([thirdparty],[use thirdparty build],[CIN_3RDPARTY],[yes]) 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` @@ -414,6 +416,11 @@ PKG_3RD([libwebp],[auto], [ usr/local/lib*/libwebp*.a ], [ usr/local/include ]) +PKG_3RD([ffnvcodec],[auto], + [ffnvcodec], + [ ], + [ . ]) + AC_SUBST(STATIC_PKGS) AC_DEFUN([CHECK_ENABLE], [ @@ -589,6 +596,7 @@ if test "x$WANT_VAAPI" != "xno" -a "x$HAVE_VAAPI" = "xyes"; then 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" @@ -606,7 +614,6 @@ AC_ARG_WITH(m4_tolower([$1]), 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 @@ -683,6 +690,9 @@ CHECK_WANT([LV2], [auto], [use lv2], [ 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])]) @@ -832,6 +842,7 @@ PKG_PROVIDE([sratom], [$WANT_LV2]) 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 @@ -884,6 +895,8 @@ echo " using: with-libzmpeg = $WANT_LIBZMPEG" 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" @@ -920,6 +933,10 @@ if test "x$WANT_VDPAU" != "xno" -a "x$HAVE_VDPAU" = "xyes"; then 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' diff --git a/cinelerra-5.1/ffmpeg/video/h264_nvenc.mp4 b/cinelerra-5.1/ffmpeg/video/h264_nvenc.mp4 new file mode 100644 index 00000000..d48bacd2 --- /dev/null +++ b/cinelerra-5.1/ffmpeg/video/h264_nvenc.mp4 @@ -0,0 +1,4 @@ +mp4 h264_nvenc +# encode for nvidia graphics hw only +preset medium +profile main diff --git a/cinelerra-5.1/ffmpeg/video/h265_nvenc.mp4 b/cinelerra-5.1/ffmpeg/video/h265_nvenc.mp4 new file mode 100644 index 00000000..784d8a60 --- /dev/null +++ b/cinelerra-5.1/ffmpeg/video/h265_nvenc.mp4 @@ -0,0 +1,4 @@ +mp4 hevc_nvenc +# encode for nvidia graphics hw only +preset medium +profile main diff --git a/cinelerra-5.1/plugin_cuda b/cinelerra-5.1/plugin_cuda new file mode 100644 index 00000000..10ee7faf --- /dev/null +++ b/cinelerra-5.1/plugin_cuda @@ -0,0 +1,32 @@ +#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 $@ diff --git a/cinelerra-5.1/plugin_defs b/cinelerra-5.1/plugin_defs index 5890e213..afd04e88 100644 --- a/cinelerra-5.1/plugin_defs +++ b/cinelerra-5.1/plugin_defs @@ -15,6 +15,7 @@ themes := \ theme_suv \ theme_neophyte \ theme_unflat \ + theme_cakewalk \ plugin_dirs += video video := \ @@ -76,6 +77,8 @@ video := \ motionblur \ motion-cv \ motion-hv \ + mandelcuda \ + nbodycuda \ oil \ overlay \ perspective \ diff --git a/cinelerra-5.1/plugins/Makefile b/cinelerra-5.1/plugins/Makefile index 77292863..2bf29432 100644 --- a/cinelerra-5.1/plugins/Makefile +++ b/cinelerra-5.1/plugins/Makefile @@ -11,6 +11,9 @@ include $(TOPDIR)/opencv_build 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 @@ -18,6 +21,7 @@ endif # motion must come before perspective DIRS = $(OPENCV_OBJS) \ + $(CUDA_OBJS) \ 1080to480 \ 1080to540 \ 720to480 \ diff --git a/cinelerra-5.1/plugins/mandelcuda/.swp b/cinelerra-5.1/plugins/mandelcuda/.swp new file mode 100644 index 0000000000000000000000000000000000000000..5d9b1b9cdda9fefd50f50161aa8e58521ce9f213 GIT binary patch literal 12288 zcmeI2KX21O7{=eSG4My_3m7^u6#ML?w!3sjsOnhO$T^=93)^S;59-E;VB~8cA+|2; z3{(tkEPMqf;B^|;PRa!sP*mx$^5o9;bI+ZBcNZy2rtb4+C)T0k5g+&4x69-E0a2-S z-JNeLQ!S%(uB+Nv)MA}QNxrE8?tuUZY=OY-)A7i2+m81hJ+vO|o^D|b=n@1#00ck) z1V8`;KmY_lU|R(0VuxOF=eL#v*j<)8YvuA31qgru2!H?xfB*=900@8p2!H?xfWQqT z5XD5r9imUH_V@qp`~TN_M4wr2SSjlT>nUrG_46*#7uGx0YnEmmvmUd4aLzZ@#WM3F zmmgT?thcQ9f1w+Q5km$65C8!X009sH0T2Lz|4TqLRVfz#w-vI9BinNwPfU|s^J&Gz@LHKVAba;EA^oE-*};J{9kyg3s|F4HDfi>OK2AYuA-^cWb8g^FCJAHS4|$j_xL7H*n2{Q$M5^{ zO?~;Js~mr1$O-zKz?2hsS2=-a$O-$L(3BJQ&mNkdz4Nq8=_JZyl}<}tJBxaEfo#by ztJT0Fi-K%zUCy@{+|cy<`5N}s&R^*N!N?P9_6z|Sa#lc^Jbg~!8ayi#Yx49tzA0xs nTxf=zaX)Ee6Q7lZPqe-hH}9rv_J7#8yaKxYzaF#tK|#L&($}R5 literal 0 HcmV?d00001 diff --git a/cinelerra-5.1/plugins/mandelcuda/Makefile b/cinelerra-5.1/plugins/mandelcuda/Makefile new file mode 100644 index 00000000..95d8587d --- /dev/null +++ b/cinelerra-5.1/plugins/mandelcuda/Makefile @@ -0,0 +1,17 @@ +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 + diff --git a/cinelerra-5.1/plugins/mandelcuda/mandelbrot.C b/cinelerra-5.1/plugins/mandelcuda/mandelbrot.C new file mode 100644 index 00000000..693b867f --- /dev/null +++ b/cinelerra-5.1/plugins/mandelcuda/mandelbrot.C @@ -0,0 +1,303 @@ +/* + * CINELERRA + * Copyright (C) 1997-2014 Adam Williams + * + * 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; +} + diff --git a/cinelerra-5.1/plugins/mandelcuda/mandelbrot.h b/cinelerra-5.1/plugins/mandelcuda/mandelbrot.h new file mode 100644 index 00000000..c2931cfd --- /dev/null +++ b/cinelerra-5.1/plugins/mandelcuda/mandelbrot.h @@ -0,0 +1,85 @@ +/* + * CINELERRA + * Copyright (C) 1997-2014 Adam Williams + * + * 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 diff --git a/cinelerra-5.1/plugins/mandelcuda/mandelbrotwindow.C b/cinelerra-5.1/plugins/mandelcuda/mandelbrotwindow.C new file mode 100644 index 00000000..c4b11687 --- /dev/null +++ b/cinelerra-5.1/plugins/mandelcuda/mandelbrotwindow.C @@ -0,0 +1,215 @@ +/* + * CINELERRA + * Copyright (C) 2014 Adam Williams + * + * 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; +} + + + diff --git a/cinelerra-5.1/plugins/mandelcuda/mandelbrotwindow.h b/cinelerra-5.1/plugins/mandelcuda/mandelbrotwindow.h new file mode 100644 index 00000000..98208fce --- /dev/null +++ b/cinelerra-5.1/plugins/mandelcuda/mandelbrotwindow.h @@ -0,0 +1,83 @@ +/* + * CINELERRA + * Copyright (C) 2008-2014 Adam Williams + * + * 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 diff --git a/cinelerra-5.1/plugins/mandelcuda/mandelcuda.cu b/cinelerra-5.1/plugins/mandelcuda/mandelcuda.cu new file mode 100644 index 00000000..8ba357ea --- /dev/null +++ b/cinelerra-5.1/plugins/mandelcuda/mandelcuda.cu @@ -0,0 +1,160 @@ +#include "mandelcuda.h" +#include +#include +#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 __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 __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= 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<<>>((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)); +} + diff --git a/cinelerra-5.1/plugins/mandelcuda/mandelcuda.h b/cinelerra-5.1/plugins/mandelcuda/mandelcuda.h new file mode 100644 index 00000000..3fc9c48f --- /dev/null +++ b/cinelerra-5.1/plugins/mandelcuda/mandelcuda.h @@ -0,0 +1,23 @@ +#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 diff --git a/cinelerra-5.1/plugins/nbodycuda/.swp b/cinelerra-5.1/plugins/nbodycuda/.swp new file mode 100644 index 0000000000000000000000000000000000000000..5d9b1b9cdda9fefd50f50161aa8e58521ce9f213 GIT binary patch literal 12288 zcmeI2KX21O7{=eSG4My_3m7^u6#ML?w!3sjsOnhO$T^=93)^S;59-E;VB~8cA+|2; z3{(tkEPMqf;B^|;PRa!sP*mx$^5o9;bI+ZBcNZy2rtb4+C)T0k5g+&4x69-E0a2-S z-JNeLQ!S%(uB+Nv)MA}QNxrE8?tuUZY=OY-)A7i2+m81hJ+vO|o^D|b=n@1#00ck) z1V8`;KmY_lU|R(0VuxOF=eL#v*j<)8YvuA31qgru2!H?xfB*=900@8p2!H?xfWQqT z5XD5r9imUH_V@qp`~TN_M4wr2SSjlT>nUrG_46*#7uGx0YnEmmvmUd4aLzZ@#WM3F zmmgT?thcQ9f1w+Q5km$65C8!X009sH0T2Lz|4TqLRVfz#w-vI9BinNwPfU|s^J&Gz@LHKVAba;EA^oE-*};J{9kyg3s|F4HDfi>OK2AYuA-^cWb8g^FCJAHS4|$j_xL7H*n2{Q$M5^{ zO?~;Js~mr1$O-zKz?2hsS2=-a$O-$L(3BJQ&mNkdz4Nq8=_JZyl}<}tJBxaEfo#by ztJT0Fi-K%zUCy@{+|cy<`5N}s&R^*N!N?P9_6z|Sa#lc^Jbg~!8ayi#Yx49tzA0xs nTxf=zaX)Ee6Q7lZPqe-hH}9rv_J7#8yaKxYzaF#tK|#L&($}R5 literal 0 HcmV?d00001 diff --git a/cinelerra-5.1/plugins/nbodycuda/Makefile b/cinelerra-5.1/plugins/nbodycuda/Makefile new file mode 100644 index 00000000..a99f748f --- /dev/null +++ b/cinelerra-5.1/plugins/nbodycuda/Makefile @@ -0,0 +1,20 @@ +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 diff --git a/cinelerra-5.1/plugins/nbodycuda/bodysys.cu b/cinelerra-5.1/plugins/nbodycuda/bodysys.cu new file mode 100644 index 00000000..76c997be --- /dev/null +++ b/cinelerra-5.1/plugins/nbodycuda/bodysys.cu @@ -0,0 +1 @@ +#include "5_Simulations/nbody/bodysystemcuda.cu" diff --git a/cinelerra-5.1/plugins/nbodycuda/nbody.C b/cinelerra-5.1/plugins/nbodycuda/nbody.C new file mode 100644 index 00000000..ae15e643 --- /dev/null +++ b/cinelerra-5.1/plugins/nbodycuda/nbody.C @@ -0,0 +1,392 @@ +/* + * CINELERRA + * Copyright (C) 1997-2014 Adam Williams + * + * 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 +#include +#include + +#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; +} + diff --git a/cinelerra-5.1/plugins/nbodycuda/nbody.h b/cinelerra-5.1/plugins/nbodycuda/nbody.h new file mode 100644 index 00000000..3d97e6a1 --- /dev/null +++ b/cinelerra-5.1/plugins/nbodycuda/nbody.h @@ -0,0 +1,150 @@ +/* + * CINELERRA + * Copyright (C) 1997-2014 Adam Williams + * + * 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 +#include +#include +#include + +#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 *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 diff --git a/cinelerra-5.1/plugins/nbodycuda/nbodycuda.cu b/cinelerra-5.1/plugins/nbodycuda/nbodycuda.cu new file mode 100644 index 00000000..b82c79fd --- /dev/null +++ b/cinelerra-5.1/plugins/nbodycuda/nbodycuda.cu @@ -0,0 +1,35 @@ +#include +#include +#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)); +} + diff --git a/cinelerra-5.1/plugins/nbodycuda/nbodycuda.h b/cinelerra-5.1/plugins/nbodycuda/nbodycuda.h new file mode 100644 index 00000000..b1a9cb05 --- /dev/null +++ b/cinelerra-5.1/plugins/nbodycuda/nbodycuda.h @@ -0,0 +1,41 @@ +#ifndef __NBODYCUDA_H__ +#define __NBODYCUDA_H__ + +#include +template +void read_tipsy_file(std::vector &bodyPositions, std::vector &bodyVelocities, + std::vector &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 +{ +public: + N_BodySystem(int n_bodies, int n_devs, int blockSize) + : BodySystemCUDA(n_bodies, n_devs, blockSize, 1) {} + N_BodySystem() {}; + virtual void loadTipsyFile(const std::string &filename) {} +}; + +#endif diff --git a/cinelerra-5.1/plugins/nbodycuda/nbodywindow.C b/cinelerra-5.1/plugins/nbodycuda/nbodywindow.C new file mode 100644 index 00000000..c5c7766e --- /dev/null +++ b/cinelerra-5.1/plugins/nbodycuda/nbodywindow.C @@ -0,0 +1,286 @@ +/* + * CINELERRA + * Copyright (C) 2014 Adam Williams + * + * 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; iplugin; + 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; iplugin; + 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; +} + diff --git a/cinelerra-5.1/plugins/nbodycuda/nbodywindow.h b/cinelerra-5.1/plugins/nbodycuda/nbodywindow.h new file mode 100644 index 00000000..b4b04c0b --- /dev/null +++ b/cinelerra-5.1/plugins/nbodycuda/nbodywindow.h @@ -0,0 +1,137 @@ +/* + * CINELERRA + * Copyright (C) 2008-2014 Adam Williams + * + * 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 +{ +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 +{ +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 +{ +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 diff --git a/cinelerra-5.1/plugins/nbodycuda/renders.C b/cinelerra-5.1/plugins/nbodycuda/renders.C new file mode 100644 index 00000000..82d669d5 --- /dev/null +++ b/cinelerra-5.1/plugins/nbodycuda/renders.C @@ -0,0 +1 @@ +#include "5_Simulations/nbody/render_particles.cpp" diff --git a/cinelerra-5.1/plugins/theme_cakewalk/data/cin_icon_rec.png b/cinelerra-5.1/plugins/theme_cakewalk/data/cin_icon_rec.png index 2c658a22948b0c48c54a4ceef2ef8969d0863f5c..61188c4000c57a0e9d15c9522746fc3f63154325 100644 GIT binary patch delta 3260 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 W+#qm_yz^K900004_|xQCnost?=}TNgT{TAP>Ta j|Nl3*?y2YuY)1|aZs^>bP0l+XkKlrT#w delta 143 zcmZo=zRfh@N_~;1i(`mIZ*s~3rhoC5LX#4HRg2G-VFm%^$F**6S9=-g3H!CGFo-E# z`IDBAu%lP$)Bpd;mv|CWY7VWa4V9iRw5lTg%7j4Y7ik<1Q~v+of9Ah-RQN>~dE-|x vpB3&2u(5@)v9alj2)eoXrRat3VP=S*CgQ$s;j%UcAmH$H^>bP0l+XkK+_^a( diff --git a/cinelerra-5.1/plugins/theme_cakewalk/data/in_dn.png b/cinelerra-5.1/plugins/theme_cakewalk/data/in_dn.png index 9ad33eac3a078df17fe4d71eb8dcd21f4b78b075..62e0c9493640a90f890aa392648fc2fc4f825c7b 100644 GIT binary patch delta 187 zcmV;s07U=L0*3>T)PJ5yL_t(IjqQ`c3Bo`SMc)sKNFW8+f+bjlm3YfN@vbLtDZ^Uq zK#~Fi2}mI0MNuTlZiwK;f7{*1V`iBV9jRhcLDKaGV6YDlq|bBE2ad_i2QnyuTu?tQ zicu25WqD(x6J;OcY^OEOLjo@eqH!T#`PjeYXA)yRSrWk3b~HpojC1Twtm_5WDt_&b p8CiHF^OgVzB6zDttUjupo;wc2AjS!dTG9Xj002ovPDHLkV1oMfPs;!R delta 131 zcmV-}0DS+41JDAH)O=@2L_t(IjbmiM0)7-SDE(t*xQk5=3hs0DFet$|On4L$4Ooa! z^ZP#o!);^%CI*Jbq#E*syN5v=p8~3QXVj2UL+EA*G09%$YYD?uG@BoD_Aq#mVhAfE l1A`W_z<&k?PBcR)2LKT^58jf~kCp%c002ovPDHLkV1kM8G7|s* diff --git a/cinelerra-5.1/plugins/theme_cakewalk/data/in_hi.png b/cinelerra-5.1/plugins/theme_cakewalk/data/in_hi.png index c020c3360f80a4227a75bb3416917796c4fefd82..59d58aaf480506027e051b2a0520b58ffff214cd 100644 GIT binary patch delta 193 zcmV;y06zcq0jC0xZhxdnL_t(IjbmiM0_@hlZ1~T}P>)THfq{X6@jpZ3pXR+P=@?xWMrj+OaA+tZ+pv!PX#e~N1N@(pE}33>t4b0&VNRRSw{lJ vXOUtE0|NsC9|OaGxNDgHF-RdxQYBykxiBeMj~c}p00000NkvXXu0mjfmZMff delta 143 zcmV;A0C4}O0`&oqZhvw~L_t(IjbmiM0&Ld4RAOXgxQk7Wfq{X6;XlLu!@=T8FfJ2L zg(LtLBGmk5U|_h7BErP*m^4HFGdwvQEUt}D301r^YRIS|bTfo-vS(zFv0eA_Dw^2i x!-3)+#2doEz{D%PDHLkV1m7_L7@Nu diff --git a/cinelerra-5.1/plugins/theme_cakewalk/data/in_up.png b/cinelerra-5.1/plugins/theme_cakewalk/data/in_up.png index 6bdccf327052b8cefb779a26ca37c6df9cb2b5cf..6a8bb8c37d1a40baec07a5360abf008373e3ef1a 100644 GIT binary patch delta 175 zcmV;g08szx0)YdN+JBNsL_t(IjbmV-0${`@Xt(xd!+%DGdJM(?85$1-i#MQ)Gf~4O zEJUjN#K6GthJoq-d$J7q&%kiyHwTOLNiX3~xYQ8z4kH8OCVU1EXUPBmzX_?KO2Cd9 zLWUv#85vnAH-zE8pZT`8d=weN$iSe(_T$fE+jXz5*{pw=hA2%9v3ZA&f#E+N(?13& dvRpz8007C9B}Myubo~GT002ovPDHLkV1f}tQsn>u delta 152 zcmV;J0B8S!1L^{h+JAdVL_t(IjbmV-0${`@XtVaE5+ftSU3BsP{~45z1dHE87iXe| zOIQf1_|Nc_fstW50|NuYKgR!G$TNh2;nm?F@lbpUsN$VbLq-iD1`v~C#cbETT+P71 z!0?yhfA+B;iC3h%gpq-pfq@}}fq@}}=|3Y6HYHT?4gd)$7!e1%2u(u(0000Uz@vFRhLs90HN>`thc~2*8l(j07*qoM6N<$f?01iGXMYp diff --git a/cinelerra-5.1/plugins/theme_cakewalk/data/label_checked.png b/cinelerra-5.1/plugins/theme_cakewalk/data/label_checked.png index ada0e5b072bbc22d54fe667ff469c9f90c61a0b4..3b6016d317db1b0f232740bba6c255adea600099 100644 GIT binary patch delta 284 zcmV+%0ptFS1AqgNZGQm$NklBeLl1RA<=6>OL9GBb) zM;IGH(3GrYQF199j(EjElw4%s$sVryfQ>%=m1p~qL9A+MT7O5q3k%x{CQO4a7=Bz`IgpF8I`zo@Ip(v)-UmuPMGLsWOh^49DMrbCFQ4@m5JeBdW_M}pC&AF9+-b_Clsg&3 ijSumZF^$R~=oJH5wm;|+0jH+`0000L>vv%Q&vrdU*|B0jD0UKz{;Z+>44y+~r%voi6sY7g5&oiTCg^p*l zW92-t5mI}f-qr3IGc7p9K%IZM&~7;Ncxs5eL*2MUTP}VS^@Y@RZ9l0EAoM8-=01n! v>jB?R%xuR@j3Sw>M!n{5oJF)^sZr?-J1<3=5;hev00000NkvXXu0mjfKg5Uh diff --git a/cinelerra-5.1/plugins/theme_cakewalk/data/label_checkedhi.png b/cinelerra-5.1/plugins/theme_cakewalk/data/label_checkedhi.png index 43334e9a0ae53249247d025837131bb86ca4a436..1f7b260ffdcb9cc2e57e49c8066ee55485563231 100644 GIT binary patch delta 339 zcmV-Z0j&PW1Goc_ZhtjNL_t(Ijir*mO9EjSfS>nO)1@}2mLzIWkA{MVCjSkq!60Y| zn`^2iTAgc%=s##|5pt{uIt!tuw!$qC>F(YJL9Qz=xO>Ovdw9Mdd}7`5I>seQN7zuz zN{Isifz2r*=_0Bn#Yh)1D=DOmh?Eq_raVbbG2KMOPnZZW+kaAV+%|BMtRctZJYOpS z@5Mu)Gr{yG@D3lvBLD@ETHC|44)h~C?NWKlBQzs{KBjf4wY_l!KpgiCqygAi&3YFi z1Z4d4P{2SMBY!j+T12YdE0ES0d}a3SVR05Oa}csxBQHdv7q#2v9EHIRu=?v2MDCax zuF1m7Fg5~Uk4)8hB)A7=LiiKkUy-F=FY0R)0EpwhVr>6}?EDq@cdT1EGq-H!R!-x* l_%A;wG|3O985Z{9v~QbAU&$`_SBC%q002ovPDHLkV1mwnnBxEd delta 355 zcmV-p0i6E01IPoAZhu8dL_t(Ijiu7RFGEon#_{ia(pJ-iFfh9j%dMsZVKAAQEtL4t z#KfN<7HMp(jE$X$#h^*Wgn@fCO&BCL5{sm5;@;O(xxMO2+OwVKJm-@)Cr8w^7f_0H zx`ai8s?{+7;OnqKq&vhI%b;|Js9FZPL_{nD#JZd$Zcvj$#DD9M@KIegl5t8vp)*5v zB~!UD0J!cpaM`Zr`F{#!-UfF741mnz;l-AK_h73~Ofi`sVDC5;20k#FlbO=j4+0?B z`&W!E1KP~at`n%j=~W^KD8h=^m6v87P4E6i0&((vieMvu_wA>5N zsW;tG zUct=5rbY!N5qK&EB?4aYb-+`Em4cFz3hV;YoPtO#d+N4$vwv`z$6$pE=Z04WFckuz zyM&!A$-Ab^Ie-F4z=Vh@&`(S{ax1JN)Dwa}5mgCh19YC6Ha!b9z%H^OPZAKh!eiWR zp=R3j=7GkVlv}(2o%wrYXpT=oa_C&~nZ{?t_nX6kZ@A)Zkx}7-h$G69 z0ofE&LKxCUV~rX*nmvOp)Iplg&BlYcC8r*II(pu)aY;l=>i z4R%m&hk+fH{~R^jVGqCn$R!;{$N?{Ys`8j-u{O_PJslLhijtLGzW*cuc9EtEc|d#F z^>YdZs!yrD77EMB3XNW1{9C6)72&w|&P_L&8v7(a)AVCUPMIrzFi=?6NO+UffVsgl zaGz|mASbl_p-u@>a>|zxG74{jRm&JMLBUW7fK{R{u-YeA)~zBB!}!p7FL3@*K)r3w n!nn{cZ;!L#wV1FRHp93dN-0u$8%*s&00000NkvXXu0mjf7ay80 diff --git a/cinelerra-5.1/plugins/theme_cakewalk/data/labeltoggle_up.png b/cinelerra-5.1/plugins/theme_cakewalk/data/labeltoggle_up.png index e7769c3b997745392546554e4ad55624904f8c46..f697b71bd68eb29d339e697f55ff3abd0f97426d 100644 GIT binary patch delta 354 zcmV-o0iFKK1IGi9Zhu5cL_t(IjqQ-3O9NpT#((d3=UFzFffi$SxxJ3$c3{s7Bh$)IR*CoWA8#I?1Zeuizbot|M}^NG*6txui*eN`apar&4Q}fP6=ecuPwCRdq_H03V$FzGL{F*AxS?3QI5yP zcL5YYDUtVmB`KiZQ%7%lwrhzd69CkGC8<&(?|(r6s!N5MDAIuLcw!i52wI!U>1K-} zU0o{FI!4bk-!ASRM^|QsfjI!tT4Kx76%n?8`4*W&&vuTwdy0S}uhzC`u3P7j6H`3{ zJMHn!`(QK|>|03C0GKSUP8eElfuXJ|8W_f`w|MFW^WQcBc(UCpqSpiV#!rAy2!Ln1 zmuODfTO4~y_dG0Xh7ABBmX&EVo6*RCmHjRE3BZwG3#3gnX8-^I07*qoM6N<$f|6sQ AApigX delta 358 zcmV-s0h#{C1Iq)DZhuHgL_t(IjqQ*zEJINghQIsn>$ALyHZ?S{h$dztp>~N)+S*G( zV$w-s6N^|3%q{I;kw{}PFp!vOgruI-AdyHI1hw=%y%vwxr!_RO`M3L@|9t113;+5P ziT>hL21T@e0{6Ora|LUFYy(l(6yw@eB7Y2GwXH3bS}7;sE4W&)cW_4>cc+g||p;LdPwdBNB{r;07*qoM6N<$ Eg3j5aI{*Lx diff --git a/cinelerra-5.1/plugins/theme_cakewalk/data/labeltoggle_uphi.png b/cinelerra-5.1/plugins/theme_cakewalk/data/labeltoggle_uphi.png index c521b8c154f828a9cdbef853dc24c68de109ec95..7ae1f93d80f21f2b2ef31abc7c5ef61cd68cd58f 100644 GIT binary patch delta 331 zcmV-R0kr-ZhtLFL_t(Ijir*mOG053hM#j(a%l;iT5@U7v7w>=L~AgJ8p3u_ z{Dg>B$Ecy8|G=?D$kpvy2sJr0xkw<=)zeb`xab}3J>&a6Jl{KflCwq;?3u_X$7)zM zx&RFJR3Mf_v8)nPVh~>D`z7#I5G(@-A6 db{ek2xL+3aRo;#4lYsyL002ovPDHLkV1hZIoihLc delta 339 zcmV-Z0j&P81Goc_ZhtjNL_t(Ijiu7DOF~f;$MNsEKFOseaL-l8h6ewSmY0=5)MWoa z;&q828fuFg`v-z>DM)a33CjcfX(;q@GlTc;c+c;C?zxvES*`k@XGC7I zY!uBz2S8!o2*g4RnlZ#g6yhWDgLpAJNg4wMfgqyssmQu%iGQsFdr<^|-L_ON4Ztng z3UEC!8R%a|BMnsm^Gz-V9;^T_;gq+3&rJRb@1WxXuZmZwiye*;;706|!YVMj+SGcW zU@o4+fPxg;vhz5~g{y6`HG!kiOV%=IIz><%Pl3SUom9@l=fv%EL64JtdJSOFtqC*- z%;mdM8ie1*JaBreJ$o?hDSjS<)$P@$3Kq002ovPDHLkV1f!GpKkyF diff --git a/cinelerra-5.1/plugins/theme_cakewalk/data/out_checked.png b/cinelerra-5.1/plugins/theme_cakewalk/data/out_checked.png index b2289b00513547a72d3f354d78ce4aa404da9e6a..0f1eb065051b8323e72ebf0e20a9745f9af7a3b0 100644 GIT binary patch delta 179 zcmV;k08Ibg0)+#R+JBZwL_t(IjqT7o4uVh+h2ejQ#!44pv{DNd*5WR#*#Wo&m*QFs zSYX%!2_2d+HrntA<3c^4TK;Hzl2xJeSma%cM@*v(K*Dziqx9}2n zRuY?7djPu-$XEoy1d?@$VB_m%VBUNf;SIg4Q-nQzC~bXH(fOZ z7J%`Rh|Mz~d&OGBhH`cS?2u$|9a-HT2uIf>?wiz9<0T*PmplAS5-=Sl(IPe|JC~&O w_L|!SNSZ)HN|r$6C85?i!q!#P;w-^{0zN4v8Wnf@nCE5^1oogQG3J7|UflA&PHDuHfx*39!?EhcU+QGoUAd8~n q|9=^h3}IkoR3ns6umP%g2LO5J8J(>3c^4TM&B3IBEda?dIL)j;w{pp(mt`*$}YF? z5_Vq00|-Gua4jNY0?B5HVB@QXfqC=8h!2W2nINSB3!7+5R?i1b1wIUFt)}8FuF@hkXJD%Np|{fOJs+0000Knh?% z<}fla-1^7B@EuJ|m4ShQ6`vuDgls|fB2B$BYRIS|bTb4c?|d&|*zu2nK^9Go3`vIk kXJAlc#8VXD0#xx10HTEv!_p2K`~Uy|07*qoM6N<$f(LUoy8r+H diff --git a/cinelerra-5.1/plugins/theme_cakewalk/data/out_hi.png b/cinelerra-5.1/plugins/theme_cakewalk/data/out_hi.png index 2143e29daccdcc3b7f81bb01942779c41694c377..260bc41a5fc4137d5f60e91802f9aecfef2005ad 100644 GIT binary patch delta 209 zcmV;?051Rb0;2Xg9tsw3Ko@7irGXT{ zg3S5H#PE#qKf_t5y<7|o|D_oi82CsshL_t(Ijbmg$0(R?Poc{lxQGo#m`1}8_$+2Lmhv?!g$ejQG z7=;-a8ANay!oLQ^A2k|7NL87vqW86ENF6KsGg-T?qJnHQq% Sj_6eY0000Cdk95K5u*#!@g3%=U%A<=KS8O8UV4O<@g*d%hnzibLovy7)g#CsBFops7~ z91uBNT<4bDk|S}R{j>X}A*ul|(o>SalpsF9fyeMvX9gn&HJj1`g4`6(% z2a%wl)I(y`l4Sw8VAO(93+QOU`}fb}$*}-uQSssJlTaA@|2KaIPKJMfv#Dyqe}@07 s;2fe06ihI1rRo3w3`A8Zqkv)n0Q0FM-39`RdH?_b07*qoM6N<$f>MT8PXGV_ delta 142 zcmbQh{D5h~t@=Vw7sn8f&g29MRu%?jz0U9X^5zdNYiQ_nhtHGX{wKVFVR>B20hb;n zF9vQsPB*q=1|=K+^ZXB=n8g@)uZ8hRg0zXFN!Gy?tc%4SXlmK*sTJzd`!=63|EK#b t)+bY}ZyY$lD#*<2th`oNo|Oj#7_^JT)AxONAIAU$p6srEF6*2UngFvBGPVE! diff --git a/cinelerra-5.1/plugins/theme_cakewalk/data/pot_dn.png b/cinelerra-5.1/plugins/theme_cakewalk/data/pot_dn.png index 0a2989d3d1633975f64ae1541edd25b8386be7a1..0ad7f75db14c3af27f4bbc4b5741f292a1dd127f 100644 GIT binary patch delta 1219 zcmV;!1U&ny3ZV*+ZhxLhL_t(oh25A@g6M)(MF%^_47*=g!Rg%(>^Dx%UdoR5F=dr<&a(sxgI~0)Jak0tf+=8H5>un+n$q zj5x+W5)Oywmg^(cUYNcY-=QK$RoD+SFT>-pD8o3;V5l>CebvAciJR?~cup&N01ySn zXAPqni}^IT?RfRDQJ;z8drMcV_jWDsat3zI-jKmZ+e75bo&tc~P)L;%0k;ST}&?vv*dv z`V!UT#N$rHq{p_TJ~4fQ2?VNmjQOR)OT3+mHiEj02q5CWkg( zeSe}BYINvX?*L?Me3t=CI2@i6WmtfHo9Yv_eQkx(f#`5YN5?$46Gg`v1e`s=JR7{V zjatyB#DWC?2eAg-^9CT)8NH73o7cdh&U{V5`XgC9rSO~!hr4b(2L@oP=QzsDo2@o` zg0<<=y&DVcYApghvI^$JvuzcyNF~Hr`y?;`aCO>Z=$?-Uxs}gAf zFBXGZ63o@)Wc)o*ISaHD%DX+k-}jKtRzKSfH9G8TD-a77+|id2Vqv1M2+UO~ zHNH(9If^3(5CYZS2V@W(My$bS>paw|fw@W~5`IhaF-3Qm7YZq{{YHh$+8uZJ>CES002ovPDHLkV1i{!Me6_n delta 1228 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 delta 1224 zcmV;(1ULJV3#AH>ZGQx!Nkl3J2~#WNi$+J6qT03jdl`jh@j?RCWQCi^!M&?KYOKy62f4lI-^-^N#<$sgP(;BjTvLQ=F35ZBnxS{FL z6U9b{2j4*WK4a0(e=n8()bdN^X|A+<*6wPVQ4#d5a3uQeoMIy*u?A831E~C}uaxDS zzWLa?+T+6(7a;AayMFd+okQmOOy`VPGTFNlm0ech z=Y&&Os~qPO4psqlcRU_12QZ#ju^p)FOB?PiqM|P+D z70-6%uN#2e4*7=_4!pCjunpP1b^d-+k+b0!T5dcf2H>fC7)Zao%Cfb#FjLyG+OlPp zhd?Uenj^FC&4@KNwk1^b0Kj`um-WGCyMGX(LCgN;Y`&^~P`h?*a!xUThKA@lQ8^JX z@X?DIT0_sKwyh5;pKf$DU=ZL~IMQ_X(P!q|iI2sHPO0#ARz*+79JzdZ`C9Id)t3Fu zSpo(SJr%BR-Y+7LP0ze%7h|J0kEv=Wz|}j3(?ccP%Pjp*UmZ~PHF<2QnfZQ?hJPEH zKAuZzUa>r*!-IPeP6EMc4=yGh&LXh38{?Ws^7YV0!m%E(i&7YS6Ny@HXmXYIU8`zkw-uD zC5h!3yA|8u@B4H&{;}qQ5J)L>i$Q0*X4k1@6U!5i$IC@B+eLL7qMJ}@5vWoKY*bYghre^D(^A?ugR~SWEz|&I3J4o8FqmLV z1mapyVss~%XiPd3NFX5(an~|k88vRy1xDDhP=NqLgqi?}L8x?~%AeF0ra(F~v_NOx zJ1&N)ZK=|h(nXiy=%p29e*lIfof16-~$pM2|=SE zzae^pWbp~x-r6@-9~m`JW8)GPQ!lVl!5V`>QsIzmB)l&aYMn5!-Qn3kvX0^HW+@MtMaAC1o=Z5datTpg7Jpd*{y1 zX9C;P)bx%)K7UuR(&;qqZBg1TUE+QsIob!u^7{xZUc&r9HJ-dYfP|tSeA3YH-I&2_ z+cs)h%_tuO+`M+3^DQm(^^SR}3}|X`5i5d0Dy!x`HkM}YCmL+qc1Mc$j08oo?`vR- z<2aoC`82V5_5=C$h+UcP_R)yr*k+_-^)Ki_eOl+-|G@pNHRI-TZx zOUtA{Wp(b%FF5Hm3Y+bwrbR=*5D5uLdt3CGmW1)B_x^p_qtOhDNN518p|PnV-Em4o+l0(ld8PTSq-2Mz#!ZMm{M4nD<(4jQ?kQ* z0Dnf5s{lT~FIP-t{QcSC6#%2k1%T3-Ww~MkptLOGpXD)%L;%WXSLBWgD6gypKt)dg z7}HyHTp(FeHUle1<@EXel*}kaAf7ZP0$^-=YoEd)5nC*c zk830hxC;UcnOa;lsZhn1#k{~m0N3%DaDVo?0oWG`wF-Ri$;)F!aMh%OEf22Btf9(* zPwVS14*>(fNjCtA%Bm{n2Lh7D%^^1NOI{bp}NXvau# zPwd>0NJMK_2M^;du*68PV(uKKmzL0dJ4UL%f80RDmc{DYHPkG988If4sfKMIA@W3f z0G`tAu^Yp0Bl?Ac-*Ft;+uCTm*ndhgG5T)!pJ(ZhfGV+B(R@K2kT>5o-bQZl17`&TZ?0a0iB z@QFSyu&nH+rbUX>1DnXSHAf|ZxWXaFW5R>isR;wisy-Ypv>d0-h}0@9LoTFR6u*LB rAP)2ZS5&zmhLdrTli6+Nf1$qtX^`sw!$Mo^00000NkvXXu0mjfaFdDN delta 1353 zcmV-P1-AP73yuts)_)^OL_t(oh27X~Y*SSn$MNs~w6&`+_J~{CZOF)YSho=rd7~ms z2-(7T5Kv;k#OR1JoMEs;6Qjl$B2QaDAt7pr#DFr9$1DWGM#4J~5Vj5w0&!hOhmLJv zI@sEKe9>J*##vi+|RW1@bhEL=%TF1kE*s z4&WScT0yO$95pVNE7;dM(rZxTg&eJ3<0sBjL;^7b3d=R4=Nifye% zzY2(97@V&2a`cyzc)e$7Z1U6I)=nrK#%i$;pAb(*nj4R2G!w>;BQMv3QVPHj*xqf} zmStpQG(Qro*?)I&0irhovB6*`yY^JGW7l4;T=}!Nf1H$*q0E_8#H<;GI2dQcV8j7tO9pr#o}Gh#0+s zX|2^||Hbcs1vhTq)T`EfDF+W7erV90nKm__5h{^s3q|A968FRnxD z((Bj%qWr^8@iv_8HwAq7`>sf zvC(x`n13K^f!KqG4%44=>VDaOpoW^-BOna1TDn)=J|+;^JPjqMgTYRDec_@w2P~mVeABa6w=YOT8<&UVq0xeglt3MN&YjjNpP@?rD zfTPDwMg?W&*zpqp80a1tj0I?T3>#@*Qtyq_7m=|5N<$XF?>>JNS>S8BRX+*$L=|SU*|1nFpb46= ztA7CT3Gq>dB_zZ}8WQm+f%5>v(%sQh0U7COX7fBmR^=&x?CjCeG6CSp9tD8b@+*K+ zPzx|&{J1ExV8Zxk0Z5cb0W%H?te1%6UW z@yg7isKDmTo{ors=&JPe^iD8e6b+*SFn?yxEF?KGaX?YY$w|y8DgZDLYlYdb0Gz|J zyl8%OIAU0``0W9Om6jCah=~E%>T*4O=3g*?khU#HbM58)iA>oe zYqu)Dee4!2BO{|(M2Z2*%SsrV=XtCsPxffaN*8MYG>e}aK0I(&7=SY^b30IJw}0FD z;`5Km&B=Z&sIhq-)~@_a+wD(?*0S1_K4R;gzq!Xr{L*I7Z*+Ba>D3iq$^HX1{e~(m zm_k|UyV&h^1U9F-Gv5*s{Xp11xQnZSGJu-eBdp)}4Xv%M4-HCAPU8I~i_q*E|-#O7A3TEc=<@4D+=e~IeLwb81(1GYG#6nte`##lg zFf%@%&ta9Wd_(I=JqL%8Ks*o!bO7zZZ(8e93aJh8M6LOl`CsI31