plugin_dirs += colors
colors := brightness bluebanana C41 color3way colorbalance huesaturation \
- gamma gradient histogram threshold
+ gamma gradient histogram histogram_bezier threshold
plugin_dirs += exotic
exotic := aging burn dot holo oil edge
graphic \
greycstoration \
histogram \
+ histogram_bezier \
holo \
huesaturation \
interpolate \
include ../../global_config
OBJS = \
- $(OBJDIR)/histogram.o \
- $(OBJDIR)/histogramconfig.o \
- $(OBJDIR)/histogramwindow.o
+ $(OBJDIR)/bistogram.o \
+ $(OBJDIR)/bistogramconfig.o \
+ $(OBJDIR)/bistogramwindow.o
-PLUGIN = histogram
+PLUGIN = histogram_bezier
include ../../plugin_config
-$(OBJDIR)/histogram.o: histogram.C
-$(OBJDIR)/histogramconfig.o: histogramconfig.C
-$(OBJDIR)/histogramwindow.o: histogramwindow.C
+$(OBJDIR)/bistogram.o: bistogram.C
+$(OBJDIR)/bistogramconfig.o: bistogramconfig.C
+$(OBJDIR)/bistogramwindow.o: bistogramwindow.C
--- /dev/null
+
+/*
+ * CINELERRA
+ * Copyright (C) 2008 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 <math.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "bcdisplayinfo.h"
+#include "bcsignals.h"
+#include "clip.h"
+#include "bchash.h"
+#include "filexml.h"
+#include "bistogram.h"
+#include "bistogramconfig.h"
+#include "bistogramwindow.h"
+#include "keyframe.h"
+#include "language.h"
+#include "loadbalance.h"
+#include "cicolors.h"
+#include "vframe.h"
+
+
+
+class HistogramMain;
+class HistogramEngine;
+class HistogramWindow;
+
+REGISTER_PLUGIN(HistogramMain)
+
+HistogramMain::HistogramMain(PluginServer *server)
+ : PluginVClient(server)
+{
+
+ engine = 0;
+ for(int i = 0; i < HISTOGRAM_MODES; i++)
+ {
+ lookup[i] = 0;
+ smoothed[i] = 0;
+ linear[i] = 0;
+ accum[i] = 0;
+ }
+ current_point = -1;
+ mode = HISTOGRAM_VALUE;
+ dragging_point = 0;
+ input = 0;
+ output = 0;
+}
+
+HistogramMain::~HistogramMain()
+{
+
+ for(int i = 0; i < HISTOGRAM_MODES;i++)
+ {
+ delete [] lookup[i];
+ delete [] smoothed[i];
+ delete [] linear[i];
+ delete [] accum[i];
+ }
+ delete engine;
+}
+
+const char* HistogramMain::plugin_title() { return _("Histogram Bezier"); }
+int HistogramMain::is_realtime() { return 1; }
+
+
+NEW_WINDOW_MACRO(HistogramMain, HistogramWindow)
+LOAD_CONFIGURATION_MACRO(HistogramMain, HistogramConfig)
+
+void HistogramMain::render_gui(void *data)
+{
+ if(thread)
+ {
+ calculate_histogram((VFrame*)data);
+
+ if(config.automatic)
+ {
+ calculate_automatic((VFrame*)data);
+ }
+
+ HistogramWindow *window = (HistogramWindow *)thread->window;
+ window->lock_window("HistogramMain::render_gui");
+ window->update_canvas();
+ if(config.automatic)
+ {
+ window->update_input();
+ }
+ window->unlock_window();
+ }
+}
+
+void HistogramMain::update_gui()
+{
+ if(thread)
+ {
+ thread->window->lock_window("HistogramMain::update_gui");
+ int reconfigure = load_configuration();
+ if(reconfigure)
+ {
+ HistogramWindow *window = (HistogramWindow *)thread->window;
+ window->update(0);
+ if(!config.automatic)
+ {
+ window->update_input();
+ }
+ }
+ thread->window->unlock_window();
+ }
+}
+
+
+void HistogramMain::save_data(KeyFrame *keyframe)
+{
+ FileXML output;
+
+// cause data to be stored directly in text
+ output.set_shared_output(keyframe->get_data(), MESSAGESIZE);
+ output.tag.set_title("HISTOGRAM");
+
+ char string[BCTEXTLEN];
+
+
+ for(int i = 0; i < HISTOGRAM_MODES; i++)
+ {
+ sprintf(string, "OUTPUT_MIN_%d", i);
+ output.tag.set_property(string, config.output_min[i]);
+ sprintf(string, "OUTPUT_MAX_%d", i);
+ output.tag.set_property(string, config.output_max[i]);
+//printf("HistogramMain::save_data %d %f %d\n", config.input_min[i], config.input_mid[i], config.input_max[i]);
+ }
+
+ output.tag.set_property("AUTOMATIC", config.automatic);
+ output.tag.set_property("THRESHOLD", config.threshold);
+ output.tag.set_property("SPLIT", config.split);
+ output.tag.set_property("INTERPOLATION", config.smoothMode);
+ output.append_tag();
+ output.tag.set_title("/HISTOGRAM");
+ output.append_tag();
+ output.append_newline();
+
+
+
+
+
+ for(int j = 0; j < HISTOGRAM_MODES; j++)
+ {
+ output.tag.set_title("POINTS");
+ output.append_tag();
+ output.append_newline();
+
+
+ HistogramPoint *current = config.points[j].first;
+ while(current)
+ {
+ output.tag.set_title("POINT");
+ output.tag.set_property("X", current->x);
+ output.tag.set_property("Y", current->y);
+ output.tag.set_property("GRADIENT", current->gradient);
+ output.tag.set_property("XOFFSET_LEFT", current->xoffset_left);
+ output.tag.set_property("XOFFSET_RIGHT", current->xoffset_right);
+ output.append_tag();
+ output.tag.set_title("/POINT");
+ output.append_tag();
+ output.append_newline();
+ current = NEXT;
+ }
+
+
+ output.tag.set_title("/POINTS");
+ output.append_tag();
+ output.append_newline();
+ }
+
+
+
+
+
+
+ output.terminate_string();
+}
+
+void HistogramMain::read_data(KeyFrame *keyframe)
+{
+ FileXML input;
+
+ input.set_shared_input(keyframe->get_data(), strlen(keyframe->get_data()));
+
+ int result = 0;
+ int current_input_mode = 0;
+
+
+ while(!result)
+ {
+ result = input.read_tag();
+
+ if(!result)
+ {
+ if(input.tag.title_is("HISTOGRAM"))
+ {
+ char string[BCTEXTLEN];
+ for(int i = 0; i < HISTOGRAM_MODES; i++)
+ {
+ sprintf(string, "OUTPUT_MIN_%d", i);
+ config.output_min[i] = input.tag.get_property(string, config.output_min[i]);
+ sprintf(string, "OUTPUT_MAX_%d", i);
+ config.output_max[i] = input.tag.get_property(string, config.output_max[i]);
+//printf("HistogramMain::read_data %d %f %d\n", config.input_min[i], config.input_mid[i], config.input_max[i]);
+ }
+ config.automatic = input.tag.get_property("AUTOMATIC", config.automatic);
+ config.threshold = input.tag.get_property("THRESHOLD", config.threshold);
+ config.split = input.tag.get_property("SPLIT", config.split);
+ config.smoothMode = input.tag.get_property("INTERPOLATION", config.smoothMode);
+ }
+ else
+ if(input.tag.title_is("POINTS"))
+ {
+ if(current_input_mode < HISTOGRAM_MODES)
+ {
+ HistogramPoints *points = &config.points[current_input_mode];
+ while(points->last)
+ delete points->last;
+ while(!result)
+ {
+ result = input.read_tag();
+ if(!result)
+ {
+ if(input.tag.title_is("/POINTS"))
+ {
+ break;
+ }
+ else
+ if(input.tag.title_is("POINT"))
+ {
+ points->insert(
+ input.tag.get_property("X", 0.0),
+ input.tag.get_property("Y", 0.0));
+ points->last->gradient =
+ input.tag.get_property("GRADIENT", 1.0);
+ points->last->xoffset_left =
+ input.tag.get_property("XOFFSET_LEFT", -0.02);
+ points->last->xoffset_right =
+ input.tag.get_property("XOFFSET_RIGHT", 0.02);
+ }
+ }
+ }
+
+ }
+ current_input_mode++;
+ }
+ }
+ }
+
+ config.boundaries();
+
+}
+
+float HistogramMain::calculate_linear(float input,
+ int subscript,
+ int use_value)
+{
+ int done = 0;
+ float output;
+
+ if(input < 0) {
+ output = 0;
+ done = 1;
+ }
+
+ if(input > 1) {
+ output = 1;
+ done = 1;
+ }
+
+ if(!done) {
+
+ float x1 = 0, y1 = 0;
+ float grad1 = 1.0;
+ float x1right = 0;
+ float x2 = 1, y2 = 1;
+ float grad2 = 1.0;
+ float x2left = 0;
+
+// Get 2 points surrounding current position
+ HistogramPoints *points = &config.points[subscript];
+ HistogramPoint *current = points->first;
+ int done = 0;
+ while(current && !done) {
+ if(current->x > input) {
+ x2 = current->x;
+ y2 = current->y;
+ grad2 = current->gradient;
+ x2left = current->xoffset_left;
+ done = 1;
+ }
+ else
+ current = NEXT;
+ }
+
+ current = points->last;
+ done = 0;
+ while(current && !done) {
+ if(current->x <= input) {
+ x1 = current->x;
+ y1 = current->y;
+ grad1 = current->gradient;
+ done = 1;
+ x1right = current->xoffset_right;
+ }
+ else
+ current = PREVIOUS;
+ }
+
+
+
+
+ if(!EQUIV(x2 - x1, 0))
+ {
+ if (config.smoothMode == HISTOGRAM_LINEAR)
+ output = (input - x1) * (y2 - y1) / (x2 - x1) + y1;
+ else if (config.smoothMode == HISTOGRAM_POLYNOMINAL)
+ {
+ /* Construct third grade polynom between every two points */
+ float dx = x2 - x1;
+ float dy = y2 - y1;
+ float delx = input - x1;
+ output = (grad2 * dx + grad1 * dx - 2*dy) / (dx * dx * dx) * delx * delx * delx +
+ (dx * dx) * (3*dy - 2* grad1*dx - grad2*dx) / (dx * dx) * delx * delx + grad1*delx + y1;
+ }
+ else if (config.smoothMode == HISTOGRAM_BEZIER)
+ {
+ /* Using standart DeCasteljau algorithm */
+ float y1right = y1 + grad1 * x1right;
+ float y2left = y2 + grad2 * x2left;
+
+ float t = (input - x1) / (x2 - x1);
+
+ float pointAy = y1 + (y1right - y1) * t;
+ float pointBy = y1right + (y2left - y1right) * t;
+ float pointCy = y2left + (y2 - y2left) * t;
+ float pointABy = pointAy + (pointBy - pointAy) * t;
+ float pointBCy = pointBy + (pointCy - pointBy) * t;
+ output = pointABy + (pointBCy - pointABy) * t;
+ }
+ }
+ else
+// Linear
+ output = input * y2;
+ }
+
+// Apply value curve
+ if(use_value) {
+ output = calculate_linear(output, HISTOGRAM_VALUE, 0);
+ }
+
+
+ float output_min = config.output_min[subscript];
+ float output_max = config.output_max[subscript];
+
+// Compress output for value followed by channel
+ output = output_min + output * (output_max - output_min);
+ return output;
+}
+
+float HistogramMain::calculate_smooth(float input, int subscript)
+{
+ float x_f = (input - HIST_MIN_INPUT) * HISTOGRAM_SLOTS / FLOAT_RANGE;
+ int x_i1 = (int)x_f;
+ int x_i2 = x_i1 + 1;
+ CLAMP(x_i1, 0, HISTOGRAM_SLOTS-1);
+ CLAMP(x_i2, 0, HISTOGRAM_SLOTS-1);
+ CLAMP(x_f, 0, HISTOGRAM_SLOTS-1);
+
+ float smooth1 = smoothed[subscript][x_i1];
+ float smooth2 = smoothed[subscript][x_i2];
+ float result = smooth1 + (smooth2 - smooth1) * (x_f - x_i1);
+ CLAMP(result, 0, 1.0);
+ return result;
+}
+
+
+void HistogramMain::calculate_histogram(VFrame *data)
+{
+
+ if(!engine) engine = new HistogramEngine(this,
+ get_project_smp() + 1,
+ get_project_smp() + 1);
+
+ if(!accum[0])
+ {
+ for(int i = 0; i < HISTOGRAM_MODES; i++)
+ accum[i] = new int[HISTOGRAM_SLOTS];
+ }
+ engine->process_packages(HistogramEngine::HISTOGRAM, data);
+
+ for(int i = 0; i < engine->get_total_clients(); i++) {
+ HistogramUnit *unit = (HistogramUnit*)engine->get_client(i);
+ if(i == 0) {
+ for(int j = 0; j < HISTOGRAM_MODES; j++)
+ memcpy(accum[j], unit->accum[j], sizeof(int) * HISTOGRAM_SLOTS);
+ }
+ else {
+ for(int j = 0; j < HISTOGRAM_MODES; j++) {
+ int *out = accum[j];
+ int *in = unit->accum[j];
+ for(int k = 0; k < HISTOGRAM_SLOTS; k++)
+ out[k] += in[k];
+ }
+ }
+ }
+
+// Remove top and bottom from calculations. Doesn't work in high
+// precision colormodels.
+ for(int i = 0; i < HISTOGRAM_MODES; i++) {
+ accum[i][0] = 0;
+ accum[i][HISTOGRAM_SLOTS - 1] = 0;
+ }
+}
+
+
+void HistogramMain::calculate_automatic(VFrame *data)
+{
+ calculate_histogram(data);
+ config.reset_points();
+
+// Do each channel
+ for(int i = 0; i < 3; i++) {
+ int *accum = this->accum[i];
+ int pixels = data->get_w() * data->get_h();
+ float white_fraction = 1.0 - (1.0 - config.threshold) / 2;
+ int threshold = (int)(white_fraction * pixels);
+ int total = 0;
+ float max_level = 1.0;
+ float min_level = 0.0;
+
+// Get histogram slot above threshold of pixels
+ for(int j = 0; j < HISTOGRAM_SLOTS; j++) {
+ total += accum[j];
+ if(total >= threshold) {
+ max_level = (float)j / HISTOGRAM_SLOTS * FLOAT_RANGE + HIST_MIN_INPUT;
+ break;
+ }
+ }
+
+// Get slot below 99% of pixels
+ total = 0;
+ for(int j = HISTOGRAM_SLOTS - 1; j >= 0; j--) {
+ total += accum[j];
+ if(total >= threshold) {
+ min_level = (float)j / HISTOGRAM_SLOTS * FLOAT_RANGE + HIST_MIN_INPUT;
+ break;
+ }
+ }
+ config.points[i].insert(max_level, 1.0);
+ config.points[i].insert(min_level, 0.0);
+ }
+}
+
+int HistogramMain::process_realtime(VFrame *input_ptr, VFrame *output_ptr)
+{
+SET_TRACE
+ int need_reconfigure = load_configuration();
+SET_TRACE
+
+ if(!engine) engine = new HistogramEngine(this,
+ get_project_smp() + 1,
+ get_project_smp() + 1);
+ this->input = input_ptr;
+ this->output = output_ptr;
+
+ send_render_gui(input_ptr);
+
+ if(input_ptr->get_rows()[0] != output_ptr->get_rows()[0])
+ {
+ output_ptr->copy_from(input_ptr);
+ }
+
+SET_TRACE
+// Generate tables here. The same table is used by many packages to render
+// each horizontal stripe. Need to cover the entire output range in each
+// table to avoid green borders
+ if( !lookup[0] || !smoothed[0] || !linear[0] || config.automatic)
+ need_reconfigure = 1;
+ if( need_reconfigure ) {
+SET_TRACE
+// Calculate new curves
+ if(config.automatic) {
+ calculate_automatic(input);
+ }
+SET_TRACE
+
+// Generate transfer tables for integer colormodels.
+ for(int i = 0; i < 3; i++)
+ tabulate_curve(i, 1);
+SET_TRACE
+ }
+
+// Apply histogram
+ engine->process_packages(HistogramEngine::APPLY, input);
+
+SET_TRACE
+ return 0;
+}
+
+void HistogramMain::tabulate_curve(int subscript, int use_value)
+{
+ int i;
+ if(!lookup[subscript])
+ lookup[subscript] = new int[HISTOGRAM_SLOTS];
+ if(!smoothed[subscript])
+ smoothed[subscript] = new float[HISTOGRAM_SLOTS];
+ if(!linear[subscript])
+ linear[subscript] = new float[HISTOGRAM_SLOTS];
+
+ float *current_smooth = smoothed[subscript];
+ float *current_linear = linear[subscript];
+
+// Make linear curve
+ for(i = 0; i < HISTOGRAM_SLOTS; i++) {
+ float input = (float)i / HISTOGRAM_SLOTS * FLOAT_RANGE + HIST_MIN_INPUT;
+ current_linear[i] = calculate_linear(input, subscript, use_value);
+ }
+// Make smooth curve
+ //float prev = 0.0;
+ for(i = 0; i < HISTOGRAM_SLOTS; i++)
+ {
+// current_smooth[i] = current_linear[i] * 0.001 +
+// prev * 0.999;
+ current_smooth[i] = current_linear[i];
+// prev = current_smooth[i];
+ }
+// Generate lookup tables for integer colormodels
+ if(input)
+ {
+ switch(input->get_color_model())
+ {
+ case BC_RGB888:
+ case BC_RGBA8888:
+ for(i = 0; i < 0x100; i++)
+ lookup[subscript][i] =
+ (int)(calculate_smooth((float)i / 0xff, subscript) * 0xff);
+ break;
+// All other integer colormodels are converted to 16 bit RGB
+ default:
+ for(i = 0; i < 0x10000; i++)
+ lookup[subscript][i] =
+ (int)(calculate_smooth((float)i / 0xffff, subscript) * 0xffff);
+ break;
+ }
+ }
+}
+
+HistogramPackage::HistogramPackage()
+ : LoadPackage()
+{
+}
+
+HistogramUnit::HistogramUnit(HistogramEngine *server,
+ HistogramMain *plugin)
+ : LoadClient(server)
+{
+ this->plugin = plugin;
+ this->server = server;
+ for(int i = 0; i < HISTOGRAM_MODES; i++)
+ accum[i] = new int[HISTOGRAM_SLOTS];
+}
+
+HistogramUnit::~HistogramUnit()
+{
+ for(int i = 0; i < HISTOGRAM_MODES; i++)
+ delete [] accum[i];
+}
+
+void HistogramUnit::process_package(LoadPackage *package)
+{
+ HistogramPackage *pkg = (HistogramPackage*)package;
+
+ if(server->operation == HistogramEngine::HISTOGRAM)
+ {
+
+#define HISTOGRAM_HEAD(type) \
+{ \
+ for(int i = pkg->start; i < pkg->end; i++) \
+ { \
+ type *row = (type*)data->get_rows()[i]; \
+ for(int j = 0; j < w; j++) \
+ {
+
+#define HISTOGRAM_TAIL(components) \
+/* v = (r * 76 + g * 150 + b * 29) >> 8; */ \
+ v = MAX(r, g); \
+ v = MAX(v, b); \
+ r += -HISTOGRAM_MIN * 0xffff / 100; \
+ g += -HISTOGRAM_MIN * 0xffff / 100; \
+ b += -HISTOGRAM_MIN * 0xffff / 100; \
+ v += -HISTOGRAM_MIN * 0xffff / 100; \
+ CLAMP(r, 0, HISTOGRAM_SLOTS-1); \
+ CLAMP(g, 0, HISTOGRAM_SLOTS-1); \
+ CLAMP(b, 0, HISTOGRAM_SLOTS-1); \
+ CLAMP(v, 0, HISTOGRAM_SLOTS-1); \
+ accum_r[r]++; \
+ accum_g[g]++; \
+ accum_b[b]++; \
+ accum_v[v]++; \
+ row += components; \
+ } \
+ } \
+}
+
+ VFrame *data = server->data;
+ int w = data->get_w();
+// int h = data->get_h();
+ int *accum_r = accum[HISTOGRAM_RED];
+ int *accum_g = accum[HISTOGRAM_GREEN];
+ int *accum_b = accum[HISTOGRAM_BLUE];
+ int *accum_v = accum[HISTOGRAM_VALUE];
+ int r, g, b, y, u, v;
+
+ switch(data->get_color_model())
+ {
+ case BC_RGB888:
+ HISTOGRAM_HEAD(unsigned char)
+ r = (row[0] << 8) | row[0];
+ g = (row[1] << 8) | row[1];
+ b = (row[2] << 8) | row[2];
+ HISTOGRAM_TAIL(3)
+ break;
+ case BC_RGB_FLOAT:
+ HISTOGRAM_HEAD(float)
+ r = (int)(row[0] * 0xffff);
+ g = (int)(row[1] * 0xffff);
+ b = (int)(row[2] * 0xffff);
+ HISTOGRAM_TAIL(3)
+ break;
+ case BC_YUV888:
+ HISTOGRAM_HEAD(unsigned char)
+ y = (row[0] << 8) | row[0];
+ u = (row[1] << 8) | row[1];
+ v = (row[2] << 8) | row[2];
+ plugin->yuv.yuv_to_rgb_16(r, g, b, y, u, v);
+ HISTOGRAM_TAIL(3)
+ break;
+ case BC_RGBA8888:
+ HISTOGRAM_HEAD(unsigned char)
+ r = (row[0] << 8) | row[0];
+ g = (row[1] << 8) | row[1];
+ b = (row[2] << 8) | row[2];
+ HISTOGRAM_TAIL(4)
+ break;
+ case BC_RGBA_FLOAT:
+ HISTOGRAM_HEAD(float)
+ r = (int)(row[0] * 0xffff);
+ g = (int)(row[1] * 0xffff);
+ b = (int)(row[2] * 0xffff);
+ HISTOGRAM_TAIL(4)
+ break;
+ case BC_YUVA8888:
+ HISTOGRAM_HEAD(unsigned char)
+ y = (row[0] << 8) | row[0];
+ u = (row[1] << 8) | row[1];
+ v = (row[2] << 8) | row[2];
+ plugin->yuv.yuv_to_rgb_16(r, g, b, y, u, v);
+ HISTOGRAM_TAIL(4)
+ break;
+ case BC_RGB161616:
+ HISTOGRAM_HEAD(uint16_t)
+ r = row[0];
+ g = row[1];
+ b = row[2];
+ HISTOGRAM_TAIL(3)
+ break;
+ case BC_YUV161616:
+ HISTOGRAM_HEAD(uint16_t)
+ y = row[0];
+ u = row[1];
+ v = row[2];
+ plugin->yuv.yuv_to_rgb_16(r, g, b, y, u, v);
+ HISTOGRAM_TAIL(3)
+ break;
+ case BC_RGBA16161616:
+ HISTOGRAM_HEAD(uint16_t)
+ r = row[0];
+ g = row[1];
+ b = row[2];
+ HISTOGRAM_TAIL(3)
+ break;
+ case BC_YUVA16161616:
+ HISTOGRAM_HEAD(uint16_t)
+ y = row[0];
+ u = row[1];
+ v = row[2];
+ plugin->yuv.yuv_to_rgb_16(r, g, b, y, u, v);
+ HISTOGRAM_TAIL(4)
+ break;
+ }
+ }
+ else
+ if(server->operation == HistogramEngine::APPLY)
+ {
+
+
+
+#define PROCESS(type, components) \
+{ \
+ for(int i = pkg->start; i < pkg->end; i++) \
+ { \
+ type *row = (type*)input->get_rows()[i]; \
+ for(int j = 0; j < w; j++) \
+ { \
+ if ( plugin->config.split && ((j + i * w / h) < w) ) \
+ continue; \
+ row[0] = lookup_r[row[0]]; \
+ row[1] = lookup_g[row[1]]; \
+ row[2] = lookup_b[row[2]]; \
+ row += components; \
+ } \
+ } \
+}
+
+#define PROCESS_YUV(type, components, max) \
+{ \
+ for(int i = pkg->start; i < pkg->end; i++) \
+ { \
+ type *row = (type*)input->get_rows()[i]; \
+ for(int j = 0; j < w; j++) \
+ { \
+ if ( plugin->config.split && ((j + i * w / h) < w) ) \
+ continue; \
+/* Convert to 16 bit RGB */ \
+ if(max == 0xff) \
+ { \
+ y = (row[0] << 8) | row[0]; \
+ u = (row[1] << 8) | row[1]; \
+ v = (row[2] << 8) | row[2]; \
+ } \
+ else \
+ { \
+ y = row[0]; \
+ u = row[1]; \
+ v = row[2]; \
+ } \
+ \
+ plugin->yuv.yuv_to_rgb_16(r, g, b, y, u, v); \
+ \
+/* Look up in RGB domain */ \
+ r = lookup_r[r]; \
+ g = lookup_g[g]; \
+ b = lookup_b[b]; \
+ \
+/* Convert to 16 bit YUV */ \
+ plugin->yuv.rgb_to_yuv_16(r, g, b, y, u, v); \
+ \
+ if(max == 0xff) \
+ { \
+ row[0] = y >> 8; \
+ row[1] = u >> 8; \
+ row[2] = v >> 8; \
+ } \
+ else \
+ { \
+ row[0] = y; \
+ row[1] = u; \
+ row[2] = v; \
+ } \
+ row += components; \
+ } \
+ } \
+}
+
+#define PROCESS_FLOAT(components) \
+{ \
+ for(int i = pkg->start; i < pkg->end; i++) \
+ { \
+ float *row = (float*)input->get_rows()[i]; \
+ for(int j = 0; j < w; j++) \
+ { \
+ if ( plugin->config.split && ((j + i * w / h) < w) ) \
+ continue; \
+ float r = row[0]; \
+ float g = row[1]; \
+ float b = row[2]; \
+ \
+ r = plugin->calculate_smooth(r, HISTOGRAM_RED); \
+ g = plugin->calculate_smooth(g, HISTOGRAM_GREEN); \
+ b = plugin->calculate_smooth(b, HISTOGRAM_BLUE); \
+ \
+ row[0] = r; \
+ row[1] = g; \
+ row[2] = b; \
+ \
+ row += components; \
+ } \
+ } \
+}
+
+
+ VFrame *input = plugin->input;
+// VFrame *output = plugin->output;
+ int w = input->get_w(), h = input->get_h();
+ int *lookup_r = plugin->lookup[0];
+ int *lookup_g = plugin->lookup[1];
+ int *lookup_b = plugin->lookup[2];
+ int r, g, b, y, u, v;
+ switch(input->get_color_model())
+ {
+ case BC_RGB888:
+ PROCESS(unsigned char, 3)
+ break;
+ case BC_RGB_FLOAT:
+ PROCESS_FLOAT(3);
+ break;
+ case BC_RGBA8888:
+ PROCESS(unsigned char, 4)
+ break;
+ case BC_RGBA_FLOAT:
+ PROCESS_FLOAT(4);
+ break;
+ case BC_RGB161616:
+ PROCESS(uint16_t, 3)
+ break;
+ case BC_RGBA16161616:
+ PROCESS(uint16_t, 4)
+ break;
+ case BC_YUV888:
+ PROCESS_YUV(unsigned char, 3, 0xff)
+ break;
+ case BC_YUVA8888:
+ PROCESS_YUV(unsigned char, 4, 0xff)
+ break;
+ case BC_YUV161616:
+ PROCESS_YUV(uint16_t, 3, 0xffff)
+ break;
+ case BC_YUVA16161616:
+ PROCESS_YUV(uint16_t, 4, 0xffff)
+ break;
+ }
+ }
+}
+
+
+
+
+
+
+HistogramEngine::HistogramEngine(HistogramMain *plugin,
+ int total_clients,
+ int total_packages)
+ : LoadServer(total_clients, total_packages)
+{
+ this->plugin = plugin;
+}
+
+void HistogramEngine::init_packages()
+{
+ switch(operation) {
+ case HISTOGRAM:
+ total_size = data->get_h();
+ break;
+ case APPLY:
+ total_size = data->get_h();
+ break;
+ }
+
+ for(int i = 0; i < get_total_packages(); i++) {
+ HistogramPackage *package = (HistogramPackage*)get_package(i);
+ package->start = total_size * i / get_total_packages();
+ package->end = total_size * (i + 1) / get_total_packages();
+ }
+
+// Initialize clients here in case some don't get run.
+ for(int i = 0; i < get_total_clients(); i++) {
+ HistogramUnit *unit = (HistogramUnit*)get_client(i);
+ for(int i = 0; i < HISTOGRAM_MODES; i++)
+ bzero(unit->accum[i], sizeof(int) * HISTOGRAM_SLOTS);
+ }
+
+}
+
+LoadClient* HistogramEngine::new_client()
+{
+ return new HistogramUnit(this, plugin);
+}
+
+LoadPackage* HistogramEngine::new_package()
+{
+ return new HistogramPackage;
+}
+
+void HistogramEngine::process_packages(int operation, VFrame *data)
+{
+ this->data = data;
+ this->operation = operation;
+ LoadServer::process_packages();
+}
+
+
+
--- /dev/null
+
+/*
+ * CINELERRA
+ * Copyright (C) 2008 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 HISTOGRAM_H
+#define HISTOGRAM_H
+
+
+#include "bistogram.inc"
+#include "bistogramconfig.h"
+#include "bistogramwindow.inc"
+#include "loadbalance.h"
+#include "cicolors.h"
+#include "pluginvclient.h"
+
+
+enum
+{
+ HISTOGRAM_LINEAR,
+ HISTOGRAM_POLYNOMINAL,
+ HISTOGRAM_BEZIER,
+};
+
+
+class HistogramMain : public PluginVClient
+{
+public:
+ HistogramMain(PluginServer *server);
+ ~HistogramMain();
+
+ int process_realtime(VFrame *input_ptr, VFrame *output_ptr);
+ int is_realtime();
+ void save_data(KeyFrame *keyframe);
+ void read_data(KeyFrame *keyframe);
+ void update_gui();
+ void render_gui(void *data);
+
+ PLUGIN_CLASS_MEMBERS(HistogramConfig)
+
+// Convert input to linear output
+ float calculate_linear(float input, int mode, int do_value);
+ float calculate_smooth(float input, int subscript);
+// Convert input to smoothed output by looking up in smooth table.
+ float calculate_curve(float input);
+// Calculate automatic settings
+ void calculate_automatic(VFrame *data);
+// Calculate histogram
+ void calculate_histogram(VFrame *data);
+// Calculate the linear, smoothed, lookup curves
+ void tabulate_curve(int subscript, int use_value);
+
+
+
+ YUV yuv;
+ VFrame *input, *output;
+ HistogramEngine *engine;
+ int *lookup[HISTOGRAM_MODES];
+ float *smoothed[HISTOGRAM_MODES];
+ float *linear[HISTOGRAM_MODES];
+ int *accum[HISTOGRAM_MODES];
+// Input point being dragged or edited
+ int current_point;
+// Current channel being viewed
+ int mode;
+ int dragging_point;
+ int point_x_offset;
+ int point_y_offset;
+};
+
+class HistogramPackage : public LoadPackage
+{
+public:
+ HistogramPackage();
+ int start, end;
+};
+
+class HistogramUnit : public LoadClient
+{
+public:
+ HistogramUnit(HistogramEngine *server, HistogramMain *plugin);
+ ~HistogramUnit();
+ void process_package(LoadPackage *package);
+ HistogramEngine *server;
+ HistogramMain *plugin;
+ int *accum[5];
+};
+
+class HistogramEngine : public LoadServer
+{
+public:
+ HistogramEngine(HistogramMain *plugin,
+ int total_clients,
+ int total_packages);
+ void process_packages(int operation, VFrame *data);
+ void init_packages();
+ LoadClient* new_client();
+ LoadPackage* new_package();
+ HistogramMain *plugin;
+ int total_size;
+
+
+ int operation;
+ enum
+ {
+ HISTOGRAM,
+ APPLY
+ };
+ VFrame *data;
+};
+
+
+
+
+
+
+
+
+
+
+
+#endif
--- /dev/null
+
+/*
+ * CINELERRA
+ * Copyright (C) 2008 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 HISTOGRAM_INC
+#define HISTOGRAM_INC
+
+
+
+
+
+// modes
+#define HISTOGRAM_MODES 4
+#define HISTOGRAM_RED 0
+#define HISTOGRAM_GREEN 1
+#define HISTOGRAM_BLUE 2
+#define HISTOGRAM_VALUE 3
+
+// Number of divisions in histogram.
+// 65536 + min and max range to speed up the tabulation
+#define HISTOGRAM_SLOTS 0x13333
+#define FLOAT_RANGE 1.2
+// Minimum value in percentage
+#define HISTOGRAM_MIN -10
+#define HIST_MIN_INPUT -0.1
+// Maximum value in percentage
+#define HISTOGRAM_MAX 110
+#define HIST_MAX_INPUT 1.1
+
+#define PRECISION 0.001
+#define DIGITS 3
+#define THRESHOLD_SCALE 1000
+
+#define BOX_SIZE 10
+
+
+class HistogramEngine;
+class HistogramMain;
+
+
+#endif
--- /dev/null
+
+/*
+ * CINELERRA
+ * Copyright (C) 2008 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 "bistogramconfig.h"
+#include "units.h"
+
+#include <math.h>
+
+
+
+
+HistogramPoint::HistogramPoint()
+ : ListItem<HistogramPoint>()
+{
+}
+
+HistogramPoint::~HistogramPoint()
+{
+}
+
+int HistogramPoint::equivalent(HistogramPoint *src)
+{
+ return EQUIV(x, src->x) && EQUIV(y, src->y) && EQUIV(gradient, src->gradient);
+}
+
+
+
+
+HistogramPoints::HistogramPoints()
+ : List<HistogramPoint>()
+{
+ insert(0.0,0.0);
+ first->gradient = 1.0;
+ first->xoffset_left = 0.0;
+ first->xoffset_right = 0.05;
+ insert(1.0,1.0);
+ last->gradient = 1.0;
+ last->xoffset_left = -0.05;
+ last->xoffset_right = 0.0;
+
+}
+
+HistogramPoints::~HistogramPoints()
+{
+}
+
+HistogramPoint* HistogramPoints::insert(float x, float y)
+{
+ HistogramPoint *current = first;
+
+// Get existing point after new point
+ while(current)
+ {
+ if(current->x > x)
+ break;
+ else
+ current = NEXT;
+ }
+
+// Insert new point before current point
+ HistogramPoint *new_point = new HistogramPoint;
+ if(current)
+ {
+ insert_before(current, new_point);
+ }
+ else
+// Append new point to list
+ {
+ append(new_point);
+ }
+
+ new_point->x = x;
+ new_point->y = y;
+ new_point->xoffset_left = -0.05;
+ new_point->xoffset_right = 0.05;
+
+
+ return new_point;
+}
+
+void HistogramPoints::boundaries()
+{
+ HistogramPoint *current = first;
+ while(current)
+ {
+ CLAMP(current->x, 0.0, 1.0);
+ CLAMP(current->y, 0.0, 1.0);
+ current = NEXT;
+ }
+}
+
+int HistogramPoints::equivalent(HistogramPoints *src)
+{
+ HistogramPoint *current_this = first;
+ HistogramPoint *current_src = src->first;
+ while(current_this && current_src)
+ {
+ if(!current_this->equivalent(current_src)) return 0;
+ current_this = current_this->next;
+ current_src = current_src->next;
+ }
+
+ return !current_this ^ !current_src ? 0 : 1;
+}
+
+void HistogramPoints::copy_from(HistogramPoints *src)
+{
+ while(last)
+ delete last;
+ HistogramPoint *current = src->first;
+ while(current)
+ {
+ HistogramPoint *new_point = new HistogramPoint;
+ new_point->x = current->x;
+ new_point->y = current->y;
+ append(new_point);
+ current = NEXT;
+ }
+}
+
+void HistogramPoints::interpolate(HistogramPoints *prev,
+ HistogramPoints *next,
+ double prev_scale,
+ double next_scale)
+{
+ HistogramPoint *current = first;
+ HistogramPoint *current_prev = prev->first;
+ HistogramPoint *current_next = next->first;
+
+ while(current && current_prev && current_next)
+ {
+ current->x = current_prev->x * prev_scale +
+ current_next->x * next_scale;
+ current->y = current_prev->y * prev_scale +
+ current_next->y * next_scale;
+ current = NEXT;
+ current_prev = current_prev->next;
+ current_next = current_next->next;
+ }
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+HistogramConfig::HistogramConfig()
+{
+ reset(1);
+}
+
+void HistogramConfig::reset(int do_mode)
+{
+ reset_points();
+
+
+ for(int i = 0; i < HISTOGRAM_MODES; i++)
+ {
+ output_min[i] = 0.0;
+ output_max[i] = 1.0;
+ }
+
+ if(do_mode)
+ {
+ automatic = 0;
+ threshold = 0.1;
+ split = 0;
+ smoothMode = 0;
+ }
+}
+
+void HistogramConfig::reset_points()
+{
+ for(int i = 0; i < HISTOGRAM_MODES; i++)
+ {
+ while(points[i].last) delete points[i].last;
+ points[i].insert(0.0,0.0);
+ points[i].last->gradient = 1.0;
+ points[i].insert(1.0,1.0);
+ points[i].last->gradient = 1.0;
+ }
+}
+
+
+void HistogramConfig::boundaries()
+{
+ for(int i = 0; i < HISTOGRAM_MODES; i++)
+ {
+ points[i].boundaries();
+ CLAMP(output_min[i], HIST_MIN_INPUT, HIST_MAX_INPUT);
+ CLAMP(output_max[i], HIST_MIN_INPUT, HIST_MAX_INPUT);
+ output_min[i] = Units::quantize(output_min[i], PRECISION);
+ output_max[i] = Units::quantize(output_max[i], PRECISION);
+ }
+ CLAMP(threshold, 0, 1);
+}
+
+int HistogramConfig::equivalent(HistogramConfig &that)
+{
+ for(int i = 0; i < HISTOGRAM_MODES; i++)
+ {
+ if(!points[i].equivalent(&that.points[i]) ||
+ !EQUIV(output_min[i], that.output_min[i]) ||
+ !EQUIV(output_max[i], that.output_max[i])) return 0;
+ }
+
+ if(automatic != that.automatic ||
+ !EQUIV(threshold, that.threshold)) return 0;
+
+ return 1;
+}
+
+void HistogramConfig::copy_from(HistogramConfig &that)
+{
+ for(int i = 0; i < HISTOGRAM_MODES; i++)
+ {
+ points[i].copy_from(&that.points[i]);
+ output_min[i] = that.output_min[i];
+ output_max[i] = that.output_max[i];
+ }
+
+ automatic = that.automatic;
+ threshold = that.threshold;
+ split = that.split;
+ smoothMode = that.smoothMode;
+}
+
+void HistogramConfig::interpolate(HistogramConfig &prev,
+ HistogramConfig &next,
+ int64_t prev_frame,
+ int64_t next_frame,
+ int64_t current_frame)
+{
+ double next_scale = (double)(current_frame - prev_frame) / (next_frame - prev_frame);
+ double prev_scale = 1.0 - next_scale;
+
+ for(int i = 0; i < HISTOGRAM_MODES; i++)
+ {
+ points[i].interpolate(&prev.points[i], &next.points[i], next_scale, prev_scale);
+ output_min[i] = prev.output_min[i] * prev_scale + next.output_min[i] * next_scale;
+ output_max[i] = prev.output_max[i] * prev_scale + next.output_max[i] * next_scale;
+ }
+
+ threshold = prev.threshold * prev_scale + next.threshold * next_scale;
+ automatic = prev.automatic;
+ split = prev.split;
+ smoothMode = prev.smoothMode;
+}
+
+
+void HistogramConfig::dump()
+{
+ for(int j = 0; j < HISTOGRAM_MODES; j++)
+ {
+ printf("HistogramConfig::dump mode=%d\n", j);
+ HistogramPoints *points = &this->points[j];
+ HistogramPoint *current = points->first;
+ while(current)
+ {
+ printf("%f,%f ", current->x, current->y);
+ fflush(stdout);
+ current = NEXT;
+ }
+ printf("\n");
+ }
+}
+
+
+
--- /dev/null
+
+/*
+ * CINELERRA
+ * Copyright (C) 2008 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 HISTOGRAMCONFIG_H
+#define HISTOGRAMCONFIG_H
+
+
+#include "bistogram.inc"
+#include "bistogramconfig.inc"
+#include "linklist.h"
+#include <stdint.h>
+
+class HistogramPoint : public ListItem<HistogramPoint>
+{
+public:
+ HistogramPoint();
+ ~HistogramPoint();
+
+ int equivalent(HistogramPoint *src);
+ float x, y;
+ float gradient;
+ float xoffset_left;
+ float xoffset_right;
+};
+
+
+class HistogramPoints : public List<HistogramPoint>
+{
+public:
+ HistogramPoints();
+ ~HistogramPoints();
+
+// Insert new point
+ HistogramPoint* insert(float x, float y);
+ int equivalent(HistogramPoints *src);
+ void boundaries();
+ void copy_from(HistogramPoints *src);
+ void interpolate(HistogramPoints *prev,
+ HistogramPoints *next,
+ double prev_scale,
+ double next_scale);
+};
+
+class HistogramConfig
+{
+public:
+ HistogramConfig();
+
+ int equivalent(HistogramConfig &that);
+ void copy_from(HistogramConfig &that);
+ void interpolate(HistogramConfig &prev,
+ HistogramConfig &next,
+ int64_t prev_frame,
+ int64_t next_frame,
+ int64_t current_frame);
+// Used by constructor and reset button
+ void reset(int do_mode);
+ void reset_points();
+ void boundaries();
+ void dump();
+
+// Range 0 - 1.0
+// Input points
+ HistogramPoints points[HISTOGRAM_MODES];
+// Output points
+ float output_min[HISTOGRAM_MODES];
+ float output_max[HISTOGRAM_MODES];
+ int automatic;
+ float threshold;
+ int split;
+ int smoothMode;
+};
+
+
+#endif
+
+
+
--- /dev/null
+
+/*
+ * CINELERRA
+ * Copyright (C) 2008 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 HISTOGRAMCONFIG_INC
+#define HISTOGRAMCONFIG_INC
+
+
+class HistogramPoint;
+class HistogramPoints;
+class HistogramConfig;
+
+
+#endif
--- /dev/null
+
+/*
+ * CINELERRA
+ * Copyright (C) 2008 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 "bcsignals.h"
+#include "bistogram.h"
+#include "bistogramconfig.h"
+#include "bistogramwindow.h"
+#include "keys.h"
+#include "language.h"
+
+
+#include <unistd.h>
+#include <string.h>
+
+HistogramWindow::HistogramWindow(HistogramMain *plugin)
+ : PluginClientWindow(plugin, 440, 480, 440, 480, 0)
+{
+ this->plugin = plugin;
+}
+
+HistogramWindow::~HistogramWindow()
+{
+}
+
+#include "min_picon_png.h"
+#include "mid_picon_png.h"
+#include "max_picon_png.h"
+static VFramePng max_picon_image(max_picon_png);
+static VFramePng mid_picon_image(mid_picon_png);
+static VFramePng min_picon_image(min_picon_png);
+
+void HistogramWindow::create_objects()
+{
+ int x = 10, y = 10, x1 = 10;
+ BC_Title *title = 0;
+
+ max_picon = create_pixmap(&max_picon_image);
+ mid_picon = create_pixmap(&mid_picon_image);
+ min_picon = create_pixmap(&min_picon_image);
+ add_subwindow(mode_v = new HistogramMode(plugin,
+ x,
+ y,
+ HISTOGRAM_VALUE,
+ _("Value")));
+ x += 70;
+ add_subwindow(mode_r = new HistogramMode(plugin,
+ x,
+ y,
+ HISTOGRAM_RED,
+ _("Red")));
+ x += 70;
+ add_subwindow(mode_g = new HistogramMode(plugin,
+ x,
+ y,
+ HISTOGRAM_GREEN,
+ _("Green")));
+ x += 70;
+ add_subwindow(mode_b = new HistogramMode(plugin,
+ x,
+ y,
+ HISTOGRAM_BLUE,
+ _("Blue")));
+// x += 70;
+// add_subwindow(mode_a = new HistogramMode(plugin,
+// x,
+// y,
+// HISTOGRAM_ALPHA,
+// _("Alpha")));
+
+ x = x1;
+ y += 30;
+ add_subwindow(title = new BC_Title(x, y, _("Input X:")));
+ x += title->get_w() + 10;
+ input_x = new HistogramInputText(plugin,
+ this,
+ x,
+ y,
+ 1);
+ input_x->create_objects();
+
+ x += input_x->get_w() + 10;
+ add_subwindow(title = new BC_Title(x, y, _("Input Y:")));
+ x += title->get_w() + 10;
+ input_y = new HistogramInputText(plugin,
+ this,
+ x,
+ y,
+ 0);
+ input_y->create_objects();
+
+ y += 30;
+ x = x1;
+
+ canvas_w = get_w() - x - x;
+ canvas_h = get_h() - y - 170;
+ title1_x = x;
+ title2_x = x + (int)(canvas_w * -HIST_MIN_INPUT / FLOAT_RANGE);
+ title3_x = x + (int)(canvas_w * (1.0 - HIST_MIN_INPUT) / FLOAT_RANGE);
+ title4_x = x + (int)(canvas_w);
+ add_subwindow(canvas = new HistogramCanvas(plugin,
+ this,
+ x,
+ y,
+ canvas_w,
+ canvas_h));
+ draw_canvas_overlay();
+ canvas->flash();
+
+ y += canvas->get_h() + 1;
+ add_subwindow(new BC_Title(title1_x,
+ y,
+ "-10%"));
+ add_subwindow(new BC_Title(title2_x,
+ y,
+ "0%"));
+ add_subwindow(new BC_Title(title3_x - get_text_width(MEDIUMFONT, "100"),
+ y,
+ "100%"));
+ add_subwindow(new BC_Title(title4_x - get_text_width(MEDIUMFONT, "110"),
+ y,
+ "110%"));
+
+ y += 20;
+ add_subwindow(title = new BC_Title(x, y, _("Output min:")));
+ x += title->get_w() + 10;
+ output_min = new HistogramOutputText(plugin,
+ this,
+ x,
+ y,
+ &plugin->config.output_min[plugin->mode]);
+ output_min->create_objects();
+ x += output_min->get_w() + 10;
+ add_subwindow(new BC_Title(x, y, _("Output Max:")));
+ x += title->get_w() + 10;
+ output_max = new HistogramOutputText(plugin,
+ this,
+ x,
+ y,
+ &plugin->config.output_max[plugin->mode]);
+ output_max->create_objects();
+
+ x = x1;
+ y += 30;
+
+ add_subwindow(output = new HistogramSlider(plugin,
+ this,
+ x,
+ y,
+ get_w() - 20,
+ 30,
+ 0));
+ output->update();
+ y += 40;
+
+
+ add_subwindow(automatic = new HistogramAuto(plugin,
+ x,
+ y));
+
+ x += 120;
+ add_subwindow(new HistogramReset(plugin,
+ x,
+ y));
+ x += 100;
+ add_subwindow(new BC_Title(x, y, _("Threshold:")));
+ x += 100;
+ threshold = new HistogramOutputText(plugin,
+ this,
+ x,
+ y,
+ &plugin->config.threshold);
+ threshold->create_objects();
+ x = x1;
+ y += 40;
+ add_subwindow(split = new HistogramSplit(plugin, x, y));
+ y += 6;
+ x += 150;
+ add_subwindow(new BC_Title(x,y, _("Interpolation:")));
+ x += 120;
+ add_subwindow(smoothModeChoser = new HistogramSmoothMode(plugin, this, x, y));
+ smoothModeChoser->create_objects();
+
+ show_window();
+}
+
+int HistogramWindow::keypress_event()
+{
+ int result = 0;
+ if(get_keypress() == BACKSPACE ||
+ get_keypress() == DELETE)
+ {
+ if(plugin->current_point >= 0)
+ {
+ HistogramPoint *current =
+ plugin->config.points[plugin->mode].get_item_number(plugin->current_point);
+ delete current;
+ plugin->current_point = -1;
+ update_input();
+ update_canvas();
+ plugin->send_configure_change();
+ result = 1;
+ }
+ }
+ return result;
+}
+
+void HistogramWindow::update(int do_input)
+{
+ automatic->update(plugin->config.automatic);
+ threshold->update(plugin->config.threshold);
+ update_mode();
+
+ if(do_input) update_input();
+ update_output();
+}
+
+void HistogramWindow::update_input()
+{
+ input_x->update();
+ input_y->update();
+}
+
+void HistogramWindow::update_output()
+{
+ output->update();
+ output_min->update(plugin->config.output_min[plugin->mode]);
+ output_max->update(plugin->config.output_max[plugin->mode]);
+}
+
+void HistogramWindow::update_mode()
+{
+ mode_v->update(plugin->mode == HISTOGRAM_VALUE ? 1 : 0);
+ mode_r->update(plugin->mode == HISTOGRAM_RED ? 1 : 0);
+ mode_g->update(plugin->mode == HISTOGRAM_GREEN ? 1 : 0);
+ mode_b->update(plugin->mode == HISTOGRAM_BLUE ? 1 : 0);
+ output_min->output = &plugin->config.output_min[plugin->mode];
+ output_max->output = &plugin->config.output_max[plugin->mode];
+}
+
+void HistogramWindow::draw_canvas_overlay()
+{
+ canvas->set_color(0x00ff00);
+ int y1;
+
+// Calculate output curve
+ plugin->tabulate_curve(plugin->mode, 0);
+
+// Draw output line
+ for(int i = 0; i < canvas_w; i++)
+ {
+ float input = (float)i /
+ canvas_w *
+ FLOAT_RANGE +
+ HIST_MIN_INPUT;
+ float output = plugin->calculate_smooth(input, plugin->mode);
+
+ int y2 = canvas_h - (int)(output * canvas_h);
+ if(i > 0)
+ {
+ canvas->draw_line(i - 1, y1, i, y2);
+ }
+ y1 = y2;
+ }
+
+// Draw output points
+ HistogramPoint *current = plugin->config.points[plugin->mode].first;
+ int number = 0;
+ while(current)
+ {
+ int x = (int)((current->x - HIST_MIN_INPUT) * canvas_w / FLOAT_RANGE);
+ int y = (int)(canvas_h - current->y * canvas_h);
+ if(number == plugin->current_point)
+ canvas->draw_box(x - BOX_SIZE / 2, y - BOX_SIZE / 2, BOX_SIZE, BOX_SIZE);
+ else
+ canvas->draw_rectangle(x - BOX_SIZE / 2, y - BOX_SIZE / 2, BOX_SIZE, BOX_SIZE);
+
+//Draw gradients
+ if (plugin->config.smoothMode > HISTOGRAM_LINEAR)
+ {
+ int x1,x2,y1,y2;
+ canvas->set_color(0x0000ff);
+ x2 = (int)((current->x + current->xoffset_right - HIST_MIN_INPUT) * canvas_w / FLOAT_RANGE);
+ x1 = (int)((current->x + current->xoffset_left - HIST_MIN_INPUT) * canvas_w / FLOAT_RANGE);
+ y2 = (int)(canvas_h - (current->y + current->xoffset_right * current->gradient) * canvas_h);
+ y1 = (int)(canvas_h - (current->y + current->xoffset_left * current->gradient) * canvas_h);
+/* x2 = x + (title3_x - title2_x)/20;
+ x1 = x - (title3_x - title2_x)/20;
+ y1 = y + (int)(current->gradient * (float)(canvas_h)/20.0);
+ y2 = y - (int)(current->gradient * (float)(canvas_h)/20.0);
+// int y2 = (int)(canvas_h - canvas_h * (current->y + current->gradient /10));*/
+ canvas->draw_line(x1,y1,x2,y2);
+
+ canvas->draw_circle(x1 - BOX_SIZE / 4, y1 - BOX_SIZE / 4, BOX_SIZE/2, BOX_SIZE/2);
+ canvas->draw_circle(x2 - BOX_SIZE / 4, y2 - BOX_SIZE / 4, BOX_SIZE/2, BOX_SIZE/2);
+ canvas->set_color(0x00ff00);
+ }
+
+ current = NEXT;
+ number++;
+ }
+
+
+// Draw 0 and 100% lines.
+ canvas->set_color(0xff0000);
+ canvas->draw_line(title2_x - canvas->get_x(),
+ 0,
+ title2_x - canvas->get_x(),
+ canvas_h);
+ canvas->draw_line(title3_x - canvas->get_x(),
+ 0,
+ title3_x - canvas->get_x(),
+ canvas_h);
+}
+
+void HistogramWindow::update_canvas()
+{
+ int *accum = plugin->accum[plugin->mode];
+ int accum_per_canvas_i = HISTOGRAM_SLOTS / canvas_w + 1;
+ float accum_per_canvas_f = (float)HISTOGRAM_SLOTS / canvas_w;
+ int normalize = 0;
+ int max = 0;
+
+ for(int i = 0; i < HISTOGRAM_SLOTS; i++)
+ {
+ if(accum && accum[i] > normalize) normalize = accum[i];
+ }
+
+
+ if(normalize)
+ {
+ for(int i = 0; i < canvas_w; i++)
+ {
+ int accum_start = (int)(accum_per_canvas_f * i);
+ int accum_end = accum_start + accum_per_canvas_i;
+ max = 0;
+ for(int j = accum_start; j < accum_end; j++)
+ {
+ max = MAX(accum[j], max);
+ }
+
+// max = max * canvas_h / normalize;
+ max = (int)(log(max) / log(normalize) * canvas_h);
+
+ canvas->set_color(0xffffff);
+ canvas->draw_line(i, 0, i, canvas_h - max);
+ canvas->set_color(0x000000);
+ canvas->draw_line(i, canvas_h - max, i, canvas_h);
+ }
+ }
+ else
+ {
+ canvas->set_color(0xffffff);
+ canvas->draw_box(0, 0, canvas_w, canvas_h);
+ }
+
+
+ draw_canvas_overlay();
+ canvas->flash();
+}
+
+
+
+
+
+
+
+
+HistogramCanvas::HistogramCanvas(HistogramMain *plugin,
+ HistogramWindow *gui,
+ int x,
+ int y,
+ int w,
+ int h)
+ : BC_SubWindow(x,
+ y,
+ w,
+ h,
+ 0xffffff)
+{
+ this->plugin = plugin;
+ this->gui = gui;
+}
+
+int HistogramCanvas::button_press_event()
+{
+ int result = 0;
+ if(is_event_win() && cursor_inside())
+ {
+ if(!plugin->dragging_point)
+ {
+ HistogramPoint *new_point = 0;
+ gui->deactivate();
+// Search for existing point under cursor
+ HistogramPoint *current = plugin->config.points[plugin->mode].first;
+ plugin->current_point = -1;
+ int dragID = 0;
+ while(current)
+ {
+ int x = (int)((current->x - HIST_MIN_INPUT) * gui->canvas_w / FLOAT_RANGE);
+ int y = (int)(gui->canvas_h - current->y * gui->canvas_h);
+
+/* Check for click on main point */
+ if(get_cursor_x() >= x - BOX_SIZE / 2 &&
+ get_cursor_y() >= y - BOX_SIZE / 2 &&
+ get_cursor_x() < x + BOX_SIZE / 2 &&
+ get_cursor_y() < y + BOX_SIZE / 2)
+ {
+ plugin->current_point =
+ plugin->config.points[plugin->mode].number_of(current);
+ plugin->point_x_offset = get_cursor_x() - x;
+ plugin->point_y_offset = get_cursor_y() - y;
+ dragID = 1;
+ break;
+ }
+ if (plugin->config.smoothMode == HISTOGRAM_LINEAR)
+ break;
+
+ int xright =
+ (int)((current->x + current->xoffset_right - HIST_MIN_INPUT) * gui->canvas_w / FLOAT_RANGE);
+ int yright =
+ (int)(gui->canvas_h - (current->y + current->xoffset_right * current->gradient) *
+ gui->canvas_h);
+
+/* Check for click on right handle */
+ if(get_cursor_x() >= xright - BOX_SIZE / 2 &&
+ get_cursor_y() >= yright - BOX_SIZE / 2 &&
+ get_cursor_x() < xright + BOX_SIZE / 2 &&
+ get_cursor_y() < yright + BOX_SIZE / 2)
+ {
+ plugin->current_point =
+ plugin->config.points[plugin->mode].number_of(current);
+ plugin->point_x_offset = get_cursor_x() - xright;
+ plugin->point_y_offset = get_cursor_y() - yright;
+ dragID = 2;
+ break;
+ }
+
+/* Check for click on left handle */
+ int xleft =
+ (int)((current->x + current->xoffset_left - HIST_MIN_INPUT) * gui->canvas_w / FLOAT_RANGE);
+ int yleft =
+ (int)(gui->canvas_h - (current->y + current->xoffset_left * current->gradient) *
+ gui->canvas_h);
+ if(get_cursor_x() >= xleft - BOX_SIZE / 2 &&
+ get_cursor_y() >= yleft - BOX_SIZE / 2 &&
+ get_cursor_x() < xleft + BOX_SIZE / 2 &&
+ get_cursor_y() < yleft + BOX_SIZE / 2)
+ {
+ plugin->current_point =
+ plugin->config.points[plugin->mode].number_of(current);
+ plugin->point_x_offset = get_cursor_x() - xleft;
+ plugin->point_y_offset = get_cursor_y() - yleft;
+ dragID = 3;
+ break;
+ }
+
+
+ current = NEXT;
+ }
+
+ if(plugin->current_point < 0)
+ {
+// Create new point under cursor
+ float current_x = (float)get_cursor_x() *
+ FLOAT_RANGE /
+ get_w() +
+ HIST_MIN_INPUT;
+ float current_y = 1.0 -
+ (float)get_cursor_y() /
+ get_h();
+ new_point =
+ plugin->config.points[plugin->mode].insert(current_x, current_y);
+ plugin->current_point =
+ plugin->config.points[plugin->mode].number_of(new_point);
+ plugin->point_x_offset = 0;
+ plugin->point_y_offset = 0;
+
+// Default gradient
+// Get 2 points surrounding current position
+ float x1,x2,y1,y2;
+
+ HistogramPoint *current = plugin->config.points[plugin->mode].first;
+ int done = 0;
+ while(current && !done)
+ {
+ if(current->x > current_x)
+ {
+ x2 = current->x;
+ y2 = current->y;
+ done = 1;
+ }
+ else
+ current = NEXT;
+ }
+
+ current = plugin->config.points[plugin->mode].last;
+ done = 0;
+ while(current && !done)
+ {
+ if(current->x <= current_x)
+ {
+ x1 = current->x;
+ y1 = current->y;
+ done = 1;
+ }
+ else
+ current = PREVIOUS;
+ }
+ new_point->gradient = (y2 - y1) / (x2 - x1);
+ dragID = 1;
+
+ }
+
+
+ plugin->dragging_point = dragID;
+ result = 1;
+
+ plugin->config.boundaries();
+ gui->update_input();
+ gui->update_canvas();
+ if(new_point)
+ {
+ plugin->send_configure_change();
+ }
+ }
+ }
+ return result;
+}
+
+int HistogramCanvas::cursor_motion_event()
+{
+ if(plugin->dragging_point)
+ {
+ HistogramPoint * current_point = plugin->config.points[plugin->mode].get_item_number(plugin->current_point);
+
+ float current_x =
+ (float)(get_cursor_x() - plugin->point_x_offset) *
+ FLOAT_RANGE /
+ get_w() +
+ HIST_MIN_INPUT;
+ float current_y = 1.0 -
+ (float)(get_cursor_y() - plugin->point_y_offset) /
+ get_h();
+
+ switch(plugin->dragging_point)
+ {
+ case 1: /* Main point dragged */
+ current_point->x = current_x;
+ current_point->y = current_y;
+ break;
+ case 2: /* Right control point dragged */
+ if (current_x - current_point->x > 0)
+ {
+ current_point->xoffset_right = current_x - current_point->x;
+ current_point->gradient = (current_y - current_point->y) / (current_x - current_point->x);
+ }
+ break;
+ case 3: /* Left control point dragged */
+ if (current_x - current_point->x < 0)
+ {
+ current_point->xoffset_left = current_x - current_point->x;
+ current_point->gradient = (current_point->y - current_y) / (current_point->x - current_x);
+ }
+ break;
+ }
+
+ plugin->config.boundaries();
+ gui->update_input();
+ gui->update_canvas();
+ plugin->send_configure_change();
+ return 1;
+ }
+ return 0;
+}
+
+int HistogramCanvas::button_release_event()
+{
+ if(plugin->dragging_point)
+ {
+// Test for out of order points to delete.
+ HistogramPoint *current =
+ plugin->config.points[plugin->mode].get_item_number(plugin->current_point);
+ HistogramPoint *prev = PREVIOUS;
+ HistogramPoint *next = NEXT;
+
+ if((prev && prev->x >= current->x) ||
+ (next && next->x <= current->x))
+ {
+ delete current;
+ plugin->current_point = -1;
+ plugin->config.boundaries();
+ gui->update_input();
+ gui->update_canvas();
+ plugin->send_configure_change();
+ }
+
+ plugin->dragging_point = 0;
+ }
+ return 0;
+}
+
+
+
+
+
+
+
+HistogramReset::HistogramReset(HistogramMain *plugin,
+ int x,
+ int y)
+ : BC_GenericButton(x, y, _("Reset"))
+{
+ this->plugin = plugin;
+}
+int HistogramReset::handle_event()
+{
+ plugin->config.reset(0);
+ HistogramWindow *window = (HistogramWindow *)plugin->thread->window;
+ window->update(1);
+ window->update_canvas();
+ plugin->send_configure_change();
+ return 1;
+}
+
+
+
+
+
+
+
+
+
+HistogramSlider::HistogramSlider(HistogramMain *plugin,
+ HistogramWindow *gui,
+ int x,
+ int y,
+ int w,
+ int h,
+ int is_input)
+ : BC_SubWindow(x, y, w, h)
+{
+ this->plugin = plugin;
+ this->gui = gui;
+ this->is_input = is_input;
+ operation = NONE;
+}
+
+int HistogramSlider::input_to_pixel(float input)
+{
+ return (int)((input - HIST_MIN_INPUT) / FLOAT_RANGE * get_w());
+}
+
+int HistogramSlider::button_press_event()
+{
+ if(is_event_win() && cursor_inside())
+ {
+// int w = get_w();
+ int h = get_h();
+ int half_h = get_h() / 2;
+
+ gui->deactivate();
+
+ if(operation == NONE)
+ {
+ int x1 = input_to_pixel(plugin->config.output_min[plugin->mode]) -
+ gui->mid_picon->get_w() / 2;
+ int x2 = x1 + gui->mid_picon->get_w();
+ if(get_cursor_x() >= x1 && get_cursor_x() < x2 &&
+ get_cursor_y() >= half_h && get_cursor_y() < h)
+ {
+ operation = DRAG_MIN_OUTPUT;
+ }
+ }
+
+ if(operation == NONE)
+ {
+ int x1 = input_to_pixel(plugin->config.output_max[plugin->mode]) -
+ gui->mid_picon->get_w() / 2;
+ int x2 = x1 + gui->mid_picon->get_w();
+ if(get_cursor_x() >= x1 && get_cursor_x() < x2 &&
+ get_cursor_y() >= half_h && get_cursor_y() < h)
+ {
+ operation = DRAG_MAX_OUTPUT;
+ }
+ }
+ return 1;
+ }
+ return 0;
+}
+
+int HistogramSlider::button_release_event()
+{
+ if(operation != NONE)
+ {
+ operation = NONE;
+ return 1;
+ }
+ return 0;
+}
+
+int HistogramSlider::cursor_motion_event()
+{
+ if(operation != NONE)
+ {
+ float value = (float)get_cursor_x() / get_w() * FLOAT_RANGE + HIST_MIN_INPUT;
+ CLAMP(value, HIST_MIN_INPUT, HIST_MAX_INPUT);
+
+ switch(operation)
+ {
+ case DRAG_MIN_OUTPUT:
+ value = MIN(plugin->config.output_max[plugin->mode], value);
+ plugin->config.output_min[plugin->mode] = value;
+ break;
+ case DRAG_MAX_OUTPUT:
+ value = MAX(plugin->config.output_min[plugin->mode], value);
+ plugin->config.output_max[plugin->mode] = value;
+ break;
+ }
+
+ plugin->config.boundaries();
+ gui->update_output();
+
+ plugin->send_configure_change();
+ return 1;
+ }
+ return 0;
+}
+
+void HistogramSlider::update()
+{
+ int w = get_w();
+ int h = get_h();
+ int half_h = get_h() / 2;
+// int quarter_h = get_h() / 4;
+ int mode = plugin->mode;
+ int r = 0xff;
+ int g = 0xff;
+ int b = 0xff;
+
+ clear_box(0, 0, w, h);
+
+ switch(mode)
+ {
+ case HISTOGRAM_RED:
+ g = b = 0x00;
+ break;
+ case HISTOGRAM_GREEN:
+ r = b = 0x00;
+ break;
+ case HISTOGRAM_BLUE:
+ r = g = 0x00;
+ break;
+ }
+
+ for(int i = 0; i < w; i++)
+ {
+ int color = (int)(i * 0xff / w);
+ set_color(((r * color / 0xff) << 16) |
+ ((g * color / 0xff) << 8) |
+ (b * color / 0xff));
+
+ draw_line(i, 0, i, half_h);
+ }
+
+ float min;
+ float max;
+ min = plugin->config.output_min[plugin->mode];
+ max = plugin->config.output_max[plugin->mode];
+
+ draw_pixmap(gui->min_picon,
+ input_to_pixel(min) - gui->min_picon->get_w() / 2,
+ half_h + 1);
+ draw_pixmap(gui->max_picon,
+ input_to_pixel(max) - gui->max_picon->get_w() / 2,
+ half_h + 1);
+
+ flash();
+ flush();
+}
+
+
+
+
+
+
+
+
+
+HistogramAuto::HistogramAuto(HistogramMain *plugin,
+ int x,
+ int y)
+ : BC_CheckBox(x, y, plugin->config.automatic, _("Automatic"))
+{
+ this->plugin = plugin;
+}
+
+int HistogramAuto::handle_event()
+{
+ plugin->config.automatic = get_value();
+ plugin->send_configure_change();
+ return 1;
+}
+
+
+
+
+HistogramSplit::HistogramSplit(HistogramMain *plugin,
+ int x,
+ int y)
+ : BC_CheckBox(x, y, plugin->config.split, _("Split picture"))
+{
+ this->plugin = plugin;
+}
+
+int HistogramSplit::handle_event()
+{
+ plugin->config.split = get_value();
+ plugin->send_configure_change();
+ return 1;
+}
+
+
+
+
+HistogramMode::HistogramMode(HistogramMain *plugin,
+ int x,
+ int y,
+ int value,
+ char *text)
+ : BC_Radial(x, y, plugin->mode == value, text)
+{
+ this->plugin = plugin;
+ this->value = value;
+}
+int HistogramMode::handle_event()
+{
+ plugin->mode = value;
+ plugin->current_point= -1;
+ HistogramWindow *window = (HistogramWindow *)plugin->thread->window;
+ window->update_canvas();
+ window->update_mode();
+ window->update_input();
+ window->update_canvas();
+ window->update_output();
+ window->output->update();
+// plugin->send_configure_change();
+ return 1;
+}
+
+
+
+
+
+
+
+
+
+HistogramOutputText::HistogramOutputText(HistogramMain *plugin,
+ HistogramWindow *gui,
+ int x,
+ int y,
+ float *output)
+ : BC_TumbleTextBox(gui,
+ output ? (float)*output : 0.0,
+ (float)HIST_MIN_INPUT,
+ (float)HIST_MAX_INPUT,
+ x,
+ y,
+ 60)
+{
+ this->plugin = plugin;
+ this->output = output;
+ set_precision(DIGITS);
+ set_increment(PRECISION);
+}
+
+
+int HistogramOutputText::handle_event()
+{
+ if(output)
+ {
+ *output = atof(get_text());
+ }
+
+ HistogramWindow *window = (HistogramWindow *)plugin->thread->window;
+ window->output->update();
+ plugin->send_configure_change();
+ return 1;
+}
+
+
+
+
+
+
+
+
+HistogramInputText::HistogramInputText(HistogramMain *plugin,
+ HistogramWindow *gui,
+ int x,
+ int y,
+ int do_x)
+ : BC_TumbleTextBox(gui,
+ 0.0,
+ (float)HIST_MIN_INPUT,
+ (float)HIST_MAX_INPUT,
+ x,
+ y,
+ 60)
+{
+ this->do_x = do_x;
+ this->plugin = plugin;
+ this->gui = gui;
+ set_precision(DIGITS);
+ set_increment(PRECISION);
+}
+
+
+int HistogramInputText::handle_event()
+{
+ if(plugin->current_point >= 0 &&
+ plugin->current_point < plugin->config.points[plugin->mode].total())
+ {
+ HistogramPoint *point =
+ plugin->config.points[plugin->mode].get_item_number(
+ plugin->current_point);
+
+ if(point)
+ {
+ if(do_x)
+ point->x = atof(get_text());
+ else
+ point->y = atof(get_text());
+
+ plugin->config.boundaries();
+ gui->update_canvas();
+
+ HistogramWindow *window = (HistogramWindow *)plugin->thread->window;
+ window->output->update();
+ plugin->send_configure_change();
+ }
+ }
+ return 1;
+}
+
+void HistogramInputText::update()
+{
+ if(plugin->current_point >= 0 &&
+ plugin->current_point < plugin->config.points[plugin->mode].total())
+ {
+ HistogramPoint *point =
+
+ plugin->config.points[plugin->mode].get_item_number(
+ plugin->current_point);
+
+ if(point)
+ {
+ if(do_x)
+ BC_TumbleTextBox::update(point->x);
+ else
+ BC_TumbleTextBox::update(point->y);
+ }
+ else
+ {
+ BC_TumbleTextBox::update((float)0.0);
+ }
+ }
+ else
+ {
+ BC_TumbleTextBox::update((float)0.0);
+ }
+
+}
+
+
+HistogramSmoothMode::HistogramSmoothMode(HistogramMain*plugin,
+ HistogramWindow *gui,
+ int x,
+ int y)
+ : BC_PopupMenu(x, y, 120, to_text(plugin->config.smoothMode), 1)
+{
+ this->plugin = plugin;
+ this->gui = gui;
+}
+void HistogramSmoothMode::create_objects()
+{
+ add_item(new BC_MenuItem(to_text(HISTOGRAM_LINEAR)));
+ add_item(new BC_MenuItem(to_text(HISTOGRAM_POLYNOMINAL)));
+ add_item(new BC_MenuItem(to_text(HISTOGRAM_BEZIER)));
+}
+
+char* HistogramSmoothMode::to_text(int mode)
+{
+ switch(mode)
+ {
+ case HISTOGRAM_LINEAR:
+ return _("Linear");
+ case HISTOGRAM_POLYNOMINAL:
+ return _("Polynominal");
+ case HISTOGRAM_BEZIER:
+ return _("Bezier");
+ }
+ return _("None");
+}
+
+int HistogramSmoothMode::from_text(char *text)
+{
+ if(!strcmp(text, to_text(HISTOGRAM_LINEAR)))
+ return HISTOGRAM_LINEAR;
+ if(!strcmp(text, to_text(HISTOGRAM_POLYNOMINAL)))
+ return HISTOGRAM_POLYNOMINAL;
+ if(!strcmp(text, to_text(HISTOGRAM_BEZIER)))
+ return HISTOGRAM_BEZIER;
+ return HISTOGRAM_LINEAR;
+}
+
+int HistogramSmoothMode::handle_event()
+{
+ plugin->config.smoothMode = from_text(get_text());
+ gui->update_canvas();
+ plugin->send_configure_change();
+ return 1;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
--- /dev/null
+
+/*
+ * CINELERRA
+ * Copyright (C) 2008 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 HISTOGRAMWINDOW_H
+#define HISTOGRAMWINDOW_H
+
+
+
+#include "bistogram.inc"
+#include "bistogramwindow.inc"
+#include "pluginvclient.h"
+
+
+class HistogramSmoothMode : public BC_PopupMenu
+{
+public:
+ HistogramSmoothMode(HistogramMain *client,
+ HistogramWindow *window,
+ int x,
+ int y);
+ void create_objects();
+ static char* to_text(int shape);
+ static int from_text(char *text);
+ int handle_event();
+ HistogramMain *plugin;
+ HistogramWindow *gui;
+};
+
+class HistogramSlider : public BC_SubWindow
+{
+public:
+ HistogramSlider(HistogramMain *plugin,
+ HistogramWindow *gui,
+ int x,
+ int y,
+ int w,
+ int h,
+ int is_input);
+
+ void update();
+ int button_press_event();
+ int button_release_event();
+ int cursor_motion_event();
+ int input_to_pixel(float input);
+
+ int operation;
+ enum
+ {
+ NONE,
+ DRAG_INPUT,
+ DRAG_MIN_OUTPUT,
+ DRAG_MAX_OUTPUT,
+ };
+ int is_input;
+ HistogramMain *plugin;
+ HistogramWindow *gui;
+};
+
+class HistogramAuto : public BC_CheckBox
+{
+public:
+ HistogramAuto(HistogramMain *plugin,
+ int x,
+ int y);
+ int handle_event();
+ HistogramMain *plugin;
+};
+
+class HistogramSplit : public BC_CheckBox
+{
+public:
+ HistogramSplit(HistogramMain *plugin,
+ int x,
+ int y);
+ int handle_event();
+ HistogramMain *plugin;
+};
+
+class HistogramMode : public BC_Radial
+{
+public:
+ HistogramMode(HistogramMain *plugin,
+ int x,
+ int y,
+ int value,
+ char *text);
+ int handle_event();
+ HistogramMain *plugin;
+ int value;
+};
+
+class HistogramReset : public BC_GenericButton
+{
+public:
+ HistogramReset(HistogramMain *plugin,
+ int x,
+ int y);
+ int handle_event();
+ HistogramMain *plugin;
+};
+
+
+class HistogramOutputText : public BC_TumbleTextBox
+{
+public:
+ HistogramOutputText(HistogramMain *plugin,
+ HistogramWindow *gui,
+ int x,
+ int y,
+ float *output);
+ int handle_event();
+ HistogramMain *plugin;
+ float *output;
+};
+
+class HistogramInputText : public BC_TumbleTextBox
+{
+public:
+ HistogramInputText(HistogramMain *plugin,
+ HistogramWindow *gui,
+ int x,
+ int y,
+ int do_x);
+
+ int handle_event();
+ void update();
+
+ HistogramMain *plugin;
+ HistogramWindow *gui;
+ int do_x;
+};
+
+class HistogramCanvas : public BC_SubWindow
+{
+public:
+ HistogramCanvas(HistogramMain *plugin,
+ HistogramWindow *gui,
+ int x,
+ int y,
+ int w,
+ int h);
+ int button_press_event();
+ int cursor_motion_event();
+ int button_release_event();
+ HistogramMain *plugin;
+ HistogramWindow *gui;
+};
+
+class HistogramWindow : public PluginClientWindow
+{
+public:
+ HistogramWindow(HistogramMain *plugin);
+ ~HistogramWindow();
+
+ void create_objects();
+ void update(int do_input);
+ void update_mode();
+ void update_canvas();
+ void draw_canvas_overlay();
+ void update_input();
+ void update_output();
+ int keypress_event();
+
+ HistogramSlider *output;
+ HistogramAuto *automatic;
+ HistogramSplit *split;
+ HistogramSmoothMode *smoothModeChoser;
+ HistogramMode *mode_v, *mode_r, *mode_g, *mode_b /*, *mode_a */;
+ HistogramOutputText *output_min;
+ HistogramOutputText *output_max;
+ HistogramOutputText *threshold;
+ HistogramInputText *input_x;
+ HistogramInputText *input_y;
+ HistogramCanvas *canvas;
+ HistogramMain *plugin;
+ int canvas_w;
+ int canvas_h;
+ int title1_x;
+ int title2_x;
+ int title3_x;
+ int title4_x;
+ BC_Pixmap *max_picon, *mid_picon, *min_picon;
+};
+
+
+#endif
--- /dev/null
+
+/*
+ * CINELERRA
+ * Copyright (C) 2008 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 HISTOGRAMWINDOW_INC
+#define HISTOGRAMWINDOW_INC
+
+class HistogramWindow;
+class HistogramThread;
+
+#endif
+++ /dev/null
-
-/*
- * CINELERRA
- * Copyright (C) 2008 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 <math.h>
-#include <stdint.h>
-#include <string.h>
-#include <unistd.h>
-
-#include "bcdisplayinfo.h"
-#include "bcsignals.h"
-#include "clip.h"
-#include "bchash.h"
-#include "filexml.h"
-#include "histogram.h"
-#include "histogramconfig.h"
-#include "histogramwindow.h"
-#include "keyframe.h"
-#include "language.h"
-#include "loadbalance.h"
-#include "cicolors.h"
-#include "vframe.h"
-
-
-
-class HistogramMain;
-class HistogramEngine;
-class HistogramWindow;
-
-
-
-
-
-REGISTER_PLUGIN(HistogramMain)
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-HistogramMain::HistogramMain(PluginServer *server)
- : PluginVClient(server)
-{
-
- engine = 0;
- for(int i = 0; i < HISTOGRAM_MODES; i++)
- {
- lookup[i] = 0;
- smoothed[i] = 0;
- linear[i] = 0;
- accum[i] = 0;
- }
- current_point = -1;
- mode = HISTOGRAM_VALUE;
- dragging_point = 0;
- input = 0;
- output = 0;
-}
-
-HistogramMain::~HistogramMain()
-{
-
- for(int i = 0; i < HISTOGRAM_MODES;i++)
- {
- delete [] lookup[i];
- delete [] smoothed[i];
- delete [] linear[i];
- delete [] accum[i];
- }
- delete engine;
-}
-
-char* HistogramMain::plugin_title() { return _("Histogram"); }
-int HistogramMain::is_realtime() { return 1; }
-
-
-
-SHOW_GUI_MACRO(HistogramMain, HistogramThread)
-
-SET_STRING_MACRO(HistogramMain)
-
-RAISE_WINDOW_MACRO(HistogramMain)
-
-LOAD_CONFIGURATION_MACRO(HistogramMain, HistogramConfig)
-
-void HistogramMain::render_gui(void *data)
-{
- if(thread)
- {
- calculate_histogram((VFrame*)data);
-
- if(config.automatic)
- {
- calculate_automatic((VFrame*)data);
- }
-
- thread->window->lock_window("HistogramMain::render_gui");
- thread->window->update_canvas();
- if(config.automatic)
- {
- thread->window->update_input();
- }
- thread->window->unlock_window();
- }
-}
-
-void HistogramMain::update_gui()
-{
- if(thread)
- {
- thread->window->lock_window("HistogramMain::update_gui");
- int reconfigure = load_configuration();
- if(reconfigure)
- {
- thread->window->update(0);
- if(!config.automatic)
- {
- thread->window->update_input();
- }
- }
- thread->window->unlock_window();
- }
-}
-
-
-int HistogramMain::load_defaults()
-{
- char directory[BCTEXTLEN], string[BCTEXTLEN];
-// set the default directory
- sprintf(directory, "%shistogram.rc", BCASTDIR);
-
-// load the defaults
- defaults = new BC_Hash(directory);
- defaults->load();
-
- for(int j = 0; j < HISTOGRAM_MODES; j++)
- {
- while(config.points[j].last) delete config.points[j].last;
-
- sprintf(string, "TOTAL_POINTS_%d", j);
- int total_points = defaults->get(string, 0);
-
- for(int i = 0; i < total_points; i++)
- {
- HistogramPoint *point = new HistogramPoint;
- sprintf(string, "INPUT_X_%d_%d", j, i);
- point->x = defaults->get(string, point->x);
- sprintf(string, "INPUT_Y_%d_%d", j, i);
- point->y = defaults->get(string, point->y);
- sprintf(string, "GRADIENT_%d_%d", j, i);
- point->gradient = defaults->get(string, point->gradient);
- sprintf(string, "XOFFSET_LEFT_%d_%d", j, i);
- point->xoffset_left = defaults->get(string, point->xoffset_left);
- sprintf(string, "XOFFSET_RIGHT_%d_%d", j, i);
- point->xoffset_right = defaults->get(string, point->xoffset_right);
- config.points[j].append(point);
- }
- }
-
-
- for(int i = 0; i < HISTOGRAM_MODES; i++)
- {
- sprintf(string, "OUTPUT_MIN_%d", i);
- config.output_min[i] = defaults->get(string, config.output_min[i]);
- sprintf(string, "OUTPUT_MAX_%d", i);
- config.output_max[i] = defaults->get(string, config.output_max[i]);
- }
-
- config.automatic = defaults->get("AUTOMATIC", config.automatic);
- mode = defaults->get("MODE", mode);
- CLAMP(mode, 0, HISTOGRAM_MODES - 1);
- config.threshold = defaults->get("THRESHOLD", config.threshold);
- config.split = defaults->get("SPLIT", config.split);
- config.smoothMode = defaults->get("INTERPOLATION", config.smoothMode);
- config.boundaries();
- return 0;
-}
-
-
-int HistogramMain::save_defaults()
-{
- char string[BCTEXTLEN];
-
-
-
- for(int j = 0; j < HISTOGRAM_MODES; j++)
- {
- int total_points = config.points[j].total();
- sprintf(string, "TOTAL_POINTS_%d", j);
- defaults->update(string, total_points);
- HistogramPoint *current = config.points[j].first;
- int number = 0;
- while(current)
- {
- sprintf(string, "INPUT_X_%d_%d", j, number);
- defaults->update(string, current->x);
- sprintf(string, "INPUT_Y_%d_%d", j, number);
- defaults->update(string, current->y);
- sprintf(string, "GRADIENT_%d_%d", j, number);
- defaults->update(string, current->gradient);
- sprintf(string, "XOFFSET_LEFT_%d_%d", j, number);
- defaults->update(string, current->xoffset_left);
- sprintf(string, "XOFFSET_RIGHT_%d_%d", j, number);
- defaults->update(string, current->xoffset_right);
- current = NEXT;
- number++;
- }
- }
-
-
- for(int i = 0; i < HISTOGRAM_MODES; i++)
- {
- sprintf(string, "OUTPUT_MIN_%d", i);
- defaults->update(string, config.output_min[i]);
- sprintf(string, "OUTPUT_MAX_%d", i);
- defaults->update(string, config.output_max[i]);
- }
-
- defaults->update("AUTOMATIC", config.automatic);
- defaults->update("MODE", mode);
- defaults->update("THRESHOLD", config.threshold);
- defaults->update("SPLIT", config.split);
- defaults->update("INTERPOLATION", config.smoothMode);
- defaults->save();
- return 0;
-}
-
-
-
-void HistogramMain::save_data(KeyFrame *keyframe)
-{
- FileXML output;
-
-// cause data to be stored directly in text
- output.set_shared_output(keyframe->get_data(), MESSAGESIZE);
- output.tag.set_title("HISTOGRAM");
-
- char string[BCTEXTLEN];
-
-
- for(int i = 0; i < HISTOGRAM_MODES; i++)
- {
- sprintf(string, "OUTPUT_MIN_%d", i);
- output.tag.set_property(string, config.output_min[i]);
- sprintf(string, "OUTPUT_MAX_%d", i);
- output.tag.set_property(string, config.output_max[i]);
-//printf("HistogramMain::save_data %d %f %d\n", config.input_min[i], config.input_mid[i], config.input_max[i]);
- }
-
- output.tag.set_property("AUTOMATIC", config.automatic);
- output.tag.set_property("THRESHOLD", config.threshold);
- output.tag.set_property("SPLIT", config.split);
- output.tag.set_property("INTERPOLATION", config.smoothMode);
- output.append_tag();
- output.append_newline();
-
-
-
-
-
- for(int j = 0; j < HISTOGRAM_MODES; j++)
- {
- output.tag.set_title("POINTS");
- output.append_tag();
- output.append_newline();
-
-
- HistogramPoint *current = config.points[j].first;
- while(current)
- {
- output.tag.set_title("POINT");
- output.tag.set_property("X", current->x);
- output.tag.set_property("Y", current->y);
- output.tag.set_property("GRADIENT", current->gradient);
- output.tag.set_property("XOFFSET_LEFT", current->xoffset_left);
- output.tag.set_property("XOFFSET_RIGHT", current->xoffset_right);
- output.append_tag();
- output.append_newline();
- current = NEXT;
- }
-
-
- output.tag.set_title("/POINTS");
- output.append_tag();
- output.append_newline();
- }
-
-
-
-
-
-
- output.terminate_string();
-}
-
-void HistogramMain::read_data(KeyFrame *keyframe)
-{
- FileXML input;
-
- input.set_shared_input(keyframe->get_data(), strlen(keyframe->get_data()));
-
- int result = 0;
- int current_input_mode = 0;
-
-
- while(!result)
- {
- result = input.read_tag();
-
- if(!result)
- {
- if(input.tag.title_is("HISTOGRAM"))
- {
- char string[BCTEXTLEN];
- for(int i = 0; i < HISTOGRAM_MODES; i++)
- {
- sprintf(string, "OUTPUT_MIN_%d", i);
- config.output_min[i] = input.tag.get_property(string, config.output_min[i]);
- sprintf(string, "OUTPUT_MAX_%d", i);
- config.output_max[i] = input.tag.get_property(string, config.output_max[i]);
-//printf("HistogramMain::read_data %d %f %d\n", config.input_min[i], config.input_mid[i], config.input_max[i]);
- }
- config.automatic = input.tag.get_property("AUTOMATIC", config.automatic);
- config.threshold = input.tag.get_property("THRESHOLD", config.threshold);
- config.split = input.tag.get_property("SPLIT", config.split);
- config.smoothMode = input.tag.get_property("INTERPOLATION", config.smoothMode);
- }
- else
- if(input.tag.title_is("POINTS"))
- {
- if(current_input_mode < HISTOGRAM_MODES)
- {
- HistogramPoints *points = &config.points[current_input_mode];
- while(points->last)
- delete points->last;
- while(!result)
- {
- result = input.read_tag();
- if(!result)
- {
- if(input.tag.title_is("/POINTS"))
- {
- break;
- }
- else
- if(input.tag.title_is("POINT"))
- {
- points->insert(
- input.tag.get_property("X", 0.0),
- input.tag.get_property("Y", 0.0));
- points->last->gradient =
- input.tag.get_property("GRADIENT", 1.0);
- points->last->xoffset_left =
- input.tag.get_property("XOFFSET_LEFT", -0.02);
- points->last->xoffset_right =
- input.tag.get_property("XOFFSET_RIGHT", 0.02);
- }
- }
- }
-
- }
- current_input_mode++;
- }
- }
- }
-
- config.boundaries();
-
-}
-
-float HistogramMain::calculate_linear(float input,
- int subscript,
- int use_value)
-{
- int done = 0;
- float output;
-
- if(input < 0)
- {
- output = 0;
- done = 1;
- }
-
- if(input > 1)
- {
- output = 1;
- done = 1;
- }
-
- if(!done)
- {
-
- float x1 = 0;
- float y1 = 0;
- float grad1 = 1.0;
- float x1right = 0;
- float x2 = 1;
- float y2 = 1;
- float grad2 = 1.0;
- float x2left = 0;
-
-
-
-// Get 2 points surrounding current position
- HistogramPoints *points = &config.points[subscript];
- HistogramPoint *current = points->first;
- int done = 0;
- while(current && !done)
- {
- if(current->x > input)
- {
- x2 = current->x;
- y2 = current->y;
- grad2 = current->gradient;
- x2left = current->xoffset_left;
- done = 1;
- }
- else
- current = NEXT;
- }
-
- current = points->last;
- done = 0;
- while(current && !done)
- {
- if(current->x <= input)
- {
- x1 = current->x;
- y1 = current->y;
- grad1 = current->gradient;
- done = 1;
- x1right = current->xoffset_right;
- }
- else
- current = PREVIOUS;
- }
-
-
-
-
- if(!EQUIV(x2 - x1, 0))
- {
- if (config.smoothMode == HISTOGRAM_LINEAR)
- output = (input - x1) * (y2 - y1) / (x2 - x1) + y1;
- else if (config.smoothMode == HISTOGRAM_POLYNOMINAL)
- {
- /* Construct third grade polynom between every two points */
- float dx = x2 - x1;
- float dy = y2 - y1;
- float delx = input - x1;
- output = 1 / (dx * dx * dx) * (grad2 * dx + grad1 * dx - 2*dy) * delx * delx * delx + 1 / (dx * dx) * (3*dy - 2* grad1*dx - grad2*dx) * delx * delx + grad1*delx + y1;
- }
- else if (config.smoothMode == HISTOGRAM_BEZIER)
- {
- /* Using standart DeCasteljau algorithm */
- float y1right = y1 + grad1 * x1right;
- float y2left = y2 + grad2 * x2left;
-
- float t = (input - x1) / (x2 - x1);
-
- float pointAy = y1 + (y1right - y1) * t;
- float pointBy = y1right + (y2left - y1right) * t;
- float pointCy = y2left + (y2 - y2left) * t;
- float pointABy = pointAy + (pointBy - pointAy) * t;
- float pointBCy = pointBy + (pointCy - pointBy) * t;
- output = pointABy + (pointBCy - pointABy) * t;
-
- }
- }
-
- else
-// Linear
- output = input * y2;
-
-
-
-//
-
-
- }
-
-// Apply value curve
- if(use_value)
- {
- output = calculate_linear(output, HISTOGRAM_VALUE, 0);
- }
-
-
- float output_min = config.output_min[subscript];
- float output_max = config.output_max[subscript];
- float output_left;
- float output_right;
- float output_linear;
-
-// Compress output for value followed by channel
- output = output_min +
- output *
- (output_max - output_min);
-
-
- return output;
-}
-
-float HistogramMain::calculate_smooth(float input, int subscript)
-{
- float x_f = (input - HIST_MIN_INPUT) * HISTOGRAM_SLOTS / FLOAT_RANGE;
- int x_i1 = (int)x_f;
- int x_i2 = x_i1 + 1;
- CLAMP(x_i1, 0, HISTOGRAM_SLOTS - 1);
- CLAMP(x_i2, 0, HISTOGRAM_SLOTS - 1);
- CLAMP(x_f, 0, HISTOGRAM_SLOTS - 1);
-
- float smooth1 = smoothed[subscript][x_i1];
- float smooth2 = smoothed[subscript][x_i2];
- float result = smooth1 + (smooth2 - smooth1) * (x_f - x_i1);
- CLAMP(result, 0, 1.0);
- return result;
-}
-
-
-void HistogramMain::calculate_histogram(VFrame *data)
-{
-
- if(!engine) engine = new HistogramEngine(this,
- get_project_smp() + 1,
- get_project_smp() + 1);
-
- if(!accum[0])
- {
- for(int i = 0; i < HISTOGRAM_MODES; i++)
- accum[i] = new int[HISTOGRAM_SLOTS];
- }
- engine->process_packages(HistogramEngine::HISTOGRAM, data);
-
- for(int i = 0; i < engine->get_total_clients(); i++)
- {
- HistogramUnit *unit = (HistogramUnit*)engine->get_client(i);
- if(i == 0)
- {
- for(int j = 0; j < HISTOGRAM_MODES; j++)
- memcpy(accum[j], unit->accum[j], sizeof(int) * HISTOGRAM_SLOTS);
- }
- else
- {
- for(int j = 0; j < HISTOGRAM_MODES; j++)
- {
- int *out = accum[j];
- int *in = unit->accum[j];
- for(int k = 0; k < HISTOGRAM_SLOTS; k++)
- out[k] += in[k];
- }
- }
- }
-
-// Remove top and bottom from calculations. Doesn't work in high
-// precision colormodels.
- for(int i = 0; i < HISTOGRAM_MODES; i++)
- {
- accum[i][0] = 0;
- accum[i][HISTOGRAM_SLOTS - 1] = 0;
- }
-}
-
-
-void HistogramMain::calculate_automatic(VFrame *data)
-{
- calculate_histogram(data);
- config.reset_points();
-
-// Do each channel
- for(int i = 0; i < 3; i++)
- {
- int *accum = this->accum[i];
- int pixels = data->get_w() * data->get_h();
- float white_fraction = 1.0 - (1.0 - config.threshold) / 2;
- int threshold = (int)(white_fraction * pixels);
- int total = 0;
- float max_level = 1.0;
- float min_level = 0.0;
-
-// Get histogram slot above threshold of pixels
- for(int j = 0; j < HISTOGRAM_SLOTS; j++)
- {
- total += accum[j];
- if(total >= threshold)
- {
- max_level = (float)j / HISTOGRAM_SLOTS * FLOAT_RANGE + HIST_MIN_INPUT;
- break;
- }
- }
-
-// Get slot below 99% of pixels
- total = 0;
- for(int j = HISTOGRAM_SLOTS - 1; j >= 0; j--)
- {
- total += accum[j];
- if(total >= threshold)
- {
- min_level = (float)j / HISTOGRAM_SLOTS * FLOAT_RANGE + HIST_MIN_INPUT;
- break;
- }
- }
-
-
- config.points[i].insert(max_level, 1.0);
- config.points[i].insert(min_level, 0.0);
-
- }
-}
-
-
-
-
-
-
-int HistogramMain::process_realtime(VFrame *input_ptr, VFrame *output_ptr)
-{
-SET_TRACE
- int need_reconfigure = load_configuration();
-
-SET_TRACE
-
- if(!engine) engine = new HistogramEngine(this,
- get_project_smp() + 1,
- get_project_smp() + 1);
- this->input = input_ptr;
- this->output = output_ptr;
-
- send_render_gui(input_ptr);
-
- if(input_ptr->get_rows()[0] != output_ptr->get_rows()[0])
- {
- output_ptr->copy_from(input_ptr);
- }
-
-SET_TRACE
-// Generate tables here. The same table is used by many packages to render
-// each horizontal stripe. Need to cover the entire output range in each
-// table to avoid green borders
- if(need_reconfigure ||
- !lookup[0] ||
- !smoothed[0] ||
- !linear[0] ||
- config.automatic)
- {
-SET_TRACE
-// Calculate new curves
- if(config.automatic)
- {
- calculate_automatic(input);
- }
-SET_TRACE
-
-// Generate transfer tables for integer colormodels.
- for(int i = 0; i < 3; i++)
- tabulate_curve(i, 1);
-SET_TRACE
- }
-
-
-
-
-// Apply histogram
- engine->process_packages(HistogramEngine::APPLY, input);
-
-SET_TRACE
-
- return 0;
-}
-
-void HistogramMain::tabulate_curve(int subscript, int use_value)
-{
- int i;
- if(!lookup[subscript])
- lookup[subscript] = new int[HISTOGRAM_SLOTS];
- if(!smoothed[subscript])
- smoothed[subscript] = new float[HISTOGRAM_SLOTS];
- if(!linear[subscript])
- linear[subscript] = new float[HISTOGRAM_SLOTS];
-
- float *current_smooth = smoothed[subscript];
- float *current_linear = linear[subscript];
-
-// Make linear curve
- for(i = 0; i < HISTOGRAM_SLOTS; i++)
- {
- float input = (float)i / HISTOGRAM_SLOTS * FLOAT_RANGE + HIST_MIN_INPUT;
- current_linear[i] = calculate_linear(input, subscript, use_value);
- }
-
-
-
-
-
-
-// Make smooth curve
- float prev = 0.0;
- for(i = 0; i < HISTOGRAM_SLOTS; i++)
- {
-// current_smooth[i] = current_linear[i] * 0.001 +
-// prev * 0.999;
- current_smooth[i] = current_linear[i];
- prev = current_smooth[i];
- }
-
-
-// Generate lookup tables for integer colormodels
- if(input)
- {
- switch(input->get_color_model())
- {
- case BC_RGB888:
- case BC_RGBA8888:
- for(i = 0; i < 0x100; i++)
- lookup[subscript][i] =
- (int)(calculate_smooth((float)i / 0xff, subscript) * 0xff);
- break;
-// All other integer colormodels are converted to 16 bit RGB
- default:
- for(i = 0; i < 0x10000; i++)
- lookup[subscript][i] =
- (int)(calculate_smooth((float)i / 0xffff, subscript) * 0xffff);
- break;
- }
- }
-}
-
-
-
-
-
-
-
-
-
-
-
-
-HistogramPackage::HistogramPackage()
- : LoadPackage()
-{
-}
-
-
-
-
-HistogramUnit::HistogramUnit(HistogramEngine *server,
- HistogramMain *plugin)
- : LoadClient(server)
-{
- this->plugin = plugin;
- this->server = server;
- for(int i = 0; i < HISTOGRAM_MODES; i++)
- accum[i] = new int[HISTOGRAM_SLOTS];
-}
-
-HistogramUnit::~HistogramUnit()
-{
- for(int i = 0; i < HISTOGRAM_MODES; i++)
- delete [] accum[i];
-}
-
-void HistogramUnit::process_package(LoadPackage *package)
-{
- HistogramPackage *pkg = (HistogramPackage*)package;
-
- if(server->operation == HistogramEngine::HISTOGRAM)
- {
-
-#define HISTOGRAM_HEAD(type) \
-{ \
- for(int i = pkg->start; i < pkg->end; i++) \
- { \
- type *row = (type*)data->get_rows()[i]; \
- for(int j = 0; j < w; j++) \
- {
-
-#define HISTOGRAM_TAIL(components) \
-/* v = (r * 76 + g * 150 + b * 29) >> 8; */ \
- v = MAX(r, g); \
- v = MAX(v, b); \
- r += -HISTOGRAM_MIN * 0xffff / 100; \
- g += -HISTOGRAM_MIN * 0xffff / 100; \
- b += -HISTOGRAM_MIN * 0xffff / 100; \
- v += -HISTOGRAM_MIN * 0xffff / 100; \
- CLAMP(r, 0, HISTOGRAM_SLOTS); \
- CLAMP(g, 0, HISTOGRAM_SLOTS); \
- CLAMP(b, 0, HISTOGRAM_SLOTS); \
- CLAMP(v, 0, HISTOGRAM_SLOTS); \
- accum_r[r]++; \
- accum_g[g]++; \
- accum_b[b]++; \
- accum_v[v]++; \
- row += components; \
- } \
- } \
-}
-
-
-
-
- VFrame *data = server->data;
- int w = data->get_w();
- int h = data->get_h();
- int *accum_r = accum[HISTOGRAM_RED];
- int *accum_g = accum[HISTOGRAM_GREEN];
- int *accum_b = accum[HISTOGRAM_BLUE];
- int *accum_v = accum[HISTOGRAM_VALUE];
- int r, g, b, a, y, u, v;
-
- switch(data->get_color_model())
- {
- case BC_RGB888:
- HISTOGRAM_HEAD(unsigned char)
- r = (row[0] << 8) | row[0];
- g = (row[1] << 8) | row[1];
- b = (row[2] << 8) | row[2];
- HISTOGRAM_TAIL(3)
- break;
- case BC_RGB_FLOAT:
- HISTOGRAM_HEAD(float)
- r = (int)(row[0] * 0xffff);
- g = (int)(row[1] * 0xffff);
- b = (int)(row[2] * 0xffff);
- HISTOGRAM_TAIL(3)
- break;
- case BC_YUV888:
- HISTOGRAM_HEAD(unsigned char)
- y = (row[0] << 8) | row[0];
- u = (row[1] << 8) | row[1];
- v = (row[2] << 8) | row[2];
- plugin->yuv.yuv_to_rgb_16(r, g, b, y, u, v);
- HISTOGRAM_TAIL(3)
- break;
- case BC_RGBA8888:
- HISTOGRAM_HEAD(unsigned char)
- r = (row[0] << 8) | row[0];
- g = (row[1] << 8) | row[1];
- b = (row[2] << 8) | row[2];
- HISTOGRAM_TAIL(4)
- break;
- case BC_RGBA_FLOAT:
- HISTOGRAM_HEAD(float)
- r = (int)(row[0] * 0xffff);
- g = (int)(row[1] * 0xffff);
- b = (int)(row[2] * 0xffff);
- HISTOGRAM_TAIL(4)
- break;
- case BC_YUVA8888:
- HISTOGRAM_HEAD(unsigned char)
- y = (row[0] << 8) | row[0];
- u = (row[1] << 8) | row[1];
- v = (row[2] << 8) | row[2];
- plugin->yuv.yuv_to_rgb_16(r, g, b, y, u, v);
- HISTOGRAM_TAIL(4)
- break;
- case BC_RGB161616:
- HISTOGRAM_HEAD(uint16_t)
- r = row[0];
- g = row[1];
- b = row[2];
- HISTOGRAM_TAIL(3)
- break;
- case BC_YUV161616:
- HISTOGRAM_HEAD(uint16_t)
- y = row[0];
- u = row[1];
- v = row[2];
- plugin->yuv.yuv_to_rgb_16(r, g, b, y, u, v);
- HISTOGRAM_TAIL(3)
- break;
- case BC_RGBA16161616:
- HISTOGRAM_HEAD(uint16_t)
- r = row[0];
- g = row[1];
- b = row[2];
- HISTOGRAM_TAIL(3)
- break;
- case BC_YUVA16161616:
- HISTOGRAM_HEAD(uint16_t)
- y = row[0];
- u = row[1];
- v = row[2];
- plugin->yuv.yuv_to_rgb_16(r, g, b, y, u, v);
- HISTOGRAM_TAIL(4)
- break;
- }
- }
- else
- if(server->operation == HistogramEngine::APPLY)
- {
-
-
-
-#define PROCESS(type, components) \
-{ \
- for(int i = pkg->start; i < pkg->end; i++) \
- { \
- type *row = (type*)input->get_rows()[i]; \
- for(int j = 0; j < w; j++) \
- { \
- if ( plugin->config.split && ((j + i * w / h) < w) ) \
- continue; \
- row[0] = lookup_r[row[0]]; \
- row[1] = lookup_g[row[1]]; \
- row[2] = lookup_b[row[2]]; \
- row += components; \
- } \
- } \
-}
-
-#define PROCESS_YUV(type, components, max) \
-{ \
- for(int i = pkg->start; i < pkg->end; i++) \
- { \
- type *row = (type*)input->get_rows()[i]; \
- for(int j = 0; j < w; j++) \
- { \
- if ( plugin->config.split && ((j + i * w / h) < w) ) \
- continue; \
-/* Convert to 16 bit RGB */ \
- if(max == 0xff) \
- { \
- y = (row[0] << 8) | row[0]; \
- u = (row[1] << 8) | row[1]; \
- v = (row[2] << 8) | row[2]; \
- } \
- else \
- { \
- y = row[0]; \
- u = row[1]; \
- v = row[2]; \
- } \
- \
- plugin->yuv.yuv_to_rgb_16(r, g, b, y, u, v); \
- \
-/* Look up in RGB domain */ \
- r = lookup_r[r]; \
- g = lookup_g[g]; \
- b = lookup_b[b]; \
- \
-/* Convert to 16 bit YUV */ \
- plugin->yuv.rgb_to_yuv_16(r, g, b, y, u, v); \
- \
- if(max == 0xff) \
- { \
- row[0] = y >> 8; \
- row[1] = u >> 8; \
- row[2] = v >> 8; \
- } \
- else \
- { \
- row[0] = y; \
- row[1] = u; \
- row[2] = v; \
- } \
- row += components; \
- } \
- } \
-}
-
-#define PROCESS_FLOAT(components) \
-{ \
- for(int i = pkg->start; i < pkg->end; i++) \
- { \
- float *row = (float*)input->get_rows()[i]; \
- for(int j = 0; j < w; j++) \
- { \
- if ( plugin->config.split && ((j + i * w / h) < w) ) \
- continue; \
- float r = row[0]; \
- float g = row[1]; \
- float b = row[2]; \
- \
- r = plugin->calculate_smooth(r, HISTOGRAM_RED); \
- g = plugin->calculate_smooth(g, HISTOGRAM_GREEN); \
- b = plugin->calculate_smooth(b, HISTOGRAM_BLUE); \
- \
- row[0] = r; \
- row[1] = g; \
- row[2] = b; \
- \
- row += components; \
- } \
- } \
-}
-
-
- VFrame *input = plugin->input;
- VFrame *output = plugin->output;
- int w = input->get_w();
- int h = input->get_h();
- int *lookup_r = plugin->lookup[0];
- int *lookup_g = plugin->lookup[1];
- int *lookup_b = plugin->lookup[2];
- int r, g, b, y, u, v, a;
- switch(input->get_color_model())
- {
- case BC_RGB888:
- PROCESS(unsigned char, 3)
- break;
- case BC_RGB_FLOAT:
- PROCESS_FLOAT(3);
- break;
- case BC_RGBA8888:
- PROCESS(unsigned char, 4)
- break;
- case BC_RGBA_FLOAT:
- PROCESS_FLOAT(4);
- break;
- case BC_RGB161616:
- PROCESS(uint16_t, 3)
- break;
- case BC_RGBA16161616:
- PROCESS(uint16_t, 4)
- break;
- case BC_YUV888:
- PROCESS_YUV(unsigned char, 3, 0xff)
- break;
- case BC_YUVA8888:
- PROCESS_YUV(unsigned char, 4, 0xff)
- break;
- case BC_YUV161616:
- PROCESS_YUV(uint16_t, 3, 0xffff)
- break;
- case BC_YUVA16161616:
- PROCESS_YUV(uint16_t, 4, 0xffff)
- break;
- }
- }
-}
-
-
-
-
-
-
-HistogramEngine::HistogramEngine(HistogramMain *plugin,
- int total_clients,
- int total_packages)
- : LoadServer(total_clients, total_packages)
-{
- this->plugin = plugin;
-}
-
-void HistogramEngine::init_packages()
-{
- switch(operation)
- {
- case HISTOGRAM:
- total_size = data->get_h();
- break;
- case APPLY:
- total_size = data->get_h();
- break;
- }
-
-
- int package_size = (int)((float)total_size /
- get_total_packages() + 1);
- int start = 0;
-
- for(int i = 0; i < get_total_packages(); i++)
- {
- HistogramPackage *package = (HistogramPackage*)get_package(i);
- package->start = total_size * i / get_total_packages();
- package->end = total_size * (i + 1) / get_total_packages();
- }
-
-// Initialize clients here in case some don't get run.
- for(int i = 0; i < get_total_clients(); i++)
- {
- HistogramUnit *unit = (HistogramUnit*)get_client(i);
- for(int i = 0; i < HISTOGRAM_MODES; i++)
- bzero(unit->accum[i], sizeof(int) * HISTOGRAM_SLOTS);
- }
-
-}
-
-LoadClient* HistogramEngine::new_client()
-{
- return new HistogramUnit(this, plugin);
-}
-
-LoadPackage* HistogramEngine::new_package()
-{
- return new HistogramPackage;
-}
-
-void HistogramEngine::process_packages(int operation, VFrame *data)
-{
- this->data = data;
- this->operation = operation;
- LoadServer::process_packages();
-}
-
-
-
+++ /dev/null
-
-/*
- * CINELERRA
- * Copyright (C) 2008 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 HISTOGRAM_H
-#define HISTOGRAM_H
-
-
-#include "histogram.inc"
-#include "histogramconfig.h"
-#include "histogramwindow.inc"
-#include "loadbalance.h"
-#include "cicolors.h"
-#include "pluginvclient.h"
-
-enum
-{
- HISTOGRAM_LINEAR,
- HISTOGRAM_POLYNOMINAL,
- HISTOGRAM_BEZIER,
-};
-
-
-class HistogramMain : public PluginVClient
-{
-public:
- HistogramMain(PluginServer *server);
- ~HistogramMain();
-
- int process_realtime(VFrame *input_ptr, VFrame *output_ptr);
- int is_realtime();
- int load_defaults();
- int save_defaults();
- void save_data(KeyFrame *keyframe);
- void read_data(KeyFrame *keyframe);
- void update_gui();
- void render_gui(void *data);
-
- PLUGIN_CLASS_MEMBERS(HistogramConfig, HistogramThread)
-
-// Convert input to linear output
- float calculate_linear(float input, int mode, int do_value);
- float calculate_smooth(float input, int subscript);
-// Convert input to smoothed output by looking up in smooth table.
- float calculate_curve(float input);
-// Calculate automatic settings
- void calculate_automatic(VFrame *data);
-// Calculate histogram
- void calculate_histogram(VFrame *data);
-// Calculate the linear, smoothed, lookup curves
- void tabulate_curve(int subscript, int use_value);
-
-
-
- YUV yuv;
- VFrame *input, *output;
- HistogramEngine *engine;
- int *lookup[HISTOGRAM_MODES];
- float *smoothed[HISTOGRAM_MODES];
- float *linear[HISTOGRAM_MODES];
- int *accum[HISTOGRAM_MODES];
-// Input point being dragged or edited
- int current_point;
-// Current channel being viewed
- int mode;
- int dragging_point;
- int point_x_offset;
- int point_y_offset;
-};
-
-class HistogramPackage : public LoadPackage
-{
-public:
- HistogramPackage();
- int start, end;
-};
-
-class HistogramUnit : public LoadClient
-{
-public:
- HistogramUnit(HistogramEngine *server, HistogramMain *plugin);
- ~HistogramUnit();
- void process_package(LoadPackage *package);
- HistogramEngine *server;
- HistogramMain *plugin;
- int *accum[5];
-};
-
-class HistogramEngine : public LoadServer
-{
-public:
- HistogramEngine(HistogramMain *plugin,
- int total_clients,
- int total_packages);
- void process_packages(int operation, VFrame *data);
- void init_packages();
- LoadClient* new_client();
- LoadPackage* new_package();
- HistogramMain *plugin;
- int total_size;
-
-
- int operation;
- enum
- {
- HISTOGRAM,
- APPLY
- };
- VFrame *data;
-};
-
-
-
-
-
-
-
-
-
-
-
-#endif
+++ /dev/null
-
-/*
- * CINELERRA
- * Copyright (C) 2008 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 HISTOGRAM_INC
-#define HISTOGRAM_INC
-
-
-
-
-
-// modes
-#define HISTOGRAM_MODES 4
-#define HISTOGRAM_RED 0
-#define HISTOGRAM_GREEN 1
-#define HISTOGRAM_BLUE 2
-#define HISTOGRAM_VALUE 3
-
-// Number of divisions in histogram.
-// 65536 + min and max range to speed up the tabulation
-#define HISTOGRAM_SLOTS 0x13333
-#define FLOAT_RANGE 1.2
-// Minimum value in percentage
-#define HISTOGRAM_MIN -10
-#define HIST_MIN_INPUT -0.1
-// Maximum value in percentage
-#define HISTOGRAM_MAX 110
-#define HIST_MAX_INPUT 1.1
-
-#define PRECISION 0.001
-#define DIGITS 3
-#define THRESHOLD_SCALE 1000
-
-#define BOX_SIZE 10
-
-
-class HistogramEngine;
-class HistogramMain;
-
-
-#endif
+++ /dev/null
-
-/*
- * CINELERRA
- * Copyright (C) 2008 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 "histogramconfig.h"
-#include "units.h"
-
-#include <math.h>
-
-
-
-
-HistogramPoint::HistogramPoint()
- : ListItem<HistogramPoint>()
-{
-}
-
-HistogramPoint::~HistogramPoint()
-{
-}
-
-int HistogramPoint::equivalent(HistogramPoint *src)
-{
- return EQUIV(x, src->x) && EQUIV(y, src->y) && EQUIV(gradient, src->gradient);
-}
-
-
-
-
-HistogramPoints::HistogramPoints()
- : List<HistogramPoint>()
-{
- insert(0.0,0.0);
- first->gradient = 1.0;
- first->xoffset_left = 0.0;
- first->xoffset_right = 0.05;
- insert(1.0,1.0);
- last->gradient = 1.0;
- last->xoffset_left = -0.05;
- last->xoffset_right = 0.0;
-
-}
-
-HistogramPoints::~HistogramPoints()
-{
-}
-
-HistogramPoint* HistogramPoints::insert(float x, float y)
-{
- HistogramPoint *current = first;
-
-// Get existing point after new point
- while(current)
- {
- if(current->x > x)
- break;
- else
- current = NEXT;
- }
-
-// Insert new point before current point
- HistogramPoint *new_point = new HistogramPoint;
- if(current)
- {
- insert_before(current, new_point);
- }
- else
-// Append new point to list
- {
- append(new_point);
- }
-
- new_point->x = x;
- new_point->y = y;
- new_point->xoffset_left = -0.05;
- new_point->xoffset_right = 0.05;
-
-
- return new_point;
-}
-
-void HistogramPoints::boundaries()
-{
- HistogramPoint *current = first;
- while(current)
- {
- CLAMP(current->x, 0.0, 1.0);
- CLAMP(current->y, 0.0, 1.0);
- current = NEXT;
- }
-}
-
-int HistogramPoints::equivalent(HistogramPoints *src)
-{
- HistogramPoint *current_this = first;
- HistogramPoint *current_src = src->first;
- while(current_this && current_src)
- {
- if(!current_this->equivalent(current_src)) return 0;
- current_this = current_this->next;
- current_src = current_src->next;
- }
-
- if(!current_this && current_src ||
- current_this && !current_src)
- return 0;
- return 1;
-}
-
-void HistogramPoints::copy_from(HistogramPoints *src)
-{
- while(last)
- delete last;
- HistogramPoint *current = src->first;
- while(current)
- {
- HistogramPoint *new_point = new HistogramPoint;
- new_point->x = current->x;
- new_point->y = current->y;
- append(new_point);
- current = NEXT;
- }
-}
-
-void HistogramPoints::interpolate(HistogramPoints *prev,
- HistogramPoints *next,
- double prev_scale,
- double next_scale)
-{
- HistogramPoint *current = first;
- HistogramPoint *current_prev = prev->first;
- HistogramPoint *current_next = next->first;
-
- while(current && current_prev && current_next)
- {
- current->x = current_prev->x * prev_scale +
- current_next->x * next_scale;
- current->y = current_prev->y * prev_scale +
- current_next->y * next_scale;
- current = NEXT;
- current_prev = current_prev->next;
- current_next = current_next->next;
- }
-}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-HistogramConfig::HistogramConfig()
-{
- reset(1);
-}
-
-void HistogramConfig::reset(int do_mode)
-{
- reset_points();
-
-
- for(int i = 0; i < HISTOGRAM_MODES; i++)
- {
- output_min[i] = 0.0;
- output_max[i] = 1.0;
- }
-
- if(do_mode)
- {
- automatic = 0;
- threshold = 0.1;
- split = 0;
- smoothMode = 0;
- }
-}
-
-void HistogramConfig::reset_points()
-{
- for(int i = 0; i < HISTOGRAM_MODES; i++)
- {
- while(points[i].last) delete points[i].last;
- points[i].insert(0.0,0.0);
- points[i].last->gradient = 1.0;
- points[i].insert(1.0,1.0);
- points[i].last->gradient = 1.0;
- }
-}
-
-
-void HistogramConfig::boundaries()
-{
- for(int i = 0; i < HISTOGRAM_MODES; i++)
- {
- points[i].boundaries();
- CLAMP(output_min[i], HIST_MIN_INPUT, HIST_MAX_INPUT);
- CLAMP(output_max[i], HIST_MIN_INPUT, HIST_MAX_INPUT);
- output_min[i] = Units::quantize(output_min[i], PRECISION);
- output_max[i] = Units::quantize(output_max[i], PRECISION);
- }
- CLAMP(threshold, 0, 1);
-}
-
-int HistogramConfig::equivalent(HistogramConfig &that)
-{
- for(int i = 0; i < HISTOGRAM_MODES; i++)
- {
- if(!points[i].equivalent(&that.points[i]) ||
- !EQUIV(output_min[i], that.output_min[i]) ||
- !EQUIV(output_max[i], that.output_max[i])) return 0;
- }
-
- if(automatic != that.automatic ||
- !EQUIV(threshold, that.threshold)) return 0;
-
- return 1;
-}
-
-void HistogramConfig::copy_from(HistogramConfig &that)
-{
- for(int i = 0; i < HISTOGRAM_MODES; i++)
- {
- points[i].copy_from(&that.points[i]);
- output_min[i] = that.output_min[i];
- output_max[i] = that.output_max[i];
- }
-
- automatic = that.automatic;
- threshold = that.threshold;
- split = that.split;
- smoothMode = that.smoothMode;
-}
-
-void HistogramConfig::interpolate(HistogramConfig &prev,
- HistogramConfig &next,
- int64_t prev_frame,
- int64_t next_frame,
- int64_t current_frame)
-{
- double next_scale = (double)(current_frame - prev_frame) / (next_frame - prev_frame);
- double prev_scale = 1.0 - next_scale;
-
- for(int i = 0; i < HISTOGRAM_MODES; i++)
- {
- points[i].interpolate(&prev.points[i], &next.points[i], next_scale, prev_scale);
- output_min[i] = prev.output_min[i] * prev_scale + next.output_min[i] * next_scale;
- output_max[i] = prev.output_max[i] * prev_scale + next.output_max[i] * next_scale;
- }
-
- threshold = prev.threshold * prev_scale + next.threshold * next_scale;
- automatic = prev.automatic;
- split = prev.split;
- smoothMode = prev.smoothMode;
-}
-
-
-void HistogramConfig::dump()
-{
- for(int j = 0; j < HISTOGRAM_MODES; j++)
- {
- printf("HistogramConfig::dump mode=%d\n", j);
- HistogramPoints *points = &this->points[j];
- HistogramPoint *current = points->first;
- while(current)
- {
- printf("%f,%f ", current->x, current->y);
- fflush(stdout);
- current = NEXT;
- }
- printf("\n");
- }
-}
-
-
-
+++ /dev/null
-
-/*
- * CINELERRA
- * Copyright (C) 2008 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 HISTOGRAMCONFIG_H
-#define HISTOGRAMCONFIG_H
-
-
-#include "histogram.inc"
-#include "histogramconfig.inc"
-#include "linklist.h"
-#include <stdint.h>
-
-class HistogramPoint : public ListItem<HistogramPoint>
-{
-public:
- HistogramPoint();
- ~HistogramPoint();
-
- int equivalent(HistogramPoint *src);
- float x, y;
- float gradient;
- float xoffset_left;
- float xoffset_right;
-};
-
-
-class HistogramPoints : public List<HistogramPoint>
-{
-public:
- HistogramPoints();
- ~HistogramPoints();
-
-// Insert new point
- HistogramPoint* insert(float x, float y);
- int equivalent(HistogramPoints *src);
- void boundaries();
- void copy_from(HistogramPoints *src);
- void interpolate(HistogramPoints *prev,
- HistogramPoints *next,
- double prev_scale,
- double next_scale);
-};
-
-class HistogramConfig
-{
-public:
- HistogramConfig();
-
- int equivalent(HistogramConfig &that);
- void copy_from(HistogramConfig &that);
- void interpolate(HistogramConfig &prev,
- HistogramConfig &next,
- int64_t prev_frame,
- int64_t next_frame,
- int64_t current_frame);
-// Used by constructor and reset button
- void reset(int do_mode);
- void reset_points();
- void boundaries();
- void dump();
-
-// Range 0 - 1.0
-// Input points
- HistogramPoints points[HISTOGRAM_MODES];
-// Output points
- float output_min[HISTOGRAM_MODES];
- float output_max[HISTOGRAM_MODES];
- int automatic;
- float threshold;
- int split;
- int smoothMode;
-};
-
-
-#endif
-
-
-
+++ /dev/null
-
-/*
- * CINELERRA
- * Copyright (C) 2008 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 HISTOGRAMCONFIG_INC
-#define HISTOGRAMCONFIG_INC
-
-
-class HistogramPoint;
-class HistogramPoints;
-class HistogramConfig;
-
-
-#endif
+++ /dev/null
-
-/*
- * CINELERRA
- * Copyright (C) 2008 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 "bcsignals.h"
-#include "histogram.h"
-#include "histogramconfig.h"
-#include "histogramwindow.h"
-#include "keys.h"
-#include "language.h"
-
-
-#include <unistd.h>
-#include <string.h>
-
-PLUGIN_THREAD_OBJECT(HistogramMain, HistogramThread, HistogramWindow)
-
-
-
-HistogramWindow::HistogramWindow(HistogramMain *plugin, int x, int y)
- : BC_Window(plugin->gui_string,
- x,
- y,
- 440,
- 480,
- 440,
- 480,
- 0,
- 1,
- 1)
-{
- this->plugin = plugin;
-}
-
-HistogramWindow::~HistogramWindow()
-{
-}
-
-static VFrame max_picon_image(max_picon_png);
-static VFrame mid_picon_image(mid_picon_png);
-static VFrame min_picon_image(min_picon_png);
-
-int HistogramWindow::create_objects()
-{
- int x = 10, y = 10, x1 = 10;
- BC_Title *title = 0;
-
- max_picon = new BC_Pixmap(this, &max_picon_image);
- mid_picon = new BC_Pixmap(this, &mid_picon_image);
- min_picon = new BC_Pixmap(this, &min_picon_image);
- add_subwindow(mode_v = new HistogramMode(plugin,
- x,
- y,
- HISTOGRAM_VALUE,
- _("Value")));
- x += 70;
- add_subwindow(mode_r = new HistogramMode(plugin,
- x,
- y,
- HISTOGRAM_RED,
- _("Red")));
- x += 70;
- add_subwindow(mode_g = new HistogramMode(plugin,
- x,
- y,
- HISTOGRAM_GREEN,
- _("Green")));
- x += 70;
- add_subwindow(mode_b = new HistogramMode(plugin,
- x,
- y,
- HISTOGRAM_BLUE,
- _("Blue")));
-// x += 70;
-// add_subwindow(mode_a = new HistogramMode(plugin,
-// x,
-// y,
-// HISTOGRAM_ALPHA,
-// _("Alpha")));
-
- x = x1;
- y += 30;
- add_subwindow(title = new BC_Title(x, y, _("Input X:")));
- x += title->get_w() + 10;
- input_x = new HistogramInputText(plugin,
- this,
- x,
- y,
- 1);
- input_x->create_objects();
-
- x += input_x->get_w() + 10;
- add_subwindow(title = new BC_Title(x, y, _("Input Y:")));
- x += title->get_w() + 10;
- input_y = new HistogramInputText(plugin,
- this,
- x,
- y,
- 0);
- input_y->create_objects();
-
- y += 30;
- x = x1;
-
- canvas_w = get_w() - x - x;
- canvas_h = get_h() - y - 170;
- title1_x = x;
- title2_x = x + (int)(canvas_w * -HIST_MIN_INPUT / FLOAT_RANGE);
- title3_x = x + (int)(canvas_w * (1.0 - HIST_MIN_INPUT) / FLOAT_RANGE);
- title4_x = x + (int)(canvas_w);
- add_subwindow(canvas = new HistogramCanvas(plugin,
- this,
- x,
- y,
- canvas_w,
- canvas_h));
- draw_canvas_overlay();
- canvas->flash();
-
- y += canvas->get_h() + 1;
- add_subwindow(new BC_Title(title1_x,
- y,
- "-10%"));
- add_subwindow(new BC_Title(title2_x,
- y,
- "0%"));
- add_subwindow(new BC_Title(title3_x - get_text_width(MEDIUMFONT, "100"),
- y,
- "100%"));
- add_subwindow(new BC_Title(title4_x - get_text_width(MEDIUMFONT, "110"),
- y,
- "110%"));
-
- y += 20;
- add_subwindow(title = new BC_Title(x, y, _("Output min:")));
- x += title->get_w() + 10;
- output_min = new HistogramOutputText(plugin,
- this,
- x,
- y,
- &plugin->config.output_min[plugin->mode]);
- output_min->create_objects();
- x += output_min->get_w() + 10;
- add_subwindow(new BC_Title(x, y, _("Output Max:")));
- x += title->get_w() + 10;
- output_max = new HistogramOutputText(plugin,
- this,
- x,
- y,
- &plugin->config.output_max[plugin->mode]);
- output_max->create_objects();
-
- x = x1;
- y += 30;
-
- add_subwindow(output = new HistogramSlider(plugin,
- this,
- x,
- y,
- get_w() - 20,
- 30,
- 0));
- output->update();
- y += 40;
-
-
- add_subwindow(automatic = new HistogramAuto(plugin,
- x,
- y));
-
- x += 120;
- add_subwindow(new HistogramReset(plugin,
- x,
- y));
- x += 100;
- add_subwindow(new BC_Title(x, y, _("Threshold:")));
- x += 100;
- threshold = new HistogramOutputText(plugin,
- this,
- x,
- y,
- &plugin->config.threshold);
- threshold->create_objects();
- x = x1;
- y += 40;
- add_subwindow(split = new HistogramSplit(plugin, x, y));
- y += 6;
- x += 150;
- add_subwindow(new BC_Title(x,y, _("Interpolation:")));
- x += 120;
- add_subwindow(smoothModeChoser = new HistogramSmoothMode(plugin, this, x, y));
- smoothModeChoser->create_objects();
-
- show_window();
-
- return 0;
-}
-
-WINDOW_CLOSE_EVENT(HistogramWindow)
-
-int HistogramWindow::keypress_event()
-{
- int result = 0;
- if(get_keypress() == BACKSPACE ||
- get_keypress() == DELETE)
- {
- if(plugin->current_point >= 0)
- {
- HistogramPoint *current =
- plugin->config.points[plugin->mode].get_item_number(plugin->current_point);
- delete current;
- plugin->current_point = -1;
- update_input();
- update_canvas();
- plugin->send_configure_change();
- result = 1;
- }
- }
- return result;
-}
-
-void HistogramWindow::update(int do_input)
-{
- automatic->update(plugin->config.automatic);
- threshold->update(plugin->config.threshold);
- update_mode();
-
- if(do_input) update_input();
- update_output();
-}
-
-void HistogramWindow::update_input()
-{
- input_x->update();
- input_y->update();
-}
-
-void HistogramWindow::update_output()
-{
- output->update();
- output_min->update(plugin->config.output_min[plugin->mode]);
- output_max->update(plugin->config.output_max[plugin->mode]);
-}
-
-void HistogramWindow::update_mode()
-{
- mode_v->update(plugin->mode == HISTOGRAM_VALUE ? 1 : 0);
- mode_r->update(plugin->mode == HISTOGRAM_RED ? 1 : 0);
- mode_g->update(plugin->mode == HISTOGRAM_GREEN ? 1 : 0);
- mode_b->update(plugin->mode == HISTOGRAM_BLUE ? 1 : 0);
- output_min->output = &plugin->config.output_min[plugin->mode];
- output_max->output = &plugin->config.output_max[plugin->mode];
-}
-
-void HistogramWindow::draw_canvas_overlay()
-{
- canvas->set_color(0x00ff00);
- int y1;
-
-// Calculate output curve
- plugin->tabulate_curve(plugin->mode, 0);
-
-// Draw output line
- for(int i = 0; i < canvas_w; i++)
- {
- float input = (float)i /
- canvas_w *
- FLOAT_RANGE +
- HIST_MIN_INPUT;
- float output = plugin->calculate_smooth(input, plugin->mode);
-
- int y2 = canvas_h - (int)(output * canvas_h);
- if(i > 0)
- {
- canvas->draw_line(i - 1, y1, i, y2);
- }
- y1 = y2;
- }
-
-// Draw output points
- HistogramPoint *current = plugin->config.points[plugin->mode].first;
- int number = 0;
- while(current)
- {
- int x = (int)((current->x - HIST_MIN_INPUT) * canvas_w / FLOAT_RANGE);
- int y = (int)(canvas_h - current->y * canvas_h);
- if(number == plugin->current_point)
- canvas->draw_box(x - BOX_SIZE / 2, y - BOX_SIZE / 2, BOX_SIZE, BOX_SIZE);
- else
- canvas->draw_rectangle(x - BOX_SIZE / 2, y - BOX_SIZE / 2, BOX_SIZE, BOX_SIZE);
-
-//Draw gradients
- if (plugin->config.smoothMode > HISTOGRAM_LINEAR)
- {
- int x1,x2,y1,y2;
- canvas->set_color(0x0000ff);
- x2 = (int)((current->x + current->xoffset_right - HIST_MIN_INPUT) * canvas_w / FLOAT_RANGE);
- x1 = (int)((current->x + current->xoffset_left - HIST_MIN_INPUT) * canvas_w / FLOAT_RANGE);
- y2 = (int)(canvas_h - (current->y + current->xoffset_right * current->gradient) * canvas_h);
- y1 = (int)(canvas_h - (current->y + current->xoffset_left * current->gradient) * canvas_h);
-/* x2 = x + (title3_x - title2_x)/20;
- x1 = x - (title3_x - title2_x)/20;
- y1 = y + (int)(current->gradient * (float)(canvas_h)/20.0);
- y2 = y - (int)(current->gradient * (float)(canvas_h)/20.0);
-// int y2 = (int)(canvas_h - canvas_h * (current->y + current->gradient /10));*/
- canvas->draw_line(x1,y1,x2,y2);
-
- canvas->draw_circle(x1 - BOX_SIZE / 4, y1 - BOX_SIZE / 4, BOX_SIZE/2, BOX_SIZE/2);
- canvas->draw_circle(x2 - BOX_SIZE / 4, y2 - BOX_SIZE / 4, BOX_SIZE/2, BOX_SIZE/2);
- canvas->set_color(0x00ff00);
- }
-
- current = NEXT;
- number++;
- }
-
-
-// Draw 0 and 100% lines.
- canvas->set_color(0xff0000);
- canvas->draw_line(title2_x - canvas->get_x(),
- 0,
- title2_x - canvas->get_x(),
- canvas_h);
- canvas->draw_line(title3_x - canvas->get_x(),
- 0,
- title3_x - canvas->get_x(),
- canvas_h);
-}
-
-void HistogramWindow::update_canvas()
-{
- int *accum = plugin->accum[plugin->mode];
- int accum_per_canvas_i = HISTOGRAM_SLOTS / canvas_w + 1;
- float accum_per_canvas_f = (float)HISTOGRAM_SLOTS / canvas_w;
- int normalize = 0;
- int max = 0;
-
- for(int i = 0; i < HISTOGRAM_SLOTS; i++)
- {
- if(accum && accum[i] > normalize) normalize = accum[i];
- }
-
-
- if(normalize)
- {
- for(int i = 0; i < canvas_w; i++)
- {
- int accum_start = (int)(accum_per_canvas_f * i);
- int accum_end = accum_start + accum_per_canvas_i;
- max = 0;
- for(int j = accum_start; j < accum_end; j++)
- {
- max = MAX(accum[j], max);
- }
-
-// max = max * canvas_h / normalize;
- max = (int)(log(max) / log(normalize) * canvas_h);
-
- canvas->set_color(0xffffff);
- canvas->draw_line(i, 0, i, canvas_h - max);
- canvas->set_color(0x000000);
- canvas->draw_line(i, canvas_h - max, i, canvas_h);
- }
- }
- else
- {
- canvas->set_color(0xffffff);
- canvas->draw_box(0, 0, canvas_w, canvas_h);
- }
-
-
- draw_canvas_overlay();
- canvas->flash();
-}
-
-
-
-
-
-
-
-
-HistogramCanvas::HistogramCanvas(HistogramMain *plugin,
- HistogramWindow *gui,
- int x,
- int y,
- int w,
- int h)
- : BC_SubWindow(x,
- y,
- w,
- h,
- 0xffffff)
-{
- this->plugin = plugin;
- this->gui = gui;
-}
-
-int HistogramCanvas::button_press_event()
-{
- int result = 0;
- if(is_event_win() && cursor_inside())
- {
- if(!plugin->dragging_point)
- {
- HistogramPoint *new_point = 0;
- gui->deactivate();
-// Search for existing point under cursor
- HistogramPoint *current = plugin->config.points[plugin->mode].first;
- plugin->current_point = -1;
- int dragID = 0;
- while(current)
- {
- int x = (int)((current->x - HIST_MIN_INPUT) * gui->canvas_w / FLOAT_RANGE);
- int y = (int)(gui->canvas_h - current->y * gui->canvas_h);
-
-/* Check for click on main point */
- if(get_cursor_x() >= x - BOX_SIZE / 2 &&
- get_cursor_y() >= y - BOX_SIZE / 2 &&
- get_cursor_x() < x + BOX_SIZE / 2 &&
- get_cursor_y() < y + BOX_SIZE / 2)
- {
- plugin->current_point =
- plugin->config.points[plugin->mode].number_of(current);
- plugin->point_x_offset = get_cursor_x() - x;
- plugin->point_y_offset = get_cursor_y() - y;
- dragID = 1;
- break;
- }
- if (plugin->config.smoothMode == HISTOGRAM_LINEAR)
- break;
-
- int xright =
- (int)((current->x + current->xoffset_right - HIST_MIN_INPUT) * gui->canvas_w / FLOAT_RANGE);
- int yright =
- (int)(gui->canvas_h - (current->y + current->xoffset_right * current->gradient) *
- gui->canvas_h);
-
-/* Check for click on right handle */
- if(get_cursor_x() >= xright - BOX_SIZE / 2 &&
- get_cursor_y() >= yright - BOX_SIZE / 2 &&
- get_cursor_x() < xright + BOX_SIZE / 2 &&
- get_cursor_y() < yright + BOX_SIZE / 2)
- {
- plugin->current_point =
- plugin->config.points[plugin->mode].number_of(current);
- plugin->point_x_offset = get_cursor_x() - xright;
- plugin->point_y_offset = get_cursor_y() - yright;
- dragID = 2;
- break;
- }
-
-/* Check for click on left handle */
- int xleft =
- (int)((current->x + current->xoffset_left - HIST_MIN_INPUT) * gui->canvas_w / FLOAT_RANGE);
- int yleft =
- (int)(gui->canvas_h - (current->y + current->xoffset_left * current->gradient) *
- gui->canvas_h);
- if(get_cursor_x() >= xleft - BOX_SIZE / 2 &&
- get_cursor_y() >= yleft - BOX_SIZE / 2 &&
- get_cursor_x() < xleft + BOX_SIZE / 2 &&
- get_cursor_y() < yleft + BOX_SIZE / 2)
- {
- plugin->current_point =
- plugin->config.points[plugin->mode].number_of(current);
- plugin->point_x_offset = get_cursor_x() - xleft;
- plugin->point_y_offset = get_cursor_y() - yleft;
- dragID = 3;
- break;
- }
-
-
- current = NEXT;
- }
-
- if(plugin->current_point < 0)
- {
-// Create new point under cursor
- float current_x = (float)get_cursor_x() *
- FLOAT_RANGE /
- get_w() +
- HIST_MIN_INPUT;
- float current_y = 1.0 -
- (float)get_cursor_y() /
- get_h();
- new_point =
- plugin->config.points[plugin->mode].insert(current_x, current_y);
- plugin->current_point =
- plugin->config.points[plugin->mode].number_of(new_point);
- plugin->point_x_offset = 0;
- plugin->point_y_offset = 0;
-
-// Default gradient
-// Get 2 points surrounding current position
- float x1,x2,y1,y2;
-
- HistogramPoint *current = plugin->config.points[plugin->mode].first;
- int done = 0;
- while(current && !done)
- {
- if(current->x > current_x)
- {
- x2 = current->x;
- y2 = current->y;
- done = 1;
- }
- else
- current = NEXT;
- }
-
- current = plugin->config.points[plugin->mode].last;
- done = 0;
- while(current && !done)
- {
- if(current->x <= current_x)
- {
- x1 = current->x;
- y1 = current->y;
- done = 1;
- }
- else
- current = PREVIOUS;
- }
- new_point->gradient = (y2 - y1) / (x2 - x1);
- dragID = 1;
-
- }
-
-
- plugin->dragging_point = dragID;
- result = 1;
-
- plugin->config.boundaries();
- gui->update_input();
- gui->update_canvas();
- if(new_point)
- {
- plugin->send_configure_change();
- }
- }
- }
- return result;
-}
-
-int HistogramCanvas::cursor_motion_event()
-{
- if(plugin->dragging_point)
- {
- HistogramPoint * current_point = plugin->config.points[plugin->mode].get_item_number(plugin->current_point);
-
- float current_x =
- (float)(get_cursor_x() - plugin->point_x_offset) *
- FLOAT_RANGE /
- get_w() +
- HIST_MIN_INPUT;
- float current_y = 1.0 -
- (float)(get_cursor_y() - plugin->point_y_offset) /
- get_h();
-
- switch(plugin->dragging_point)
- {
- case 1: /* Main point dragged */
- current_point->x = current_x;
- current_point->y = current_y;
- break;
- case 2: /* Right control point dragged */
- if (current_x - current_point->x > 0)
- {
- current_point->xoffset_right = current_x - current_point->x;
- current_point->gradient = (current_y - current_point->y) / (current_x - current_point->x);
- }
- break;
- case 3: /* Left control point dragged */
- if (current_x - current_point->x < 0)
- {
- current_point->xoffset_left = current_x - current_point->x;
- current_point->gradient = (current_point->y - current_y) / (current_point->x - current_x);
- }
- break;
- }
-
- plugin->config.boundaries();
- gui->update_input();
- gui->update_canvas();
- plugin->send_configure_change();
- return 1;
- }
- return 0;
-}
-
-int HistogramCanvas::button_release_event()
-{
- if(plugin->dragging_point)
- {
-// Test for out of order points to delete.
- HistogramPoint *current =
- plugin->config.points[plugin->mode].get_item_number(plugin->current_point);
- HistogramPoint *prev = PREVIOUS;
- HistogramPoint *next = NEXT;
-
- if((prev && prev->x >= current->x) ||
- (next && next->x <= current->x))
- {
- delete current;
- plugin->current_point = -1;
- plugin->config.boundaries();
- gui->update_input();
- gui->update_canvas();
- plugin->send_configure_change();
- }
-
- plugin->dragging_point = 0;
- }
- return 0;
-}
-
-
-
-
-
-
-
-HistogramReset::HistogramReset(HistogramMain *plugin,
- int x,
- int y)
- : BC_GenericButton(x, y, _("Reset"))
-{
- this->plugin = plugin;
-}
-int HistogramReset::handle_event()
-{
- plugin->config.reset(0);
- plugin->thread->window->update(1);
- plugin->thread->window->update_canvas();
- plugin->send_configure_change();
- return 1;
-}
-
-
-
-
-
-
-
-
-
-HistogramSlider::HistogramSlider(HistogramMain *plugin,
- HistogramWindow *gui,
- int x,
- int y,
- int w,
- int h,
- int is_input)
- : BC_SubWindow(x, y, w, h)
-{
- this->plugin = plugin;
- this->gui = gui;
- this->is_input = is_input;
- operation = NONE;
-}
-
-int HistogramSlider::input_to_pixel(float input)
-{
- return (int)((input - HIST_MIN_INPUT) / FLOAT_RANGE * get_w());
-}
-
-int HistogramSlider::button_press_event()
-{
- if(is_event_win() && cursor_inside())
- {
- int min;
- int max;
- int w = get_w();
- int h = get_h();
- int half_h = get_h() / 2;
-
- gui->deactivate();
-
- if(operation == NONE)
- {
- int x1 = input_to_pixel(plugin->config.output_min[plugin->mode]) -
- gui->mid_picon->get_w() / 2;
- int x2 = x1 + gui->mid_picon->get_w();
- if(get_cursor_x() >= x1 && get_cursor_x() < x2 &&
- get_cursor_y() >= half_h && get_cursor_y() < h)
- {
- operation = DRAG_MIN_OUTPUT;
- }
- }
-
- if(operation == NONE)
- {
- int x1 = input_to_pixel(plugin->config.output_max[plugin->mode]) -
- gui->mid_picon->get_w() / 2;
- int x2 = x1 + gui->mid_picon->get_w();
- if(get_cursor_x() >= x1 && get_cursor_x() < x2 &&
- get_cursor_y() >= half_h && get_cursor_y() < h)
- {
- operation = DRAG_MAX_OUTPUT;
- }
- }
- return 1;
- }
- return 0;
-}
-
-int HistogramSlider::button_release_event()
-{
- if(operation != NONE)
- {
- operation = NONE;
- return 1;
- }
- return 0;
-}
-
-int HistogramSlider::cursor_motion_event()
-{
- if(operation != NONE)
- {
- float value = (float)get_cursor_x() / get_w() * FLOAT_RANGE + HIST_MIN_INPUT;
- CLAMP(value, HIST_MIN_INPUT, HIST_MAX_INPUT);
-
- switch(operation)
- {
- case DRAG_MIN_OUTPUT:
- value = MIN(plugin->config.output_max[plugin->mode], value);
- plugin->config.output_min[plugin->mode] = value;
- break;
- case DRAG_MAX_OUTPUT:
- value = MAX(plugin->config.output_min[plugin->mode], value);
- plugin->config.output_max[plugin->mode] = value;
- break;
- }
-
- plugin->config.boundaries();
- gui->update_output();
-
- plugin->send_configure_change();
- return 1;
- }
- return 0;
-}
-
-void HistogramSlider::update()
-{
- int w = get_w();
- int h = get_h();
- int half_h = get_h() / 2;
- int quarter_h = get_h() / 4;
- int mode = plugin->mode;
- int r = 0xff;
- int g = 0xff;
- int b = 0xff;
-
- clear_box(0, 0, w, h);
-
- switch(mode)
- {
- case HISTOGRAM_RED:
- g = b = 0x00;
- break;
- case HISTOGRAM_GREEN:
- r = b = 0x00;
- break;
- case HISTOGRAM_BLUE:
- r = g = 0x00;
- break;
- }
-
- for(int i = 0; i < w; i++)
- {
- int color = (int)(i * 0xff / w);
- set_color(((r * color / 0xff) << 16) |
- ((g * color / 0xff) << 8) |
- (b * color / 0xff));
-
- draw_line(i, 0, i, half_h);
- }
-
- float min;
- float max;
- min = plugin->config.output_min[plugin->mode];
- max = plugin->config.output_max[plugin->mode];
-
- draw_pixmap(gui->min_picon,
- input_to_pixel(min) - gui->min_picon->get_w() / 2,
- half_h + 1);
- draw_pixmap(gui->max_picon,
- input_to_pixel(max) - gui->max_picon->get_w() / 2,
- half_h + 1);
-
- flash();
- flush();
-}
-
-
-
-
-
-
-
-
-
-HistogramAuto::HistogramAuto(HistogramMain *plugin,
- int x,
- int y)
- : BC_CheckBox(x, y, plugin->config.automatic, _("Automatic"))
-{
- this->plugin = plugin;
-}
-
-int HistogramAuto::handle_event()
-{
- plugin->config.automatic = get_value();
- plugin->send_configure_change();
- return 1;
-}
-
-
-
-
-HistogramSplit::HistogramSplit(HistogramMain *plugin,
- int x,
- int y)
- : BC_CheckBox(x, y, plugin->config.split, _("Split picture"))
-{
- this->plugin = plugin;
-}
-
-int HistogramSplit::handle_event()
-{
- plugin->config.split = get_value();
- plugin->send_configure_change();
- return 1;
-}
-
-
-
-
-HistogramMode::HistogramMode(HistogramMain *plugin,
- int x,
- int y,
- int value,
- char *text)
- : BC_Radial(x, y, plugin->mode == value, text)
-{
- this->plugin = plugin;
- this->value = value;
-}
-int HistogramMode::handle_event()
-{
- plugin->mode = value;
- plugin->current_point= -1;
- plugin->thread->window->update_canvas();
- plugin->thread->window->update_mode();
- plugin->thread->window->update_input();
- plugin->thread->window->update_canvas();
- plugin->thread->window->update_output();
- plugin->thread->window->output->update();
-// plugin->send_configure_change();
- return 1;
-}
-
-
-
-
-
-
-
-
-
-HistogramOutputText::HistogramOutputText(HistogramMain *plugin,
- HistogramWindow *gui,
- int x,
- int y,
- float *output)
- : BC_TumbleTextBox(gui,
- output ? (float)*output : 0.0,
- (float)HIST_MIN_INPUT,
- (float)HIST_MAX_INPUT,
- x,
- y,
- 60)
-{
- this->plugin = plugin;
- this->output = output;
- set_precision(DIGITS);
- set_increment(PRECISION);
-}
-
-
-int HistogramOutputText::handle_event()
-{
- if(output)
- {
- *output = atof(get_text());
- }
-
- plugin->thread->window->output->update();
- plugin->send_configure_change();
- return 1;
-}
-
-
-
-
-
-
-
-
-HistogramInputText::HistogramInputText(HistogramMain *plugin,
- HistogramWindow *gui,
- int x,
- int y,
- int do_x)
- : BC_TumbleTextBox(gui,
- 0.0,
- (float)HIST_MIN_INPUT,
- (float)HIST_MAX_INPUT,
- x,
- y,
- 60)
-{
- this->do_x = do_x;
- this->plugin = plugin;
- this->gui = gui;
- set_precision(DIGITS);
- set_increment(PRECISION);
-}
-
-
-int HistogramInputText::handle_event()
-{
- if(plugin->current_point >= 0 &&
- plugin->current_point < plugin->config.points[plugin->mode].total())
- {
- HistogramPoint *point =
- plugin->config.points[plugin->mode].get_item_number(
- plugin->current_point);
-
- if(point)
- {
- if(do_x)
- point->x = atof(get_text());
- else
- point->y = atof(get_text());
-
- plugin->config.boundaries();
- gui->update_canvas();
-
- plugin->thread->window->output->update();
- plugin->send_configure_change();
- }
- }
- return 1;
-}
-
-void HistogramInputText::update()
-{
- if(plugin->current_point >= 0 &&
- plugin->current_point < plugin->config.points[plugin->mode].total())
- {
- HistogramPoint *point =
-
- plugin->config.points[plugin->mode].get_item_number(
- plugin->current_point);
-
- if(point)
- {
- if(do_x)
- BC_TumbleTextBox::update(point->x);
- else
- BC_TumbleTextBox::update(point->y);
- }
- else
- {
- BC_TumbleTextBox::update((float)0.0);
- }
- }
- else
- {
- BC_TumbleTextBox::update((float)0.0);
- }
-
-}
-
-
-HistogramSmoothMode::HistogramSmoothMode(HistogramMain*plugin,
- HistogramWindow *gui,
- int x,
- int y)
- : BC_PopupMenu(x, y, 120, to_text(plugin->config.smoothMode), 1)
-{
- this->plugin = plugin;
- this->gui = gui;
-}
-void HistogramSmoothMode::create_objects()
-{
- add_item(new BC_MenuItem(to_text(HISTOGRAM_LINEAR)));
- add_item(new BC_MenuItem(to_text(HISTOGRAM_POLYNOMINAL)));
- add_item(new BC_MenuItem(to_text(HISTOGRAM_BEZIER)));
-}
-
-char* HistogramSmoothMode::to_text(int mode)
-{
- switch(mode)
- {
- case HISTOGRAM_LINEAR:
- return _("Linear");
- case HISTOGRAM_POLYNOMINAL:
- return _("Polynominal");
- case HISTOGRAM_BEZIER:
- return _("Bezier");
- }
-}
-int HistogramSmoothMode::from_text(char *text)
-{
- if(!strcmp(text, to_text(HISTOGRAM_LINEAR)))
- return HISTOGRAM_LINEAR;
- if(!strcmp(text, to_text(HISTOGRAM_POLYNOMINAL)))
- return HISTOGRAM_POLYNOMINAL;
- if(!strcmp(text, to_text(HISTOGRAM_BEZIER)))
- return HISTOGRAM_BEZIER;
-}
-
-int HistogramSmoothMode::handle_event()
-{
- plugin->config.smoothMode = from_text(get_text());
- gui->update_canvas();
- plugin->send_configure_change();
-}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+++ /dev/null
-
-/*
- * CINELERRA
- * Copyright (C) 2008 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 HISTOGRAMWINDOW_H
-#define HISTOGRAMWINDOW_H
-
-
-
-#include "histogram.inc"
-#include "histogramwindow.inc"
-#include "pluginvclient.h"
-
-
-class HistogramSmoothMode : public BC_PopupMenu
-{
-public:
- HistogramSmoothMode(HistogramMain *client,
- HistogramWindow *window,
- int x,
- int y);
- void create_objects();
- static char* to_text(int shape);
- static int from_text(char *text);
- int handle_event();
- HistogramMain *plugin;
- HistogramWindow *gui;
-};
-
-class HistogramSlider : public BC_SubWindow
-{
-public:
- HistogramSlider(HistogramMain *plugin,
- HistogramWindow *gui,
- int x,
- int y,
- int w,
- int h,
- int is_input);
-
- void update();
- int button_press_event();
- int button_release_event();
- int cursor_motion_event();
- int input_to_pixel(float input);
-
- int operation;
- enum
- {
- NONE,
- DRAG_INPUT,
- DRAG_MIN_OUTPUT,
- DRAG_MAX_OUTPUT,
- };
- int is_input;
- HistogramMain *plugin;
- HistogramWindow *gui;
-};
-
-class HistogramAuto : public BC_CheckBox
-{
-public:
- HistogramAuto(HistogramMain *plugin,
- int x,
- int y);
- int handle_event();
- HistogramMain *plugin;
-};
-
-class HistogramSplit : public BC_CheckBox
-{
-public:
- HistogramSplit(HistogramMain *plugin,
- int x,
- int y);
- int handle_event();
- HistogramMain *plugin;
-};
-
-class HistogramMode : public BC_Radial
-{
-public:
- HistogramMode(HistogramMain *plugin,
- int x,
- int y,
- int value,
- char *text);
- int handle_event();
- HistogramMain *plugin;
- int value;
-};
-
-class HistogramReset : public BC_GenericButton
-{
-public:
- HistogramReset(HistogramMain *plugin,
- int x,
- int y);
- int handle_event();
- HistogramMain *plugin;
-};
-
-
-class HistogramOutputText : public BC_TumbleTextBox
-{
-public:
- HistogramOutputText(HistogramMain *plugin,
- HistogramWindow *gui,
- int x,
- int y,
- float *output);
- int handle_event();
- HistogramMain *plugin;
- float *output;
-};
-
-class HistogramInputText : public BC_TumbleTextBox
-{
-public:
- HistogramInputText(HistogramMain *plugin,
- HistogramWindow *gui,
- int x,
- int y,
- int do_x);
-
- int handle_event();
- void update();
-
- HistogramMain *plugin;
- HistogramWindow *gui;
- int do_x;
-};
-
-class HistogramCanvas : public BC_SubWindow
-{
-public:
- HistogramCanvas(HistogramMain *plugin,
- HistogramWindow *gui,
- int x,
- int y,
- int w,
- int h);
- int button_press_event();
- int cursor_motion_event();
- int button_release_event();
- HistogramMain *plugin;
- HistogramWindow *gui;
-};
-
-class HistogramWindow : public BC_Window
-{
-public:
- HistogramWindow(HistogramMain *plugin, int x, int y);
- ~HistogramWindow();
-
- void create_objects();
- int close_event();
- void update(int do_input);
- void update_mode();
- void update_canvas();
- void draw_canvas_overlay();
- void update_input();
- void update_output();
- int keypress_event();
-
- HistogramSlider *output;
- HistogramAuto *automatic;
- HistogramSplit *split;
- HistogramSmoothMode *smoothModeChoser;
- HistogramMode *mode_v, *mode_r, *mode_g, *mode_b /*, *mode_a */;
- HistogramOutputText *output_min;
- HistogramOutputText *output_max;
- HistogramOutputText *threshold;
- HistogramInputText *input_x;
- HistogramInputText *input_y;
- HistogramCanvas *canvas;
- HistogramMain *plugin;
- int canvas_w;
- int canvas_h;
- int title1_x;
- int title2_x;
- int title3_x;
- int title4_x;
- BC_Pixmap *max_picon, *mid_picon, *min_picon;
-};
-
-
-
-PLUGIN_THREAD_HEADER(HistogramMain, HistogramThread, HistogramWindow)
-
-
-
-
-#endif
+++ /dev/null
-
-/*
- * CINELERRA
- * Copyright (C) 2008 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 HISTOGRAMWINDOW_INC
-#define HISTOGRAMWINDOW_INC
-
-class HistogramWindow;
-class HistogramThread;
-
-#endif