X-Git-Url: http://git.cinelerra-gg.org/git/?p=goodguy%2Fhistory.git;a=blobdiff_plain;f=cinelerra-5.1%2Fguicast%2Fvframe.C;h=041887702435f4028f605bf07ebdfbb1720fb610;hp=7aeb079a22a7fff3c7e6a822f171d5090d44e3f3;hb=c279e21fc2394a7908bbd1ba8c79b116fe9fb14a;hpb=5a1b2bb96f2bd6b7ef4f8031763683726c02219d diff --git a/cinelerra-5.1/guicast/vframe.C b/cinelerra-5.1/guicast/vframe.C index 7aeb079a..04188770 100644 --- a/cinelerra-5.1/guicast/vframe.C +++ b/cinelerra-5.1/guicast/vframe.C @@ -24,7 +24,9 @@ #include #include #include +#include #include +#include #include "bcbitmap.h" #include "bchash.h" @@ -78,41 +80,69 @@ VFrameScene::~VFrameScene() //static BCCounter counter; - -VFramePng::VFramePng(unsigned char *png_data, double scale) +VFramePng::VFramePng(unsigned char *png_data, double s) { long image_size = ((long)png_data[0] << 24) | ((long)png_data[1] << 16) | ((long)png_data[2] << 8) | (long)png_data[3]; - if( !scale ) scale = BC_WindowBase::get_resources()->icon_scale; - read_png(png_data+4, image_size, scale, scale); + if( !s ) s = BC_WindowBase::get_resources()->icon_scale; + read_png(png_data+4, image_size, s, s); } -VFramePng::VFramePng(unsigned char *png_data, long image_size, double xscale, double yscale) +VFramePng::VFramePng(unsigned char *png_data, long image_size, double xs, double ys) { - if( !xscale ) xscale = BC_WindowBase::get_resources()->icon_scale; - if( !yscale ) yscale = BC_WindowBase::get_resources()->icon_scale; - read_png(png_data, image_size, xscale, yscale); + if( !xs ) xs = BC_WindowBase::get_resources()->icon_scale; + if( !ys ) ys = BC_WindowBase::get_resources()->icon_scale; + read_png(png_data, image_size, xs, ys); } VFramePng::~VFramePng() { } +VFrame *VFramePng::vframe_png(int fd, double xs, double ys) +{ + struct stat st; + if( fstat(fd, &st) ) return 0; + long len = st.st_size; + if( !len ) return 0; + int w = 0, h = 0; + unsigned char *bfr = (unsigned char *) + ::mmap (NULL, len, PROT_READ, MAP_SHARED, fd, 0); + if( bfr == MAP_FAILED ) return 0; + VFrame *vframe = new VFramePng(bfr, len, xs, ys); + if( (w=vframe->get_w()) <= 0 || (h=vframe->get_h()) <= 0 || + vframe->get_data() == 0 ) { delete vframe; vframe = 0; } + ::munmap(bfr, len); + return vframe; +} +VFrame *VFramePng::vframe_png(const char *png_path, double xs, double ys) +{ + VFrame *vframe = 0; + int fd = ::open(png_path, O_RDONLY); + if( fd >= 0 ) { + vframe = vframe_png(fd, xs, ys); + ::close(fd); + } + return vframe; +} VFrame::VFrame(VFrame &frame) { reset_parameters(1); params = new BC_Hash; + use_shm = frame.use_shm; allocate_data(0, -1, 0, 0, 0, frame.w, frame.h, frame.color_model, frame.bytes_per_line); - memcpy(data, frame.data, bytes_per_line * h); - copy_stacks(&frame); + copy_vframe(&frame); } + VFrame::VFrame(int w, int h, int color_model, long bytes_per_line) { reset_parameters(1); +// use bytes_per_line == 0 to allocate default unshared + if( !bytes_per_line ) { bytes_per_line = -1; use_shm = 0; } params = new BC_Hash; allocate_data(data, -1, 0, 0, 0, w, h, color_model, bytes_per_line); @@ -249,6 +279,10 @@ int VFrame::reset_parameters(int do_opengl) sequence_number = -1; timestamp = -1.; is_keyframe = 0; + draw_point = 0; + pixel_rgb = 0x000000; // BLACK + pixel_yuv = 0x008080; + stipple = 0; if(do_opengl) { @@ -275,6 +309,11 @@ int VFrame::clear_objects(int do_opengl) pbuffer = 0; } +#ifdef LEAKER +if( memory_type != VFrame::SHARED ) + printf("==del %p from %p\n", data, __builtin_return_address(0)); +#endif + // Delete data switch(memory_type) { @@ -316,6 +355,7 @@ int VFrame::clear_objects(int do_opengl) case BC_YUV444P: case BC_RGB_FLOATP: case BC_RGBA_FLOATP: + case BC_GBRP: break; default: @@ -407,6 +447,12 @@ void VFrame::create_row_pointers() this->u_offset = sz; this->v_offset = sz + sz; break; + case BC_GBRP: + if( this->v_offset ) break; + this->y_offset = 0; + this->u_offset = sz * sizeof(uint8_t); + this->v_offset = 2 * sz * sizeof(uint8_t); + break; case BC_RGBA_FLOATP: if( this->v_offset || a ) break; a = this->data + 3 * sz * sizeof(float); @@ -465,27 +511,30 @@ int VFrame::allocate_data(unsigned char *data, int shmid, } else { memory_type = VFrame::PRIVATE; + this->data = 0; int size = calculate_data_size(this->w, this->h, this->bytes_per_line, this->color_model); - if(BC_WindowBase::get_resources()->use_vframe_shm() && use_shm) { + if( use_shm && size >= SHM_MIN_SIZE && + BC_WindowBase::get_resources()->use_vframe_shm() ) { this->shmid = shmget(IPC_PRIVATE, size, IPC_CREAT | 0777); - if(this->shmid < 0) { - printf("VFrame::allocate_data %d could not allocate shared memory\n", __LINE__); - } - - this->data = (unsigned char*)shmat(this->shmid, NULL, 0); -//printf("VFrame::allocate_data %d %d %d\n", __LINE__, size, this->shmid); - -//printf("VFrame::allocate_data %d %p\n", __LINE__, this->data); + if( this->shmid >= 0 ) { + this->data = (unsigned char*)shmat(this->shmid, NULL, 0); +//printf("VFrame::allocate_data %d %d %d %p\n", __LINE__, size, this->shmid, this->data); // This causes it to automatically delete when the program exits. - shmctl(this->shmid, IPC_RMID, 0); + shmctl(this->shmid, IPC_RMID, 0); + } + else { + printf("VFrame::allocate_data %d could not allocate" + " shared memory, %dx%d (model %d) size=0x%08x\n", + __LINE__, w, h, color_model, size); + BC_Trace::dump_shm_stats(stdout); + } } - else { // Have to use malloc for libpng -//printf("==vframe %d from %p\n", size, __builtin_return_address(0)); + if( !this->data ) { this->data = (unsigned char *)malloc(size); + this->shmid = -1; } - // Memory check // if(this->w * this->h > 1500 * 1100) // printf("VFrame::allocate_data 2 this=%p w=%d h=%d this->data=%p\n", @@ -493,6 +542,9 @@ int VFrame::allocate_data(unsigned char *data, int shmid, if(!this->data) printf("VFrame::allocate_data %dx%d: memory exhausted.\n", this->w, this->h); +#ifdef LEAKER +printf("==new %p from %p sz %d\n", this->data, __builtin_return_address(0), size); +#endif //printf("VFrame::allocate_data %d %p data=%p %d %d\n", __LINE__, this, this->data, this->w, this->h); //if(size > 1000000) printf("VFrame::allocate_data %d\n", size); @@ -776,49 +828,41 @@ int VFramePng::read_png(const unsigned char *data, long sz, double xscale, doubl int VFrame::write_png(const char *path) { + VFrame *vframe = this; png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0); png_infop info_ptr = png_create_info_struct(png_ptr); FILE *out_fd = fopen(path, "w"); - if(!out_fd) - { + if(!out_fd) { printf("VFrame::write_png %d %s %s\n", __LINE__, path, strerror(errno)); return 1; } int png_cmodel = PNG_COLOR_TYPE_RGB; - switch(get_color_model()) - { - case BC_RGB888: - case BC_YUV888: - png_cmodel = PNG_COLOR_TYPE_RGB; - break; - - case BC_RGBA8888: - case BC_YUVA8888: + int bc_cmodel = get_color_model(); + switch( bc_cmodel ) { + case BC_RGB888: break; + case BC_RGBA8888: png_cmodel = PNG_COLOR_TYPE_RGB_ALPHA; break; + case BC_A8: png_cmodel = PNG_COLOR_TYPE_GRAY; break; + default: + bc_cmodel = BC_RGB888; + if( BC_CModels::has_alpha(bc_cmodel) ) { + bc_cmodel = BC_RGBA8888; png_cmodel = PNG_COLOR_TYPE_RGB_ALPHA; - break; - - case BC_A8: - png_cmodel = PNG_COLOR_TYPE_GRAY; - break; + } + vframe = new VFrame(get_w(), get_h(), bc_cmodel, 0); + vframe->transfer_from(this); + break; } - png_init_io(png_ptr, out_fd); png_set_compression_level(png_ptr, 9); - png_set_IHDR(png_ptr, - info_ptr, - get_w(), - get_h(), - 8, - png_cmodel, - PNG_INTERLACE_NONE, - PNG_COMPRESSION_TYPE_DEFAULT, - PNG_FILTER_TYPE_DEFAULT); + png_set_IHDR(png_ptr, info_ptr, get_w(), get_h(), 8, png_cmodel, + PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); png_write_info(png_ptr, info_ptr); - png_write_image(png_ptr, get_rows()); + png_write_image(png_ptr, vframe->get_rows()); png_write_end(png_ptr, info_ptr); png_destroy_write_struct(&png_ptr, &info_ptr); fclose(out_fd); + if( vframe != this ) delete vframe; return 0; } @@ -848,27 +892,33 @@ int VFrame::clear_frame() case BC_YUV410P: bzero(get_y(), sz); - bzero(get_u(), w / 4 * h / 4); - bzero(get_v(), w / 4 * h / 4); + memset(get_u(), 0x80, w / 4 * h / 4); + memset(get_v(), 0x80, w / 4 * h / 4); break; case BC_YUV411P: case BC_YUV420P: case BC_YUV420PI: bzero(get_y(), sz); - bzero(get_u(), sz / 4); - bzero(get_v(), sz / 4); + memset(get_u(), 0x80, sz / 4); + memset(get_v(), 0x80, sz / 4); break; case BC_YUV422P: bzero(get_y(), sz); - bzero(get_u(), sz / 2); - bzero(get_v(), sz / 2); + memset(get_u(), 0x80, sz / 2); + memset(get_v(), 0x80, sz / 2); + break; + + case BC_GBRP: + bzero(get_y(), sz); + bzero(get_u(), sz); + bzero(get_b(), sz); break; case BC_RGBA_FLOATP: if( a ) { float *ap = (float *)a; - for( int i=sz; --i>=0; ++ap ) *ap = 1.f; } + for( int i=sz; --i>=0; ++ap ) *ap = 0.f; } case BC_RGB_FLOATP: { float *rp = (float *)y; for( int i=sz; --i>=0; ++rp ) *rp = 0.f; @@ -879,8 +929,8 @@ int VFrame::clear_frame() break; } case BC_YUV444P: bzero(get_y(), sz); - bzero(get_u(), sz); - bzero(get_v(), sz); + memset(get_u(), 0x80, sz); + memset(get_v(), 0x80, sz); break; case BC_YUV888: @@ -909,12 +959,9 @@ int VFrame::clear_frame() void VFrame::rotate90() { // Allocate new frame - int new_w = h, new_h = w, new_bytes_per_line = bytes_per_pixel * new_w; - unsigned char *new_data = new unsigned char[calculate_data_size(new_w, new_h, new_bytes_per_line, color_model)]; - unsigned char **new_rows = new unsigned char*[new_h]; - for(int i = 0; i < new_h; i++) - new_rows[i] = &new_data[new_bytes_per_line * i]; - + int new_w = h, new_h = w; + VFrame new_frame(new_w, new_h, color_model); + unsigned char **new_rows = new_frame.get_rows(); // Copy data for(int in_y = 0, out_x = new_w - 1; in_y < h; in_y++, out_x--) { @@ -929,23 +976,34 @@ void VFrame::rotate90() } // Swap frames - clear_objects(0); +// swap memory + unsigned char *new_data = new_frame.data; + new_frame.data = data; data = new_data; +// swap rows + new_rows = new_frame.rows; + new_frame.rows = rows; rows = new_rows; - bytes_per_line = new_bytes_per_line; - w = new_w; - h = new_h; +// swap shmid + int new_shmid = new_frame.shmid; + new_frame.shmid = shmid; + shmid = new_shmid; +// swap bytes_per_line + int new_bpl = new_frame.bytes_per_line; + new_frame.bytes_per_line = bytes_per_line; + bytes_per_line = new_bpl; + new_frame.clear_objects(0); + + w = new_frame.w; + h = new_frame.h; } void VFrame::rotate270() { // Allocate new frame - int new_w = h, new_h = w, new_bytes_per_line = bytes_per_pixel * new_w; - unsigned char *new_data = new unsigned char[calculate_data_size(new_w, new_h, new_bytes_per_line, color_model)]; - unsigned char **new_rows = new unsigned char*[new_h]; - for(int i = 0; i < new_h; i++) - new_rows[i] = &new_data[new_bytes_per_line * i]; - + int new_w = h, new_h = w; + VFrame new_frame(new_w, new_h, color_model); + unsigned char **new_rows = new_frame.get_rows(); // Copy data for(int in_y = 0, out_x = 0; in_y < h; in_y++, out_x++) { @@ -960,24 +1018,36 @@ void VFrame::rotate270() } // Swap frames - clear_objects(0); +// swap memory + unsigned char *new_data = new_frame.data; + new_frame.data = data; data = new_data; +// swap rows + new_rows = new_frame.rows; + new_frame.rows = rows; rows = new_rows; - bytes_per_line = new_bytes_per_line; - w = new_w; - h = new_h; +// swap shmid + int new_shmid = new_frame.shmid; + new_frame.shmid = shmid; + shmid = new_shmid; +// swap bytes_per_line + int new_bpl = new_frame.bytes_per_line; + new_frame.bytes_per_line = bytes_per_line; + bytes_per_line = new_bpl; + new_frame.clear_objects(0); + + w = new_frame.w; + h = new_frame.h; } void VFrame::flip_vert() { - unsigned char *temp = new unsigned char[bytes_per_line]; - for(int i = 0, j = h - 1; i < j; i++, j--) - { + unsigned char temp[bytes_per_line]; + for( int i=0, j=h; --j>i; ++i ) { memcpy(temp, rows[j], bytes_per_line); memcpy(rows[j], rows[i], bytes_per_line); memcpy(rows[i], temp, bytes_per_line); } - delete [] temp; } void VFrame::flip_horiz() @@ -999,6 +1069,18 @@ void VFrame::flip_horiz() int VFrame::copy_from(VFrame *frame) { + if(this->w != frame->get_w() || + this->h != frame->get_h()) + { + printf("VFrame::copy_from %d sizes differ src %dx%d != dst %dx%d\n", + __LINE__, + frame->get_w(), + frame->get_h(), + get_w(), + get_h()); + return 1; + } + int w = MIN(this->w, frame->get_w()); int h = MIN(this->h, frame->get_h()); timestamp = frame->timestamp; @@ -1054,12 +1136,14 @@ int VFrame::copy_from(VFrame *frame) int VFrame::transfer_from(VFrame *that, int bg_color, int in_x, int in_y, int in_w, int in_h) { + timestamp = that->timestamp; + copy_params(that); + if( this->get_color_model() == that->get_color_model() && this->get_w() == that->get_w() && this->get_h() == that->get_h() && this->get_bytes_per_line() == that->get_bytes_per_line() ) return this->copy_from(that); - timestamp = that->timestamp; #if 0 BC_CModels::transfer( this->get_rows(), that->get_rows(), // Packed data out/in @@ -1082,7 +1166,7 @@ int VFrame::transfer_from(VFrame *that, int bg_color, int in_x, int in_y, int in inp = in_ptrs; } else - inp = that->get_rows(); + inp = that->get_rows(); if( BC_CModels::is_planar(this->get_color_model()) ) { out_ptrs[0] = this->get_y(); out_ptrs[1] = this->get_u(); @@ -1091,7 +1175,7 @@ int VFrame::transfer_from(VFrame *that, int bg_color, int in_x, int in_y, int in outp = out_ptrs; } else - outp = this->get_rows(); + outp = this->get_rows(); BC_CModels::transfer(outp, this->get_color_model(), 0, 0, this->get_w(), this->get_h(), this->get_bytes_per_line(), @@ -1104,58 +1188,6 @@ int VFrame::transfer_from(VFrame *that, int bg_color, int in_x, int in_y, int in } - - - - -#define OVERLAY(type, max, components) \ -{ \ - type **in_rows = (type**)src->get_rows(); \ - type **out_rows = (type**)get_rows(); \ - int in_w = src->get_w(); \ - int in_h = src->get_h(); \ - \ - for(int i = 0; i < in_h; i++) \ - { \ - if(i + out_y1 >= 0 && i + out_y1 < h) \ - { \ - type *src_row = in_rows[i]; \ - type *dst_row = out_rows[i + out_y1] + out_x1 * components; \ - \ - for(int j = 0; j < in_w; j++) \ - { \ - if(j + out_x1 >= 0 && j + out_x1 < w) \ - { \ - int opacity = src_row[3]; \ - int transparency = dst_row[3] * (max - src_row[3]) / max; \ - dst_row[0] = (transparency * dst_row[0] + opacity * src_row[0]) / max; \ - dst_row[1] = (transparency * dst_row[1] + opacity * src_row[1]) / max; \ - dst_row[2] = (transparency * dst_row[2] + opacity * src_row[2]) / max; \ - dst_row[3] = MAX(dst_row[3], src_row[3]); \ - } \ - \ - dst_row += components; \ - src_row += components; \ - } \ - } \ - } \ -} - - -void VFrame::overlay(VFrame *src, - int out_x1, - int out_y1) -{ - switch(get_color_model()) - { - case BC_RGBA8888: - OVERLAY(unsigned char, 0xff, 4); - break; - } -} - - - int VFrame::get_scale_tables(int *column_table, int *row_table, int in_x1, int in_y1, int in_x2, int in_y2, int out_x1, int out_y1, int out_x2, int out_y2) @@ -1250,22 +1282,20 @@ void VFrame::copy_stacks(VFrame *src) { clear_stacks(); - for(int i = 0; i < src->next_effects.total; i++) - { - char *ptr; - next_effects.append(ptr = new char[strlen(src->next_effects.values[i]) + 1]); - strcpy(ptr, src->next_effects.values[i]); - } - for(int i = 0; i < src->prev_effects.total; i++) - { - char *ptr; - prev_effects.append(ptr = new char[strlen(src->prev_effects.values[i]) + 1]); - strcpy(ptr, src->prev_effects.values[i]); - } + for( int i=0; i < src->next_effects.total; ++i ) + next_effects.append(cstrdup(src->next_effects[i])); + for( int i=0; i < src->prev_effects.total; ++i ) + prev_effects.append(cstrdup(src->prev_effects[i])); copy_params(src); } +int VFrame::copy_vframe(VFrame *frame) +{ + copy_stacks(frame); + return copy_from(frame); +} + int VFrame::equal_stacks(VFrame *src) { for(int i = 0; i < src->next_effects.total && i < next_effects.total; i++) @@ -1312,119 +1342,354 @@ int VFrame::get_memory_usage() return get_h() * get_bytes_per_line(); } -void VFrame::draw_pixel(int x, int y) +void VFrame::set_pixel_color(int rgb) { - if(!(x >= 0 && y >= 0 && x < get_w() && y < get_h())) return; + pixel_rgb = rgb; + int ir = 0xff & (pixel_rgb >> 16); + int ig = 0xff & (pixel_rgb >> 8); + int ib = 0xff & (pixel_rgb >> 0); + YUV::yuv.rgb_to_yuv_8(ir, ig, ib); + pixel_yuv = (ir<<16) | (ig<<8) | (ib<<0); +} -#define DRAW_PIXEL(x, y, components, do_yuv, max, type) \ -{ \ - type **rows = (type**)get_rows(); \ - rows[y][x * components] = max - rows[y][x * components]; \ - if(!do_yuv) \ - { \ - rows[y][x * components + 1] = max - rows[y][x * components + 1]; \ - rows[y][x * components + 2] = max - rows[y][x * components + 2]; \ - } \ - else \ - { \ - rows[y][x * components + 1] = (max / 2 + 1) - rows[y][x * components + 1]; \ - rows[y][x * components + 2] = (max / 2 + 1) - rows[y][x * components + 2]; \ - } \ - if(components == 4) \ - rows[y][x * components + 3] = max; \ +void VFrame::set_stiple(int mask) +{ + stipple = mask; } +int VFrame::draw_pixel(int x, int y) +{ + if( x < 0 || y < 0 || x >= get_w() || y >= get_h() ) return 1; + if( draw_point ) return (this->*draw_point)(x, y); - switch(get_color_model()) - { - case BC_RGB888: - DRAW_PIXEL(x, y, 3, 0, 0xff, unsigned char); - break; - case BC_RGBA8888: - DRAW_PIXEL(x, y, 4, 0, 0xff, unsigned char); - break; - case BC_RGB_FLOAT: - DRAW_PIXEL(x, y, 3, 0, 1.0, float); - break; - case BC_RGBA_FLOAT: - DRAW_PIXEL(x, y, 4, 0, 1.0, float); - break; - case BC_YUV888: - DRAW_PIXEL(x, y, 3, 1, 0xff, unsigned char); - break; - case BC_YUVA8888: - DRAW_PIXEL(x, y, 4, 1, 0xff, unsigned char); - break; - case BC_RGB161616: - DRAW_PIXEL(x, y, 3, 0, 0xffff, uint16_t); - break; - case BC_YUV161616: - DRAW_PIXEL(x, y, 3, 1, 0xffff, uint16_t); - break; - case BC_RGBA16161616: - DRAW_PIXEL(x, y, 4, 0, 0xffff, uint16_t); - break; - case BC_YUVA16161616: - DRAW_PIXEL(x, y, 4, 1, 0xffff, uint16_t); - break; +#define DRAW_PIXEL(type, r, g, b) { \ + type **rows = (type**)get_rows(); \ + rows[y][x * components + 0] = r; \ + rows[y][x * components + 1] = g; \ + rows[y][x * components + 2] = b; \ + if( components == 4 ) \ + rows[y][x * components + 3] = mx; \ +} + int components = BC_CModels::components(color_model); + int bch = BC_CModels::calculate_pixelsize(color_model) / components; + int sz = 8*bch, mx = BC_CModels::is_float(color_model) ? 1 : (1<> 16); float fr = 0; + int ig = 0xff & (pixel_color >> 8); float fg = 0; + int ib = 0xff & (pixel_color >> 0); float fb = 0; + if( (x+y) & stipple ) { + ir = 255 - ir; ig = 255 - ig; ib = 255 - ib; } + if( BC_CModels::is_float(color_model) ) { + fr = ir / 255.; fg = ig / 255.; fb = ib / 255.; + mx = 1; + } + else if( (sz-=8) > 0 ) { + ir <<= sz; ig <<= sz; ib <<= sz; + } + + switch(get_color_model()) { + case BC_RGB888: + case BC_YUV888: + case BC_RGBA8888: + case BC_YUVA8888: + DRAW_PIXEL(uint8_t, ir, ig, ib); + break; + case BC_RGB161616: + case BC_YUV161616: + case BC_RGBA16161616: + case BC_YUVA16161616: + DRAW_PIXEL(uint16_t, ir, ig, ib); + break; + case BC_RGB_FLOAT: + case BC_RGBA_FLOAT: + DRAW_PIXEL(float, fr, fg, fb); + break; + } + return 0; } +// Bresenham's void VFrame::draw_line(int x1, int y1, int x2, int y2) { - int w = labs(x2 - x1); - int h = labs(y2 - y1); -//printf("FindObjectMain::draw_line 1 %d %d %d %d\n", x1, y1, x2, y2); + if( y1 > y2 ) { + int tx = x1; x1 = x2; x2 = tx; + int ty = y1; y1 = y2; y2 = ty; + } - if(!w && !h) - { - draw_pixel(x1, y1); + int x = x1, y = y1; + int dx = x2-x1, dy = y2-y1; + int dx2 = 2*dx, dy2 = 2*dy; + if( dx < 0 ) dx = -dx; + int r = dx > dy ? dx : dy, n = r; + int dir = 0; + if( dx2 < 0 ) dir += 1; + if( dy >= dx ) { + if( dx2 >= 0 ) do { /* +Y, +X */ + draw_pixel(x, y++); + if( (r -= dx2) < 0 ) { r += dy2; ++x; } + } while( --n >= 0 ); + else do { /* +Y, -X */ + draw_pixel(x, y++); + if( (r += dx2) < 0 ) { r += dy2; --x; } + } while( --n >= 0 ); } - else - if(w > h) - { -// Flip coordinates so x1 < x2 - if(x2 < x1) - { - y2 ^= y1; - y1 ^= y2; - y2 ^= y1; - x1 ^= x2; - x2 ^= x1; - x1 ^= x2; + else { + if( dx2 >= 0 ) do { /* +X, +Y */ + draw_pixel(x++, y); + if( (r -= dy2) < 0 ) { r += dx2; ++y; } + } while( --n >= 0 ); + else do { /* -X, +Y */ + draw_pixel(x--, y); + if( (r -= dy2) < 0 ) { r -= dx2; ++y; } + } while( --n >= 0 ); + } +} + +// g++ -dD -E - < /dev/null | grep DBL_EPSILON +#ifndef __DBL_EPSILON__ +#define __DBL_EPSILON__ ((double)2.22044604925031308085e-16L) +#endif +// weakest fraction * graphics integer range +#define RND_EPSILON (__DBL_EPSILON__*65536) + +class smooth_line { + int rnd(double v) { return round(v)+RND_EPSILON; } + VFrame *vframe; +public: + int sx, sy, ex, ey; /* current point, end point */ + int xs, ys; /* x/y quadrant sign -1/1 */ + int64_t A, B, C; /* quadratic coefficients */ + int64_t r, dx, dy; /* residual, dr/dx and dr/dy */ + int xmxx, xmxy; /* x,y at apex */ + int done; + + void init0(int x1,int y1, int x2,int y2, int x3,int y3, int top); + void init1(int x1,int y1, int x2,int y2, int x3,int y3); + int64_t rx() { return r + xs*8*dx + 4*A; } + void moveX(int64_t r) { + dx += xs*A; dy -= xs*B; + this->r = r; sx += xs; + } + int64_t ry() { return r + 8*dy + 4*C; } + void moveY(int64_t r) { + dx -= B; dy += C; + this->r = r; ++sy; + } + void draw(); + + smooth_line(VFrame *vframe) { this->vframe = vframe; this->done = 0; } +}; + + +void smooth_line::draw() +{ + if( done ) return; + if( abs(dy) >= abs(dx) ) { + if( xs*(sx-xmxx) >= 0 ) { + if( ys > 0 ) { done = 1; return; } + if( dy < 0 || ry() < 0 ) { moveY(ry()); goto xit; } + xmxx = ex; xmxy = ey; + ys = 1; xs = -xs; } - int numerator = y2 - y1; - int denominator = x2 - x1; - for(int i = x1; i <= x2; i++) - { - int y = y1 + (int64_t)(i - x1) * (int64_t)numerator / (int64_t)denominator; - draw_pixel(i, y); + moveX(rx()); + int64_t rr = ry(); + if( abs(rr) < abs(r) ) + moveY(rr); + } + else { + if( sy >= xmxy ) { + if( ys > 0 ) { done = 1; return; } + xmxx = ex; xmxy = ey; + ys = 1; xs = -xs; } + moveY(ry()); + int64_t rr = rx(); + if( abs(rr) < abs(r) ) + moveX(rr); + } +xit: vframe->draw_pixel(sx, sy); +} + +void VFrame::draw_smooth(int x1, int y1, int x2, int y2, int x3, int y3) +{ + if( (x1 == x2 && y1 == y2) || (x2 == x3 && y2 == y3) ) + draw_line(x1,y1, x3,y3); + else if( x1 == x3 && y1 == y3 ) + draw_line(x1,y1, x2,y2); + else if( (x2-x1) * (y2-y3) == (x2-x3) * (y2-y1) ) { + // co-linear, draw line from min to max + if( x1 < x3 ) { + if( x2 < x1 ) { x1 = x2; y1 = y2; } + if( x2 > x3 ) { x3 = x2; y3 = y2; } + } + else { + if( x2 > x1 ) { x1 = x2; y1 = y2; } + if( x2 < x3 ) { x3 = x2; y3 = y2; } + } + draw_line(x1,y1, x3,y3); } else - { -// Flip coordinates so y1 < y2 - if(y2 < y1) - { - y2 ^= y1; - y1 ^= y2; - y2 ^= y1; - x1 ^= x2; - x2 ^= x1; - x1 ^= x2; + smooth_draw(x1, y1, x2, y2, x3, y3); +} + +/* + Non-Parametric Smooth Curve Generation. Don Kelly 1984 + + P+-----+Q'= virtual + / / origin + / / + Q+-----+R + + Let the starting point be P. the ending point R. and the tangent vertex Q. + A general point Z on the curve is then + Z = (P + R - Q) + (Q - P) sin t + (Q - R) cos t + + Expanding the Cartesian coordinates around (P + R - Q) gives + [x y] = Z - (P + R - Q) + [a c] = Q - P + [b d] = Q - R + x = a*sin(t) + b*cos(t) + y = c*sin(t) + d*cos(t) + + from which t can now be eliminated via + c*x - a*y = (c*b - a*d)*cos(t) + d*x - b*y = (a*d - c*b)*sin(t) + + giving the Cartesian equation for the ellipse as + f(x, y) = (c*x - a*y)**2 + (d*x - b*y)**2 - (a*d - c*b)**2 = 0 + + or: f(x, y) = A*x**2 - 2*B*x*y + C*y**2 + B**2 - A*C = 0 + where: A = c**2 + d**2, B = a*c + b*d, C = a**2 + b**2 + + The maximum y extent of the ellipse may now be derived as follows: + let df/dx = 0, 2*A*x = 2*B*y, x = y*B/A + f(x, y) == B**2 * y**2 / A - 2*B**2 * y**2 / A + C*y**2 + B**2 - A*C = 0 + (A*C - B**2)*y = (A*C - B**2)*A + max x = sqrt(C), at y = B/sqrt(C) + max y = sqrt(A), at x = B/sqrt(A) + + */ + + +/* x1,y1 = P, x2,y2 = Q, x3,y3=R, + * draw from P to Q to R if top=0 + * or from P to (x,ymax) if top>0 + * or from Q to (x,ymax) if top<0 + */ +void smooth_line::init0(int x1,int y1, int x2,int y2, int x3,int y3, int top) +{ + int x0 = x1+x3-x2, y0 = y1+y3-y2; // Q' + + int a = x2-x1, c = y2-y1; + int b = x2-x3, d = y2-y3; + A = c*c + d*d; C = a*a + b*b; B = a*c + b*d; + + sx = top >= 0 ? x1 : x3; + sy = top >= 0 ? y1 : y3; + xs = x2 > sx || (x2==sx && (x1+x3-sx)>=x2) ? 1 : -1; + int64_t px = sx-x0, py = sy-y0; + dx = A*px - B*py; dy = C*py - B*px; + r = 0; + + if( top ) { + double ymy = sqrt(A), ymx = B/ymy; + ex = x0 + rnd(ymx); + ey = y0 + rnd(ymy); + } + else { + ex = x3; ey = y3; + } + + ys = a*b > 0 && (!top || top*xs*(b*c - a*d) > 0) ? -1 : 1; + if( ys < 0 ) { + double xmx = xs*sqrt(C), xmy = B/xmx; + xmxx = x0 + rnd(xmx); + xmxy = y0 + rnd(xmy); + } + else { + xmxx = ex; xmxy = ey; + } +} + +/* x1,y1 = P, x2,y2 = Q, x3,y3=R, + * draw from (x,ymax) to P + */ +void smooth_line::init1(int x1,int y1, int x2,int y2, int x3,int y3) +{ + int x0 = x1+x3-x2, y0 = y1+y3-y2; // Q' + + int a = x2-x1, c = y2-y1; + int b = x2-x3, d = y2-y3; + A = c*c + d*d; C = a*a + b*b; B = a*c + b*d; + + double ymy = -sqrt(A), ymx = B/ymy; + int64_t px = rnd(ymx), py = rnd(ymy); + sx = x0 + px; ex = x1; + sy = y0 + py; ey = y1; + xs = x2 > x1 || (x2==x1 && x3>=x2) ? 1 : -1; + dx = A*px - B*py; dy = C*py - B*px; + r = 4 * (A*px*px - 2*B*px*py + C*py*py + B*B - A*C); + + ys = a*b > 0 && xs*(b*c - a*d) < 0 ? -1 : 1; + if( ys < 0 ) { + double xmx = xs*sqrt(C), xmy = B/xmx; + xmxx = x0 + rnd(xmx); + xmxy = y0 + rnd(xmy); + } + else { + xs = -xs; + xmxx = ex; xmxy = ey; + } + if( xs > 0 ) + vframe->draw_pixel(sx, sy); + while( xs*(sx-xmxx) < 0 && (xs*dx < 0 || rx() < 0) ) { + moveX(rx()); + vframe->draw_pixel(sx, sy); + } +} + + +void VFrame::smooth_draw(int x1, int y1, int x2, int y2, int x3, int y3) +{ +//printf("p smooth_draw( %d,%d, %d,%d, %d,%d )\n", x1,y1,x2,y2,x3,y3); + if( y1 > y3 ) { // make y3 >= y1 + int xt = x1; x1 = x3; x3 = xt; + int yt = y1; y1 = y3; y3 = yt; + } + if( y1 > y2 && y3 > y2 ) { + smooth_line lt(this), rt(this); // Q on bottom + lt.init1(x1, y1, x2, y2, x3, y3); + rt.init1(x3, y3, x2, y2, x1, y1); + while( !lt.done || !rt.done ) { + lt.draw(); + rt.draw(); } - int numerator = x2 - x1; - int denominator = y2 - y1; - for(int i = y1; i <= y2; i++) - { - int x = x1 + (int64_t)(i - y1) * (int64_t)numerator / (int64_t)denominator; - draw_pixel(x, i); + } + else if( y1 < y2 && y3 < y2 ) { + smooth_line lt(this), rt(this); // Q on top + lt.init0(x1, y1, x2, y2, x3, y3, 1); + draw_pixel(lt.sx, lt.sy); + rt.init0(x1, y1, x2, y2, x3, y3, -1); + draw_pixel(rt.sx, rt.sy); + while( !lt.done || !rt.done ) { + lt.draw(); + rt.draw(); + } + } + else { + smooth_line pt(this); // Q in between + pt.init0(x1, y1, x2, y2, x3, y3, 0); + draw_pixel(pt.sx, pt.sy); + while( !pt.done ) { + pt.draw(); } } -//printf("FindObjectMain::draw_line 2\n"); } + void VFrame::draw_rect(int x1, int y1, int x2, int y2) { draw_line(x1, y1, x2, y1); @@ -1433,30 +1698,62 @@ void VFrame::draw_rect(int x1, int y1, int x2, int y2) draw_line(x1, y2 - 1, x1, y1 + 1); } -#define ARROW_SIZE 10 -void VFrame::draw_arrow(int x1, int y1, int x2, int y2) + +void VFrame::draw_oval(int x1, int y1, int x2, int y2) { - double angle = atan((float)(y2 - y1) / (float)(x2 - x1)); - double angle1 = angle + (float)145 / 360 * 2 * 3.14159265; - double angle2 = angle - (float)145 / 360 * 2 * 3.14159265; - int x3; - int y3; - int x4; - int y4; - if(x2 < x1) - { - x3 = x2 - (int)(ARROW_SIZE * cos(angle1)); - y3 = y2 - (int)(ARROW_SIZE * sin(angle1)); - x4 = x2 - (int)(ARROW_SIZE * cos(angle2)); - y4 = y2 - (int)(ARROW_SIZE * sin(angle2)); + int w = x2 - x1; + int h = y2 - y1; + int center_x = (x2 + x1) / 2; + int center_y = (y2 + y1) / 2; + int x_table[h / 2]; + +//printf("VFrame::draw_oval %d %d %d %d %d\n", __LINE__, x1, y1, x2, y2); + + for(int i = 0; i < h / 2; i++) { +// A^2 = -(B^2) + C^2 + x_table[i] = (int)(sqrt(-SQR(h / 2 - i) + SQR(h / 2)) * w / h); +//printf("VFrame::draw_oval %d i=%d x=%d\n", __LINE__, i, x_table[i]); } - else - { - x3 = x2 + (int)(ARROW_SIZE * cos(angle1)); - y3 = y2 + (int)(ARROW_SIZE * sin(angle1)); - x4 = x2 + (int)(ARROW_SIZE * cos(angle2)); - y4 = y2 + (int)(ARROW_SIZE * sin(angle2)); + + for(int i = 0; i < h / 2 - 1; i++) { + int x3 = x_table[i]; + int x4 = x_table[i + 1]; + + if(x4 > x3 + 1) { + for(int j = x3; j < x4; j++) { + draw_pixel(center_x + j, y1 + i); + draw_pixel(center_x - j, y1 + i); + draw_pixel(center_x + j, y2 - i - 1); + draw_pixel(center_x - j, y2 - i - 1); + } + } + else { + draw_pixel(center_x + x3, y1 + i); + draw_pixel(center_x - x3, y1 + i); + draw_pixel(center_x + x3, y2 - i - 1); + draw_pixel(center_x - x3, y2 - i - 1); + } } + + draw_pixel(center_x, y1); + draw_pixel(center_x, y2 - 1); + draw_pixel(x1, center_y); + draw_pixel(x2 - 1, center_y); + draw_pixel(x1, center_y - 1); + draw_pixel(x2 - 1, center_y - 1); +} + + +void VFrame::draw_arrow(int x1, int y1, int x2, int y2, int sz) +{ + double angle = atan((float)(y2 - y1) / (float)(x2 - x1)); + double angle1 = angle + (float)145 / 360 * 2 * M_PI; + double angle2 = angle - (float)145 / 360 * 2 * M_PI; + int s = x2 < x1 ? -1 : 1; + int x3 = x2 + s * (int)(sz * cos(angle1)); + int y3 = y2 + s * (int)(sz * sin(angle1)); + int x4 = x2 + s * (int)(sz * cos(angle2)); + int y4 = y2 + s * (int)(sz * sin(angle2)); // Main vector draw_line(x1, y1, x2, y2); @@ -1468,6 +1765,15 @@ void VFrame::draw_arrow(int x1, int y1, int x2, int y2) if(abs(y2 - y1) || abs(x2 - x1)) draw_line(x2, y2, x4, y4); } - +void VFrame::draw_x(int x, int y, int sz) +{ + draw_line(x-sz,y-sz, x+sz,y+sz); + draw_line(x+sz,y-sz, x-sz,y+sz); +} +void VFrame::draw_t(int x, int y, int sz) +{ + draw_line(x,y-sz, x,y+sz); + draw_line(x+sz,y, x-sz,y); +}