/* * CINELERRA * Copyright (C) 2008 Adam Williams * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "clip.h" #include "bccmodels.h" #include "filexml.h" #include "dot.h" #include "dotwindow.h" #include "effecttv.h" #include "language.h" #include #include #include REGISTER_PLUGIN(DotMain) DotConfig::DotConfig() { dot_depth = 5; dot_size = 8; } DotMain::DotMain(PluginServer *server) : PluginVClient(server) { pattern = 0; sampx = 0; sampy = 0; effecttv = 0; need_reconfigure = 1; } DotMain::~DotMain() { if(pattern) delete [] pattern; if(sampx) delete [] sampx; if(sampy) delete [] sampy; if(effecttv) { delete dot_server; delete effecttv; } } const char* DotMain::plugin_title() { return N_("DotTV"); } int DotMain::is_realtime() { return 1; } NEW_WINDOW_MACRO(DotMain, DotWindow) int DotMain::load_configuration() { return 0; } void DotMain::save_data(KeyFrame *keyframe) { } void DotMain::read_data(KeyFrame *keyframe) { } void DotMain::make_pattern() { int i, x, y, c; int u, v; double p, q, r; uint32_t *pat; for(i = 0; i < config.dot_max(); i++) { /* Generated pattern is a quadrant of a disk. */ pat = pattern + (i + 1) * dot_hsize * dot_hsize - 1; // r = (0.2 * i / config.dot_max() + 0.8) * dot_hsize; // r = r * r; r = ((double)i / config.dot_max()) * dot_hsize; r *= 5; //printf("make_pattern %f\n", r); for(y = 0; y < dot_hsize; y++) { for(x = 0; x < dot_hsize; x++) { c = 0; for(u = 0; u < 4; u++) { p = (double)u / 4.0 + y; p = p * p; for(v = 0; v < 4; v++) { q = (double)v / 4.0 + x; if(p + q * q < r) { c++; } } } c = (c > 15) ? 15 : c; //printf("DotMain::make_pattern %d\n", c); *pat-- = (c << 20) | (c << 12) | (c << 4); /* The upper left part of a disk is needed, but generated pattern is a bottom * right part. So I spin the pattern. */ } } } } void DotMain::init_sampxy_table() { int i, j; // Need aspect ratio j = dot_hsize; for(i = 0; i < dots_width; i++) { sampx[i] = j; j += dot_size; } j = dot_hsize; for(i = 0; i < dots_height; i++) { sampy[i] = j; j += dot_size; } } void DotMain::reconfigure() { if(!effecttv) { effecttv = new EffectTV(input_ptr->get_w(), input_ptr->get_h()); dot_server = new DotServer(this, 1, 1); } dot_size = config.dot_size; dot_size = dot_size & 0xfe; dot_hsize = dot_size / 2; dots_width = input_ptr->get_w() / dot_size; dots_height = input_ptr->get_h() / dot_size; pattern = new uint32_t[config.dot_max() * dot_hsize * dot_hsize]; sampx = new int[input_ptr->get_w()]; sampy = new int[input_ptr->get_h()]; make_pattern(); init_sampxy_table(); need_reconfigure = 0; } int DotMain::process_realtime(VFrame *input_ptr, VFrame *output_ptr) { this->input_ptr = input_ptr; this->output_ptr = output_ptr; load_configuration(); if(need_reconfigure) reconfigure(); dot_server->process_packages(); return 0; } DotServer::DotServer(DotMain *plugin, int total_clients, int total_packages) : LoadServer(total_clients, total_packages) { this->plugin = plugin; } LoadClient* DotServer::new_client() { return new DotClient(this); } LoadPackage* DotServer::new_package() { return new DotPackage; } void DotServer::init_packages() { for(int i = 0; i < get_total_packages(); i++) { DotPackage *package = (DotPackage*)get_package(i); package->row1 = plugin->input_ptr->get_h() * i / get_total_packages(); package->row2 = plugin->input_ptr->get_h() * (i + 1) / get_total_packages(); } } DotClient::DotClient(DotServer *server) : LoadClient(server) { this->plugin = server->plugin; } #define COPY_uint16_t_0x8000_PIXEL(components, output, pattern) \ { \ output[0] = (pattern & 0xff0000) >> 8; \ output[1] = output[2] = 0x8000; \ if(components > 3) output[3] = 0xffff; \ } #define COPY_uint8_t_0x80_PIXEL(components, output, pattern) \ { \ output[0] = (pattern & 0xff0000) >> 16; \ output[1] = output[2] = 0x80; \ if(components > 3) output[3] = 0xff; \ } #define COPY_float_0x0_PIXEL(components, output, pattern) \ { \ output[0] = (float)(pattern & 0xff0000) / 0xff0000; \ output[1] = (float)(pattern & 0xff00) / 0xff00; \ output[2] = (float)(pattern & 0xff) / 0xff; \ if(components > 3) output[3] = 1; \ } #define COPY_uint16_t_0x0_PIXEL(components, output, pattern) \ { \ output[0] = (pattern & 0xff0000) >> 8; \ output[1] = (pattern & 0xff00); \ output[2] = (pattern & 0xff) << 8; \ if(components > 3) output[3] = 0xffff; \ } #define COPY_uint8_t_0x0_PIXEL(components, output, pattern) \ { \ output[0] = (pattern & 0xff0000) >> 16; \ output[1] = (pattern & 0xff00) >> 8; \ output[2] = (pattern & 0xff); \ if(components > 3) output[3] = 0xff; \ } #define DRAW_DOT(type, components, chroma) \ { \ int x, y; \ uint32_t *pat; \ type *output; \ int y_total = 0; \ \ c = (c >> (8 - plugin->config.dot_depth)); \ pat = plugin->pattern + c * plugin->dot_hsize * plugin->dot_hsize; \ output = ((type**)output_rows)[0] + \ yy * plugin->dot_size * plugin->input_ptr->get_w() * components + \ xx * plugin->dot_size * components; \ \ for(y = 0; y < plugin->dot_hsize && y_total < plugin->input_ptr->get_h(); y++) \ { \ for(x = 0; x < plugin->dot_hsize; x++) { \ COPY_##type##_##chroma##_PIXEL(components, output, *pat); \ output += components; \ pat++; \ } \ pat -= 2; \ for(x = 0; x < plugin->dot_hsize - 1; x++) { \ COPY_##type##_##chroma##_PIXEL(components, output, *pat); \ output += components; \ pat--; \ } \ COPY_##type##_##chroma##_PIXEL(components, output, 0x00000000); \ output += components * (plugin->input_ptr->get_w() - plugin->dot_size + 1); \ pat += plugin->dot_hsize + 1; \ y_total++; \ } \ \ pat -= plugin->dot_hsize * 2; \ \ for(y = 0; y < plugin->dot_hsize && y_total < plugin->input_ptr->get_h(); y++) \ { \ if(y < plugin->dot_hsize - 1) { \ for(x = 0; x < plugin->dot_hsize; x++) { \ COPY_##type##_##chroma##_PIXEL(components, output, *pat); \ output += components; \ pat++; \ } \ pat -= 2; \ for(x = 0; x < plugin->dot_hsize - 1; x++) { \ COPY_##type##_##chroma##_PIXEL(components, output, *pat); \ output += components; \ pat--; \ } \ COPY_##type##_##chroma##_PIXEL(components, output, 0x00000000); \ output += components * (plugin->input_ptr->get_w() - plugin->dot_size + 1); \ pat += -plugin->dot_hsize + 1; \ } \ else { \ for(x = 0; x < plugin->dot_hsize * 2; x++) { \ COPY_##type##_##chroma##_PIXEL(components, output, 0x00000000); \ output += components; \ } \ } \ \ y_total++; \ } \ } void DotClient::draw_dot(int xx, int yy, unsigned char c, unsigned char **output_rows, int color_model) { switch(plugin->input_ptr->get_color_model()) { case BC_RGB888: DRAW_DOT(uint8_t, 3, 0x0); break; case BC_RGB_FLOAT: DRAW_DOT(float, 3, 0x0); break; case BC_YUV888: DRAW_DOT(uint8_t, 3, 0x80); break; case BC_RGBA_FLOAT: DRAW_DOT(float, 4, 0x0); break; case BC_RGBA8888: DRAW_DOT(uint8_t, 4, 0x0); break; case BC_YUVA8888: DRAW_DOT(uint8_t, 4, 0x80); break; case BC_RGB161616: DRAW_DOT(uint16_t, 3, 0x0); break; case BC_YUV161616: DRAW_DOT(uint16_t, 3, 0x8000); break; case BC_RGBA16161616: DRAW_DOT(uint16_t, 4, 0x0); break; case BC_YUVA16161616: DRAW_DOT(uint16_t, 4, 0x8000); break; } } #define RGB_TO_Y(type, is_yuv) \ { \ type *row_local = (type*)row; \ \ if(sizeof(type) == 4) \ { \ int r = (int)(row_local[0] * 0xff); \ int g = (int)(row_local[0] * 0xff); \ int b = (int)(row_local[0] * 0xff); \ CLAMP(r, 0, 0xff); \ CLAMP(g, 0, 0xff); \ CLAMP(b, 0, 0xff); \ result = plugin->effecttv->RtoY[r] + \ plugin->effecttv->RtoY[g] + \ plugin->effecttv->RtoY[b]; \ } \ else \ if(sizeof(type) == 2) \ { \ if(is_yuv) \ result = (int)row_local[0] >> 8; \ else \ { \ result = plugin->effecttv->RtoY[(int)row_local[0] >> 8]; \ result += plugin->effecttv->GtoY[(int)row_local[1] >> 8]; \ result += plugin->effecttv->BtoY[(int)row_local[2] >> 8]; \ } \ } \ else \ { \ if(is_yuv) \ result = (int)row_local[0]; \ else \ { \ result = plugin->effecttv->RtoY[(int)row_local[0]]; \ result += plugin->effecttv->GtoY[(int)row_local[1]]; \ result += plugin->effecttv->BtoY[(int)row_local[2]]; \ } \ } \ } unsigned char DotClient::RGBtoY(unsigned char *row, int color_model) { unsigned char result = 0; switch(color_model) { case BC_RGB888: case BC_RGBA8888: RGB_TO_Y(uint8_t, 0); break; case BC_RGB_FLOAT: case BC_RGBA_FLOAT: RGB_TO_Y(float, 0); break; case BC_YUV888: case BC_YUVA8888: RGB_TO_Y(uint8_t, 1); break; case BC_RGB161616: case BC_RGBA16161616: RGB_TO_Y(uint16_t, 0); break; case BC_YUV161616: case BC_YUVA16161616: RGB_TO_Y(uint16_t, 1); break; } return result; } void DotClient::process_package(LoadPackage *package) { int x, y; int sx, sy; DotPackage *local_package = (DotPackage*)package; unsigned char **input_rows = plugin->input_ptr->get_rows() + local_package->row1; unsigned char **output_rows = plugin->output_ptr->get_rows() + local_package->row1; //int width = plugin->input_ptr->get_w(); //int height = local_package->row2 - local_package->row1; for(y = 0; y < plugin->dots_height; y++) { sy = plugin->sampy[y]; for(x = 0; x < plugin->dots_width; x++) { sx = plugin->sampx[x]; //printf("DotClient::process_package %d\n", // RGBtoY(&input_rows[sy][sx * plugin->input_ptr->get_bytes_per_pixel()], // plugin->input_ptr->get_color_model())); draw_dot(x, y, RGBtoY(&input_rows[sy][sx * plugin->input_ptr->get_bytes_per_pixel()], plugin->input_ptr->get_color_model()), output_rows, plugin->input_ptr->get_color_model()); } } } DotPackage::DotPackage() { }