4 * Copyright (C) 2011 Adam Williams <broadcast at earthling dot net>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
34 #include "bcpbuffer.h"
35 #include "bcresources.h"
36 #include "bcsignals.h"
37 #include "bcsynchronous.h"
38 #include "bctexture.h"
39 #include "bcwindowbase.h"
41 #include "bccmodels.h"
47 static void png_read_function(png_structp png_ptr,
48 png_bytep data, png_size_t length)
50 VFrame *frame = (VFrame*)png_get_io_ptr(png_ptr);
51 if(frame->image_size - frame->image_offset < (long)length)
53 printf("PngReadFunction::png_read_function %d: overrun\n", __LINE__);
54 length = frame->image_size - frame->image_offset;
57 memcpy(data, &frame->image[frame->image_offset], length);
58 frame->image_offset += length;
68 VFrameScene::VFrameScene()
72 VFrameScene::~VFrameScene()
77 //static BCCounter counter;
79 VFramePng::VFramePng(unsigned char *png_data, double s)
82 ((long)png_data[0] << 24) | ((long)png_data[1] << 16) |
83 ((long)png_data[2] << 8) | (long)png_data[3];
84 if( !s ) s = BC_WindowBase::get_resources()->icon_scale;
85 read_png(png_data+4, image_size, s, s);
88 VFramePng::VFramePng(unsigned char *png_data, long image_size, double xs, double ys)
90 if( !xs ) xs = BC_WindowBase::get_resources()->icon_scale;
91 if( !ys ) ys = BC_WindowBase::get_resources()->icon_scale;
92 read_png(png_data, image_size, xs, ys);
95 VFramePng::~VFramePng()
99 VFrame *VFramePng::vframe_png(int fd, double xs, double ys)
102 if( fstat(fd, &st) ) return 0;
103 long len = st.st_size;
106 unsigned char *bfr = (unsigned char *)
107 ::mmap (NULL, len, PROT_READ, MAP_SHARED, fd, 0);
108 if( bfr == MAP_FAILED ) return 0;
109 VFrame *vframe = new VFramePng(bfr, len, xs, ys);
110 if( (w=vframe->get_w()) <= 0 || (h=vframe->get_h()) <= 0 ||
111 vframe->get_data() == 0 ) { delete vframe; vframe = 0; }
115 VFrame *VFramePng::vframe_png(const char *png_path, double xs, double ys)
118 int fd = ::open(png_path, O_RDONLY);
120 vframe = vframe_png(fd, xs, ys);
126 VFrame::VFrame(VFrame &frame)
129 params = new BC_Hash;
130 use_shm = frame.use_shm;
131 allocate_data(0, -1, 0, 0, 0, frame.w, frame.h,
132 frame.color_model, frame.bytes_per_line);
137 VFrame::VFrame(int w, int h, int color_model, long bytes_per_line)
140 // use bytes_per_line == 0 to allocate default unshared
141 if( !bytes_per_line ) { bytes_per_line = -1; use_shm = 0; }
142 params = new BC_Hash;
143 allocate_data(data, -1, 0, 0, 0, w, h,
144 color_model, bytes_per_line);
147 VFrame::VFrame(unsigned char *data, int shmid, int w, int h,
148 int color_model, long bytes_per_line)
151 params = new BC_Hash;
152 allocate_data(data, shmid, 0, 0, 0, w, h,
153 color_model, bytes_per_line);
156 VFrame::VFrame(unsigned char *data, int shmid,
157 long y_offset, long u_offset, long v_offset,
158 int w, int h, int color_model, long bytes_per_line)
161 params = new BC_Hash;
162 allocate_data(data, shmid, y_offset, u_offset, v_offset, w, h,
163 color_model, bytes_per_line);
166 VFrame::VFrame(BC_Bitmap *bitmap, int w, int h,
167 int color_model, long bytes_per_line)
170 params = new BC_Hash;
172 unsigned char *data = 0;
173 if( bitmap->is_shared() )
174 shmid = bitmap->get_shmid();
176 data = bitmap->get_data();
177 allocate_data(data, shmid,
178 bitmap->get_y_offset(),
179 bitmap->get_u_offset(),
180 bitmap->get_v_offset(),
181 w, h, color_model, bytes_per_line);
187 params = new BC_Hash;
188 this->color_model = BC_COMPRESSED;
196 // Delete effect stack
197 prev_effects.remove_all_objects();
198 next_effects.remove_all_objects();
203 int VFrame::equivalent(VFrame *src, int test_stacks)
205 return (src->get_color_model() == get_color_model() &&
206 src->get_w() == get_w() &&
207 src->get_h() == get_h() &&
208 src->bytes_per_line == bytes_per_line &&
209 (!test_stacks || equal_stacks(src)));
212 int VFrame::data_matches(VFrame *frame)
214 if(data && frame->get_data() &&
215 frame->params_match(get_w(), get_h(), get_color_model()) &&
216 get_data_size() == frame->get_data_size())
218 int data_size = get_data_size();
219 unsigned char *ptr1 = get_data();
220 unsigned char *ptr2 = frame->get_data();
221 for(int i = 0; i < data_size; i++)
223 if(*ptr1++ != *ptr2++) return 0;
230 // long VFrame::set_shm_offset(long offset)
232 // shm_offset = offset;
236 // long VFrame::get_shm_offset()
238 // return shm_offset;
241 int VFrame::get_memory_type()
246 int VFrame::params_match(int w, int h, int color_model)
248 return (this->w == w &&
250 this->color_model == color_model);
254 int VFrame::reset_parameters(int do_opengl)
259 memory_type = VFrame::PRIVATE;
267 compressed_allocated = 0;
268 compressed_size = 0; // Size of current image
275 sequence_number = -1;
278 pixel_rgb = 0x000000; // BLACK
279 pixel_yuv = 0x008080;
281 draw_flags = ALIAS_OFF;
283 clear_color = 0x000000;
288 // By default, anything is going to be done in RAM
289 opengl_state = VFrame::RAM;
294 prev_effects.set_array_delete();
295 next_effects.set_array_delete();
299 int VFrame::clear_objects(int do_opengl)
312 if( memory_type != VFrame::SHARED )
313 printf("==del %p from %p\n", data, __builtin_return_address(0));
319 case VFrame::PRIVATE:
321 // if(this->w * this->h > 1500 * 1100)
322 // printf("VFrame::clear_objects 2 this=%p data=%p\n", this, data);
325 //printf("VFrame::clear_objects %d this=%p shmid=%p data=%p\n", __LINE__, this, shmid, data);
337 case VFrame::SHM_GET:
345 // Delete row pointers
370 int VFrame::get_field2_offset()
372 return field2_offset;
375 int VFrame::set_field2_offset(int value)
377 this->field2_offset = value;
381 void VFrame::set_keyframe(int value)
383 this->is_keyframe = value;
386 int VFrame::get_keyframe()
391 void VFrame::get_temp(VFrame *&vfrm, int w, int h, int color_model)
393 if( vfrm && ( vfrm->color_model != color_model ||
394 vfrm->get_w() != w || vfrm->get_h() != h ) ) {
395 delete vfrm; vfrm = 0;
397 if( !vfrm ) vfrm = new VFrame(w, h, color_model, 0);
402 VFrameScene* VFrame::get_scene()
407 int VFrame::calculate_bytes_per_pixel(int color_model)
409 return BC_CModels::calculate_pixelsize(color_model);
412 long VFrame::get_bytes_per_line()
414 return bytes_per_line;
417 long VFrame::get_data_size()
419 return calculate_data_size(w, h, bytes_per_line, color_model) - BC_COLOR_ALIGN;
422 long VFrame::calculate_data_size(int w, int h, int bytes_per_line, int color_model)
424 return BC_CModels::calculate_datasize(w, h, bytes_per_line, color_model);
427 void VFrame::create_row_pointers()
430 switch(color_model) {
432 if( this->v_offset ) break;
435 this->v_offset = sz + w / 4 * h / 4;
441 if( this->v_offset ) break;
444 this->v_offset = sz + sz / 4;
448 if( this->v_offset ) break;
451 this->v_offset = sz + sz / 2;
454 if( this->v_offset ) break;
457 this->v_offset = sz + sz;
460 if( this->v_offset ) break;
462 this->u_offset = sz * sizeof(uint8_t);
463 this->v_offset = 2 * sz * sizeof(uint8_t);
466 if( this->v_offset || a ) break;
467 a = this->data + 3 * sz * sizeof(float);
469 if( this->v_offset ) break;
471 this->u_offset = sz * sizeof(float);
472 this->v_offset = 2 * sz * sizeof(float);
476 rows = new unsigned char*[h];
477 for(int i = 0; i < h; i++)
478 rows[i] = &this->data[i * this->bytes_per_line];
481 y = this->data + this->y_offset;
482 u = this->data + this->u_offset;
483 v = this->data + this->v_offset;
486 int VFrame::allocate_data(unsigned char *data, int shmid,
487 long y_offset, long u_offset, long v_offset, int w, int h,
488 int color_model, long bytes_per_line)
492 this->color_model = color_model;
493 this->bytes_per_pixel = calculate_bytes_per_pixel(color_model);
494 this->y_offset = this->u_offset = this->v_offset = 0;
496 // printf("VFrame::allocate_data %d shmid == 0\n", __LINE__, shmid);
499 this->bytes_per_line = bytes_per_line >= 0 ?
500 bytes_per_line : this->bytes_per_pixel * w;
502 // Allocate data + padding for MMX
504 //printf("VFrame::allocate_data %d %p\n", __LINE__, this->data);
505 memory_type = VFrame::SHARED;
508 this->y_offset = y_offset;
509 this->u_offset = u_offset;
510 this->v_offset = v_offset;
512 else if( shmid >= 0 ) {
513 memory_type = VFrame::SHM_GET;
514 this->data = (unsigned char*)shmat(shmid, NULL, 0);
515 if( this->data == (unsigned char*)-1 ) {
516 printf("VFrame::allocate_data %d could not attach"
517 " shared memory, %dx%d (model %d) shmid=0x%08x\n",
518 __LINE__, w, h, color_model, shmid);
519 BC_Trace::dump_shm_stats(stdout);
522 //printf("VFrame::allocate_data %d shmid=%d data=%p\n", __LINE__, shmid, this->data);
524 this->y_offset = y_offset;
525 this->u_offset = u_offset;
526 this->v_offset = v_offset;
529 memory_type = VFrame::PRIVATE;
531 int size = calculate_data_size(this->w, this->h,
532 this->bytes_per_line, this->color_model);
533 if( use_shm && size >= SHM_MIN_SIZE &&
534 BC_WindowBase::get_resources()->use_vframe_shm() ) {
535 this->shmid = shmget(IPC_PRIVATE, size, IPC_CREAT | 0777);
536 if( this->shmid >= 0 ) {
537 this->data = (unsigned char*)shmat(this->shmid, NULL, 0);
538 if( this->data == (unsigned char *)-1 ) this->data = 0;
541 printf("VFrame::allocate_data %d could not allocate"
542 " shared memory, %dx%d (model %d) size=0x%08x\n",
543 __LINE__, w, h, color_model, size);
544 BC_Trace::dump_shm_stats(stdout);
547 // This causes it to automatically delete when the program exits.
548 shmctl(this->shmid, IPC_RMID, 0);
551 this->data = (unsigned char *)malloc(size);
553 printf("VFrame::allocate_data %dx%d: memory exhausted.\n", this->w, this->h);
559 // if(this->w * this->h > 1500 * 1100)
560 // printf("VFrame::allocate_data 2 this=%p w=%d h=%d this->data=%p\n",
561 // this, this->w, this->h, this->data);
564 printf("==new %p from %p sz %d\n", this->data, __builtin_return_address(0), size);
567 //printf("VFrame::allocate_data %d %p data=%p %d %d\n", __LINE__, this, this->data, this->w, this->h);
568 //if(size > 1000000) printf("VFrame::allocate_data %d\n", size);
571 // Create row pointers
572 create_row_pointers();
576 void VFrame::set_memory(unsigned char *data,
586 memory_type = VFrame::SHARED;
589 this->y_offset = y_offset;
590 this->u_offset = u_offset;
591 this->v_offset = v_offset;
596 memory_type = VFrame::SHM_GET;
597 this->data = (unsigned char*)shmat(shmid, NULL, 0);
601 y = this->data + this->y_offset;
602 u = this->data + this->u_offset;
603 v = this->data + this->v_offset;
605 create_row_pointers();
608 void VFrame::set_memory(BC_Bitmap *bitmap)
611 unsigned char *data = 0;
612 if( bitmap->is_shared() && !bitmap->is_zombie() )
613 shmid = bitmap->get_shmid();
615 data = bitmap->get_data();
616 set_memory(data, shmid,
617 bitmap->get_y_offset(),
618 bitmap->get_u_offset(),
619 bitmap->get_v_offset());
622 void VFrame::set_compressed_memory(unsigned char *data,
631 memory_type = VFrame::SHARED;
638 memory_type = VFrame::SHM_GET;
639 this->data = (unsigned char*)shmat(shmid, NULL, 0);
643 this->compressed_allocated = data_allocated;
644 this->compressed_size = data_size;
648 // Reallocate uncompressed buffer with or without alpha
649 int VFrame::reallocate(
660 // if(shmid == 0) printf("VFrame::reallocate %d shmid=%d\n", __LINE__, shmid);
662 // reset_parameters(0);
675 int VFrame::allocate_compressed_data(long bytes)
677 if( bytes < 1 ) return 1;
679 // Want to preserve original contents
680 if( data && compressed_allocated < bytes ) {
682 unsigned char *new_data = 0;
683 if( BC_WindowBase::get_resources()->use_vframe_shm() && use_shm ) {
684 new_shmid = shmget(IPC_PRIVATE, bytes, IPC_CREAT | 0777);
685 if( new_shmid >= 0 ) {
686 new_data = (unsigned char *) shmat(new_shmid, NULL, 0);
687 if( new_data == (unsigned char *)-1 ) new_data = 0;
690 printf("VFrame::allocate_compressed_data %d could not allocate"
691 " shared memory, %ld\n", __LINE__, bytes);
692 BC_Trace::dump_shm_stats(stdout);
695 shmctl(new_shmid, IPC_RMID, 0);
698 // Have to use malloc for libpng
699 new_data = (unsigned char *)malloc(bytes);
701 printf("VFrame::allocate_compressed_data %ld: memory exhausted.\n", bytes);
706 bcopy(data, new_data, compressed_allocated);
709 if( memory_type == VFrame::PRIVATE ) {
711 if( data ) shmdt(data);
716 else if( memory_type == VFrame::SHM_GET ) {
717 if( data ) shmdt(data);
722 compressed_allocated = bytes;
725 if( BC_WindowBase::get_resources()->use_vframe_shm() && use_shm ) {
726 shmid = shmget(IPC_PRIVATE, bytes, IPC_CREAT | 0777);
728 data = (unsigned char *)shmat(shmid, NULL, 0);
729 if( data == (unsigned char *)-1 ) data = 0;
732 printf("VFrame::allocate_compressed_data %d: could not allocate"
733 " shared memory, %ld\n", __LINE__, bytes);
734 BC_Trace::dump_shm_stats(stdout);
737 shmctl(shmid, IPC_RMID, 0);
740 // Have to use malloc for libpng
741 data = (unsigned char *)malloc(bytes);
743 printf("VFrame::allocate_compressed_data %d: memory exhausted, %ld\n",
749 compressed_allocated = bytes;
756 int VFramePng::read_png(const unsigned char *data, long sz, double xscale, double yscale)
758 // Test for RAW format
759 if(data[0] == 'R' && data[1] == 'A' && data[2] == 'W' && data[3] == ' ') {
760 int new_color_model = BC_RGBA8888;
761 w = data[4] | (data[5] << 8) | (data[6] << 16) | (data[7] << 24);
762 h = data[8] | (data[9] << 8) | (data[10] << 16) | (data[11] << 24);
763 int components = data[12];
764 new_color_model = components == 3 ? BC_RGB888 : BC_RGBA8888;
765 // This shares the data directly
766 // reallocate(data + 20, 0, 0, 0, w, h, new_color_model, -1);
768 // Can't use shared data for theme since button constructions overlay the
770 reallocate(NULL, -1, 0, 0, 0, w, h, new_color_model, -1);
771 memcpy(get_data(), data + 16, w * h * components);
774 else if(data[0] == 0x89 && data[1] == 'P' && data[2] == 'N' && data[3] == 'G') {
776 png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
777 png_infop info_ptr = png_create_info_struct(png_ptr);
781 image = data; image_size = sz;
782 png_set_read_fn(png_ptr, this, PngReadFunction::png_read_function);
783 png_read_info(png_ptr, info_ptr);
785 w = png_get_image_width(png_ptr, info_ptr);
786 h = png_get_image_height(png_ptr, info_ptr);
788 int src_color_model = png_get_color_type(png_ptr, info_ptr);
790 /* tell libpng to strip 16 bit/color files down to 8 bits/color */
791 png_set_strip_16(png_ptr);
793 /* extract multiple pixels with bit depths of 1, 2, and 4 from a single
794 * byte into separate bytes (useful for paletted and grayscale images).
796 png_set_packing(png_ptr);
798 /* expand paletted colors into true RGB triplets */
799 if (src_color_model == PNG_COLOR_TYPE_PALETTE)
800 png_set_expand(png_ptr);
802 /* expand grayscale images to the full 8 bits from 1, 2, or 4 bits/pixel */
803 if (src_color_model == PNG_COLOR_TYPE_GRAY && png_get_bit_depth(png_ptr, info_ptr) < 8)
804 png_set_expand(png_ptr);
806 if (src_color_model == PNG_COLOR_TYPE_GRAY_ALPHA)
807 png_set_gray_to_rgb(png_ptr);
809 /* expand paletted or RGB images with transparency to full alpha channels
810 * so the data will be available as RGBA quartets */
811 if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)){
813 png_set_expand(png_ptr);
816 switch(src_color_model) {
817 case PNG_COLOR_TYPE_GRAY:
818 new_color_model = BC_GREY8;
820 case PNG_COLOR_TYPE_RGB:
821 new_color_model = BC_RGB888;
823 case PNG_COLOR_TYPE_PALETTE:
824 new_color_model = have_alpha ? BC_RGBA8888 : BC_RGB888;
826 case PNG_COLOR_TYPE_GRAY_ALPHA:
827 case PNG_COLOR_TYPE_RGB_ALPHA:
829 new_color_model = BC_RGBA8888;
832 reallocate(NULL, -1, 0, 0, 0, w, h, new_color_model, -1);
834 //printf("VFrame::read_png %d %d %d %p\n", __LINE__, w, h, get_rows());
835 png_read_image(png_ptr, get_rows());
836 png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
839 printf("VFrame::read_png %d: unknown file format"
840 " 0x%02x 0x%02x 0x%02x 0x%02x\n",
841 __LINE__, data[4], data[5], data[6], data[7]);
844 int ww = w * xscale, hh = h * yscale;
847 if( ww != w || hh != h ) {
848 VFrame vframe(*this);
849 reallocate(NULL, -1, 0, 0, 0, ww, hh, color_model, -1);
850 transfer_from(&vframe);
855 int VFrame::write_png(const char *path)
857 VFrame *vframe = this;
858 png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
859 png_infop info_ptr = png_create_info_struct(png_ptr);
860 FILE *out_fd = fopen(path, "w");
862 printf("VFrame::write_png %d %s %s\n", __LINE__, path, strerror(errno));
866 int png_cmodel = PNG_COLOR_TYPE_RGB;
867 int bc_cmodel = get_color_model();
868 switch( bc_cmodel ) {
869 case BC_RGB888: break;
870 case BC_RGBA8888: png_cmodel = PNG_COLOR_TYPE_RGB_ALPHA; break;
871 case BC_A8: png_cmodel = PNG_COLOR_TYPE_GRAY; break;
873 bc_cmodel = BC_RGB888;
874 if( BC_CModels::has_alpha(bc_cmodel) ) {
875 bc_cmodel = BC_RGBA8888;
876 png_cmodel = PNG_COLOR_TYPE_RGB_ALPHA;
878 vframe = new VFrame(get_w(), get_h(), bc_cmodel, 0);
879 vframe->transfer_from(this);
882 png_init_io(png_ptr, out_fd);
883 png_set_compression_level(png_ptr, 9);
884 png_set_IHDR(png_ptr, info_ptr, get_w(), get_h(), 8, png_cmodel,
885 PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
886 png_write_info(png_ptr, info_ptr);
887 png_write_image(png_ptr, vframe->get_rows());
888 png_write_end(png_ptr, info_ptr);
889 png_destroy_write_struct(&png_ptr, &info_ptr);
891 if( vframe != this ) delete vframe;
895 void VFrame::write_ppm(VFrame *vfrm, const char *fmt, ...)
900 vsnprintf(fn, sizeof(fn), fmt, ap);
902 FILE *fp = fopen(fn,"w");
903 if( !fp ) { perror("write_ppm"); return; }
905 if( frm->get_color_model() != BC_RGB888 ) {
906 frm = new VFrame(frm->get_w(), frm->get_h(), BC_RGB888);
907 frm->transfer_from(vfrm);
909 int w = frm->get_w(), h = frm->get_h();
910 fprintf(fp,"P6\n%d %d\n255\n",w,h);
911 unsigned char **rows = frm->get_rows();
912 for( int i=0; i<h; ++i ) fwrite(rows[i],3,w,fp);
914 if( frm != vfrm ) delete frm;
918 #define ZERO_YUV(components, type, max) \
920 for(int i = 0; i < h; i++) \
922 type *row = (type*)get_rows()[i]; \
923 for(int j = 0; j < w; j++) \
925 row[j * components] = 0; \
926 row[j * components + 1] = (max + 1) / 2; \
927 row[j * components + 2] = (max + 1) / 2; \
928 if(components == 4) row[j * components + 3] = 0; \
933 void VFrame::black_frame()
936 //printf("VFrame::black_frame %d\n", __LINE__);
937 switch(color_model) {
943 memset(get_u(), 0x80, w / 4 * h / 4);
944 memset(get_v(), 0x80, w / 4 * h / 4);
951 memset(get_u(), 0x80, sz / 4);
952 memset(get_v(), 0x80, sz / 4);
957 memset(get_u(), 0x80, sz / 2);
958 memset(get_v(), 0x80, sz / 2);
967 case BC_RGBA_FLOATP: if( a ) {
968 float *ap = (float *)a;
969 for( int i=sz; --i>=0; ++ap ) *ap = 0.f; }
970 case BC_RGB_FLOATP: {
971 float *rp = (float *)y;
972 for( int i=sz; --i>=0; ++rp ) *rp = 0.f;
973 float *gp = (float *)u;
974 for( int i=sz; --i>=0; ++gp ) *gp = 0.f;
975 float *bp = (float *)v;
976 for( int i=sz; --i>=0; ++bp ) *bp = 0.f;
980 memset(get_u(), 0x80, sz);
981 memset(get_v(), 0x80, sz);
985 ZERO_YUV(3, unsigned char, 0xff);
989 ZERO_YUV(4, unsigned char, 0xff);
993 ZERO_YUV(3, uint16_t, 0xffff);
996 case BC_YUVA16161616:
997 ZERO_YUV(4, uint16_t, 0xffff);
1001 bzero(data, calculate_data_size(w, h, bytes_per_line, color_model));
1006 void VFrame::set_clear_color(int color, int alpha)
1008 clear_color = color;
1009 clear_alpha = alpha;
1011 int VFrame::get_clear_color() { return clear_color; }
1012 int VFrame::get_clear_alpha() { return clear_alpha; }
1014 void VFrame::clear_frame()
1016 if( clear_color >= 0 &&
1017 !BC_CModels::init_color(clear_color, clear_alpha,
1018 get_rows(), get_color_model(), get_y(), get_u(), get_v(),
1019 0,0, get_w(),get_h(), get_bytes_per_line()) )
1024 void VFrame::rotate90()
1026 // Allocate new frame
1027 int new_w = h, new_h = w;
1028 VFrame new_frame(new_w, new_h, color_model);
1029 unsigned char **new_rows = new_frame.get_rows();
1031 for(int in_y = 0, out_x = new_w - 1; in_y < h; in_y++, out_x--)
1033 for(int in_x = 0, out_y = 0; in_x < w; in_x++, out_y++)
1035 for(int k = 0; k < bytes_per_pixel; k++)
1037 new_rows[out_y][out_x * bytes_per_pixel + k] =
1038 rows[in_y][in_x * bytes_per_pixel + k];
1045 unsigned char *new_data = new_frame.data;
1046 new_frame.data = data;
1049 new_rows = new_frame.rows;
1050 new_frame.rows = rows;
1053 int new_shmid = new_frame.shmid;
1054 new_frame.shmid = shmid;
1056 // swap bytes_per_line
1057 int new_bpl = new_frame.bytes_per_line;
1058 new_frame.bytes_per_line = bytes_per_line;
1059 bytes_per_line = new_bpl;
1060 new_frame.clear_objects(0);
1066 void VFrame::rotate270()
1068 // Allocate new frame
1069 int new_w = h, new_h = w;
1070 VFrame new_frame(new_w, new_h, color_model);
1071 unsigned char **new_rows = new_frame.get_rows();
1073 for(int in_y = 0, out_x = 0; in_y < h; in_y++, out_x++)
1075 for(int in_x = 0, out_y = new_h - 1; in_x < w; in_x++, out_y--)
1077 for(int k = 0; k < bytes_per_pixel; k++)
1079 new_rows[out_y][out_x * bytes_per_pixel + k] =
1080 rows[in_y][in_x * bytes_per_pixel + k];
1087 unsigned char *new_data = new_frame.data;
1088 new_frame.data = data;
1091 new_rows = new_frame.rows;
1092 new_frame.rows = rows;
1095 int new_shmid = new_frame.shmid;
1096 new_frame.shmid = shmid;
1098 // swap bytes_per_line
1099 int new_bpl = new_frame.bytes_per_line;
1100 new_frame.bytes_per_line = bytes_per_line;
1101 bytes_per_line = new_bpl;
1102 new_frame.clear_objects(0);
1108 void VFrame::flip_vert()
1110 unsigned char temp[bytes_per_line];
1111 for( int i=0, j=h; --j>i; ++i ) {
1112 memcpy(temp, rows[j], bytes_per_line);
1113 memcpy(rows[j], rows[i], bytes_per_line);
1114 memcpy(rows[i], temp, bytes_per_line);
1118 void VFrame::flip_horiz()
1120 unsigned char temp[32];
1121 for(int i = 0; i < h; i++)
1123 unsigned char *row = rows[i];
1124 for(int j = 0; j < bytes_per_line / 2; j += bytes_per_pixel)
1126 memcpy(temp, row + j, bytes_per_pixel);
1127 memcpy(row + j, row + bytes_per_line - j - bytes_per_pixel, bytes_per_pixel);
1128 memcpy(row + bytes_per_line - j - bytes_per_pixel, temp, bytes_per_pixel);
1135 int VFrame::copy_from(VFrame *frame)
1137 if( this->w != frame->get_w() ||
1138 this->h != frame->get_h() ) {
1139 printf("VFrame::copy_from %d sizes differ src %dx%d != dst %dx%d\n",
1140 __LINE__, frame->get_w(), frame->get_h(), get_w(), get_h());
1144 int w = MIN(this->w, frame->get_w());
1145 int h = MIN(this->h, frame->get_h());
1146 timestamp = frame->timestamp;
1148 switch( frame->color_model ) {
1150 allocate_compressed_data(frame->compressed_size);
1151 memcpy(data, frame->data, frame->compressed_size);
1152 this->compressed_size = frame->compressed_size;
1156 memcpy(get_y(), frame->get_y(), w * h);
1157 memcpy(get_u(), frame->get_u(), w / 4 * h / 4);
1158 memcpy(get_v(), frame->get_v(), w / 4 * h / 4);
1164 //printf("%d %d %p %p %p %p %p %p\n", w, h, get_y(), get_u(), get_v(), frame->get_y(), frame->get_u(), frame->get_v());
1165 memcpy(get_y(), frame->get_y(), w * h);
1166 memcpy(get_u(), frame->get_u(), w * h / 4);
1167 memcpy(get_v(), frame->get_v(), w * h / 4);
1171 //printf("%d %d %p %p %p %p %p %p\n", w, h, get_y(), get_u(), get_v(), frame->get_y(), frame->get_u(), frame->get_v());
1172 memcpy(get_y(), frame->get_y(), w * h);
1173 memcpy(get_u(), frame->get_u(), w * h / 2);
1174 memcpy(get_v(), frame->get_v(), w * h / 2);
1178 //printf("%d %d %p %p %p %p %p %p\n", w, h, get_y(), get_u(), get_v(), frame->get_y(), frame->get_u(), frame->get_v());
1179 memcpy(get_y(), frame->get_y(), w * h);
1180 memcpy(get_u(), frame->get_u(), w * h);
1181 memcpy(get_v(), frame->get_v(), w * h);
1184 // printf("VFrame::copy_from %d\n", calculate_data_size(w, h, -1, frame->color_model));
1185 // Copy without extra 4 bytes in case the source is a hardware device
1186 memmove(data, frame->data, get_data_size());
1193 int VFrame::transfer_from(VFrame *that, int bg_color, int in_x, int in_y, int in_w, int in_h)
1195 timestamp = that->timestamp;
1198 if( in_x == 0 && in_y == 0 && in_w == that->get_w() && in_h == that->get_h() &&
1199 bg_color == 0 && this->get_color_model() == that->get_color_model() &&
1200 this->get_w() == that->get_w() && this->get_h() == that->get_h() &&
1201 this->get_bytes_per_line() == that->get_bytes_per_line() )
1202 return this->copy_from(that);
1205 BC_CModels::transfer(
1206 this->get_rows(), that->get_rows(), // Packed data out/in
1207 this->get_y(), this->get_u(), this->get_v(), // Planar data out/in
1208 that->get_y(), that->get_u(), that->get_v(),
1209 0, 0, that->get_w(), that->get_h(), // Dimensions in/out
1210 0, 0, this->get_w(), this->get_h(),
1211 that->get_color_model(), this->get_color_model(), // Color models in/out
1212 bg_color, // alpha blend bg_color
1213 that->get_bytes_per_line(),
1214 this->get_bytes_per_line()); // rowspans (of luma for YUV)
1216 unsigned char *in_ptrs[4], *out_ptrs[4];
1217 unsigned char **inp, **outp;
1218 if( BC_CModels::is_planar(that->get_color_model()) ) {
1219 in_ptrs[0] = that->get_y();
1220 in_ptrs[1] = that->get_u();
1221 in_ptrs[2] = that->get_v();
1222 in_ptrs[3] = that->get_a();
1226 inp = that->get_rows();
1227 if( BC_CModels::is_planar(this->get_color_model()) ) {
1228 out_ptrs[0] = this->get_y();
1229 out_ptrs[1] = this->get_u();
1230 out_ptrs[2] = this->get_v();
1231 out_ptrs[3] = this->get_a();
1235 outp = this->get_rows();
1236 BC_CModels::transfer(outp, this->get_color_model(),
1237 0, 0, this->get_w(), this->get_h(),
1238 this->get_bytes_per_line(),
1239 inp, that->get_color_model(),
1240 in_x, in_y, in_w, in_h,
1241 that->get_bytes_per_line(),
1248 int VFrame::get_scale_tables(int *column_table, int *row_table,
1249 int in_x1, int in_y1, int in_x2, int in_y2,
1250 int out_x1, int out_y1, int out_x2, int out_y2)
1253 float w_in = in_x2 - in_x1;
1254 float h_in = in_y2 - in_y1;
1255 int w_out = out_x2 - out_x1;
1256 int h_out = out_y2 - out_y1;
1258 float hscale = w_in / w_out;
1259 float vscale = h_in / h_out;
1261 for(i = 0; i < w_out; i++)
1263 column_table[i] = (int)(hscale * i);
1266 for(i = 0; i < h_out; i++)
1268 row_table[i] = (int)(vscale * i) + in_y1;
1273 void VFrame::push_prev_effect(const char *name)
1276 prev_effects.append(ptr = new char[strlen(name) + 1]);
1278 if(prev_effects.total > MAX_STACK_ELEMENTS) prev_effects.remove_object(0);
1281 void VFrame::pop_prev_effect()
1283 if(prev_effects.total)
1284 prev_effects.remove_object(prev_effects.last());
1287 void VFrame::push_next_effect(const char *name)
1290 next_effects.append(ptr = new char[strlen(name) + 1]);
1292 if(next_effects.total > MAX_STACK_ELEMENTS) next_effects.remove_object(0);
1295 void VFrame::pop_next_effect()
1297 if(next_effects.total)
1298 next_effects.remove_object(next_effects.last());
1301 const char* VFrame::get_next_effect(int number)
1303 if(!next_effects.total) return "";
1305 if(number > next_effects.total - 1) number = next_effects.total - 1;
1307 return next_effects.values[next_effects.total - number - 1];
1310 const char* VFrame::get_prev_effect(int number)
1312 if(!prev_effects.total) return "";
1314 if(number > prev_effects.total - 1) number = prev_effects.total - 1;
1316 return prev_effects.values[prev_effects.total - number - 1];
1319 BC_Hash* VFrame::get_params()
1324 void VFrame::clear_stacks()
1326 next_effects.remove_all_objects();
1327 prev_effects.remove_all_objects();
1332 void VFrame::copy_params(VFrame *src)
1334 status = src->status;
1335 params->copy_from(src->params);
1338 void VFrame::copy_stacks(VFrame *src)
1342 for( int i=0; i < src->next_effects.total; ++i )
1343 next_effects.append(cstrdup(src->next_effects[i]));
1344 for( int i=0; i < src->prev_effects.total; ++i )
1345 prev_effects.append(cstrdup(src->prev_effects[i]));
1350 int VFrame::copy_vframe(VFrame *frame)
1353 return copy_from(frame);
1356 int VFrame::equal_stacks(VFrame *src)
1358 for(int i = 0; i < src->next_effects.total && i < next_effects.total; i++)
1360 if(strcmp(src->next_effects.values[i], next_effects.values[i])) return 0;
1363 for(int i = 0; i < src->prev_effects.total && i < prev_effects.total; i++)
1365 if(strcmp(src->prev_effects.values[i], prev_effects.values[i])) return 0;
1368 if(!params->equivalent(src->params)) return 0;
1372 void VFrame::dump_stacks()
1374 printf("VFrame::dump_stacks\n");
1375 printf(" next_effects:\n");
1376 for(int i = next_effects.total - 1; i >= 0; i--)
1377 printf(" %s\n", next_effects.values[i]);
1378 printf(" prev_effects:\n");
1379 for(int i = prev_effects.total - 1; i >= 0; i--)
1380 printf(" %s\n", prev_effects.values[i]);
1383 void VFrame::dump_params()
1390 printf("VFrame::dump %d this=%p\n", __LINE__, this);
1391 printf(" w=%d h=%d colormodel=%d rows=%p use_shm=%d shmid=%d\n",
1392 w, h, color_model, rows, use_shm, shmid);
1396 int VFrame::get_memory_usage()
1398 if(get_compressed_allocated()) return get_compressed_allocated();
1399 return get_h() * get_bytes_per_line();
1402 // rgb component colors (eg. from colors.h)
1403 // a (~alpha) transparency, 0x00==solid .. 0xff==transparent
1404 void VFrame::set_pixel_color(int rgb, int a)
1406 pixel_rgb = (~(unsigned int)a<<24) | (rgb&0xffffff);
1407 int ir = 0xff & (pixel_rgb >> 16);
1408 int ig = 0xff & (pixel_rgb >> 8);
1409 int ib = 0xff & (pixel_rgb >> 0);
1410 YUV::yuv.rgb_to_yuv_8(ir, ig, ib);
1411 pixel_yuv = (~(unsigned int)a<<24) | (ir<<16) | (ig<<8) | (ib<<0);
1414 void VFrame::set_stiple(int mask)
1418 void VFrame::set_draw_alpha(float alpha)
1422 void VFrame::set_draw_flags(int flags)
1427 int VFrame::draw_pixel(float x, float y, float a)
1430 if( ix < 0 || iy < 0 || ix >= get_w() || iy >= get_h() ) return 1;
1431 if( a <= 0 ) return 0;
1433 int color = BC_CModels::is_yuv(color_model) ? pixel_yuv : pixel_rgb;
1434 float fr = 0, fg = 0, fb = 0, fa = 0;
1435 int ir = (0xff & (color >> 16));
1436 int ig = (0xff & (color >> 8));
1437 int ib = (0xff & (color >> 0));
1438 int ia = (0xff & ~(color >> 24)); // transparency, not opacity
1439 if( (ix+iy) & stipple ) {
1440 ir = 255 - ir; ig = 255 - ig; ib = 255 - ib;
1442 int rr = (ir<<8) | ir, gg = (ig<<8) | ig, bb = (ib<<8) | ib, aa = (ia<<8) | ia;
1443 float fmax = 65535.f; fa = aa/fmax;
1444 if( BC_CModels::is_float(color_model) ) {
1445 fr = rr/fmax; fg = gg/fmax; fb = bb/fmax;
1448 #define DRAW_PIXEL(cmdl, type, r, g, b, ofs, max, comps) \
1450 float src_a = fa*draw_alpha, src_1a = 1 - src_a; \
1451 type **rows = (type**)get_rows(); \
1452 type *rp = rows[iy], *bp = rp + ix*comps; \
1453 bp[0] = src_a * r + src_1a * bp[0]; \
1455 bp[1] = src_a * (g-ofs) + src_1a * (bp[1]-ofs) + ofs; \
1456 bp[2] = src_a * (b-ofs) + src_1a * (bp[2]-ofs) + ofs; \
1459 bp[3] = src_a * max + src_1a * bp[3]; \
1463 switch(get_color_model()) {
1464 DRAW_PIXEL(BC_A8, uint8_t, ib, 0, 0, 0x00, 0xff, 1);
1465 DRAW_PIXEL(BC_RGB888, uint8_t, ir, ig, ib, 0x00, 0xff, 3);
1466 DRAW_PIXEL(BC_YUV888, uint8_t, ir, ig, ib, 0x80, 0xff, 3);
1467 DRAW_PIXEL(BC_RGBA8888, uint8_t, ir, ig, ib, 0x00, 0xff, 4);
1468 DRAW_PIXEL(BC_YUVA8888, uint8_t, ir, ig, ib, 0x80, 0xff, 4);
1469 DRAW_PIXEL(BC_RGB161616, uint16_t, rr, gg, bb, 0x0000, 0xffff, 3);
1470 DRAW_PIXEL(BC_YUV161616, uint16_t, rr, gg, bb, 0x8000, 0xffff, 3);
1471 DRAW_PIXEL(BC_RGBA16161616, uint16_t, rr, gg, bb, 0x0000, 0xffff, 4);
1472 DRAW_PIXEL(BC_YUVA16161616, uint16_t, rr, gg, bb, 0x8000, 0xffff, 4);
1473 DRAW_PIXEL(BC_RGB_FLOAT, float, fr, fg, fb, 0., 1., 3);
1474 DRAW_PIXEL(BC_RGBA_FLOAT, float, fr, fg, fb, 0., 1., 4);
1479 int VFrame::draw_pixel(float x, float y, float frac, int axis)
1482 int xs = axis, ys = 1-axis;
1483 if( draw_flags & ALIAS_TOP ) draw_pixel(x-xs, y-ys, 1-frac);
1484 draw_pixel(x, y, draw_flags & ALIAS_CTR ? 1-frac : 1);
1485 if( draw_flags & ALIAS_BOT ) draw_pixel(x+xs, y+ys, frac);
1492 void VFrame::draw_line(float x1, float y1, float x2, float y2)
1495 int tx = x1; x1 = x2; x2 = tx;
1496 int ty = y1; y1 = y2; y2 = ty;
1498 float dx = x2-x1, dy = y2-y1;
1499 float s = dx ? dy/dx : 1;
1500 float t = dy ? dx/dy : 0;
1501 int xs = dx < 0 ? -1 : 1;
1503 int idx = (int)x2 - (int)x1;
1504 int idy = (int)y2 - (int)y1;
1505 int d = dx >= dy ? abs(idx) : idy;
1506 float x = x1, y = y1;
1508 draw_pixel(x, y, y-(int)y, 0);
1510 y = y1 + ((x += xs) - x1) * s;
1511 draw_pixel(x, y, y-(int)y, 0);
1515 draw_pixel(x, y, x-(int)x, 1);
1517 x = x1 + (++y - y1) * t;
1518 draw_pixel(x, y, x-(int)x, 1);
1523 // g++ -dD -E - < /dev/null | grep DBL_EPSILON
1524 #ifndef __DBL_EPSILON__
1525 #define __DBL_EPSILON__ ((double)2.22044604925031308085e-16L)
1527 // weakest fraction * graphics integer range
1528 #define RND_EPSILON (__DBL_EPSILON__*65536)
1531 int rnd(double v) { return round(v)+RND_EPSILON; }
1534 int sx, sy, ex, ey; /* current point, end point */
1535 int xs, ys; /* x/y quadrant sign -1/1 */
1536 int64_t A, B, C; /* quadratic coefficients */
1537 int64_t r, dx, dy; /* residual, dr/dx and dr/dy */
1538 int xmxx, xmxy; /* x,y at apex */
1541 void init0(int x1,int y1, int x2,int y2, int x3,int y3, int top);
1542 void init1(int x1,int y1, int x2,int y2, int x3,int y3);
1543 int64_t rx() { return r + xs*8*dx + 4*A; }
1544 void moveX(int64_t r) {
1545 dx += xs*A; dy -= xs*B;
1546 this->r = r; sx += xs;
1548 int64_t ry() { return r + 8*dy + 4*C; }
1549 void moveY(int64_t r) {
1555 smooth_line(VFrame *vframe) { this->vframe = vframe; this->done = 0; }
1559 void smooth_line::draw()
1562 if( abs(dy) >= abs(dx) ) {
1563 if( xs*(sx-xmxx) >= 0 ) {
1564 if( ys > 0 ) { done = 1; return; }
1565 if( dy < 0 || ry() < 0 ) { moveY(ry()); goto xit; }
1566 xmxx = ex; xmxy = ey;
1571 if( abs(rr) < abs(r) )
1576 if( ys > 0 ) { done = 1; return; }
1577 xmxx = ex; xmxy = ey;
1582 if( abs(rr) < abs(r) )
1586 // vframe->draw_pixel(sx, sy);
1587 float vx = abs(dx), vy = abs(dy);
1588 float vv = 4*(vx > vy ? dx : dy);
1589 float frac = vv ? -r / vv : 0;
1590 frac = (1+frac) / 2;
1592 int axis = abs(dx) >= abs(dy) ? 1 : 0;
1593 vframe->draw_pixel(sx, sy, frac, axis);
1596 void VFrame::draw_smooth(int x1, int y1, int x2, int y2, int x3, int y3)
1598 if( (x1 == x2 && y1 == y2) || (x2 == x3 && y2 == y3) )
1599 draw_line(x1,y1, x3,y3);
1600 else if( x1 == x3 && y1 == y3 )
1601 draw_line(x1,y1, x2,y2);
1602 else if( (x2-x1) * (y2-y3) == (x2-x3) * (y2-y1) ) {
1603 // co-linear, draw line from min to max
1605 if( x2 < x1 ) { x1 = x2; y1 = y2; }
1606 if( x2 > x3 ) { x3 = x2; y3 = y2; }
1609 if( x2 > x1 ) { x1 = x2; y1 = y2; }
1610 if( x2 < x3 ) { x3 = x2; y3 = y2; }
1612 draw_line(x1,y1, x3,y3);
1615 smooth_draw(x1, y1, x2, y2, x3, y3);
1619 Non-Parametric Smooth Curve Generation. Don Kelly 1984
1626 Let the starting point be P. the ending point R. and the tangent vertex Q.
1627 A general point Z on the curve is then
1628 Z = (P + R - Q) + (Q - P) sin t + (Q - R) cos t
1630 Expanding the Cartesian coordinates around (P + R - Q) gives
1631 [x y] = Z - (P + R - Q)
1634 x = a*sin(t) + b*cos(t)
1635 y = c*sin(t) + d*cos(t)
1637 from which t can now be eliminated via
1638 c*x - a*y = (c*b - a*d)*cos(t)
1639 d*x - b*y = (a*d - c*b)*sin(t)
1641 giving the Cartesian equation for the ellipse as
1642 f(x, y) = (c*x - a*y)**2 + (d*x - b*y)**2 - (a*d - c*b)**2 = 0
1644 or: f(x, y) = A*x**2 - 2*B*x*y + C*y**2 + B**2 - A*C = 0
1645 where: A = c**2 + d**2, B = a*c + b*d, C = a**2 + b**2
1647 The maximum y extent of the ellipse may now be derived as follows:
1648 let df/dx = 0, 2*A*x = 2*B*y, x = y*B/A
1649 f(x, y) == B**2 * y**2 / A - 2*B**2 * y**2 / A + C*y**2 + B**2 - A*C = 0
1650 (A*C - B**2)*y = (A*C - B**2)*A
1651 max x = sqrt(C), at y = B/sqrt(C)
1652 max y = sqrt(A), at x = B/sqrt(A)
1657 /* x1,y1 = P, x2,y2 = Q, x3,y3=R,
1658 * draw from P to Q to R if top=0
1659 * or from P to (x,ymax) if top>0
1660 * or from Q to (x,ymax) if top<0
1662 void smooth_line::init0(int x1,int y1, int x2,int y2, int x3,int y3, int top)
1664 int x0 = x1+x3-x2, y0 = y1+y3-y2; // Q'
1666 int a = x2-x1, c = y2-y1;
1667 int b = x2-x3, d = y2-y3;
1668 A = c*c + d*d; C = a*a + b*b; B = a*c + b*d;
1670 sx = top >= 0 ? x1 : x3;
1671 sy = top >= 0 ? y1 : y3;
1672 xs = x2 > sx || (x2==sx && (x1+x3-sx)>=x2) ? 1 : -1;
1673 int64_t px = sx-x0, py = sy-y0;
1674 dx = A*px - B*py; dy = C*py - B*px;
1678 double ymy = sqrt(A), ymx = B/ymy;
1686 ys = a*b > 0 && (!top || top*xs*(b*c - a*d) > 0) ? -1 : 1;
1688 double xmx = xs*sqrt(C), xmy = B/xmx;
1689 xmxx = x0 + rnd(xmx);
1690 xmxy = y0 + rnd(xmy);
1693 xmxx = ex; xmxy = ey;
1697 /* x1,y1 = P, x2,y2 = Q, x3,y3=R,
1698 * draw from (x,ymax) to P
1700 void smooth_line::init1(int x1,int y1, int x2,int y2, int x3,int y3)
1702 int x0 = x1+x3-x2, y0 = y1+y3-y2; // Q'
1704 int a = x2-x1, c = y2-y1;
1705 int b = x2-x3, d = y2-y3;
1706 A = c*c + d*d; C = a*a + b*b; B = a*c + b*d;
1708 double ymy = -sqrt(A), ymx = B/ymy;
1709 int64_t px = rnd(ymx), py = rnd(ymy);
1710 sx = x0 + px; ex = x1;
1711 sy = y0 + py; ey = y1;
1712 xs = x2 > x1 || (x2==x1 && x3>=x2) ? 1 : -1;
1713 dx = A*px - B*py; dy = C*py - B*px;
1714 r = 4 * (A*px*px - 2*B*px*py + C*py*py + B*B - A*C);
1716 ys = a*b > 0 && xs*(b*c - a*d) < 0 ? -1 : 1;
1718 double xmx = xs*sqrt(C), xmy = B/xmx;
1719 xmxx = x0 + rnd(xmx);
1720 xmxy = y0 + rnd(xmy);
1724 xmxx = ex; xmxy = ey;
1727 vframe->draw_pixel(sx, sy, 0, 0);
1728 while( xs*(sx-xmxx) < 0 && (xs*dx < 0 || rx() < 0) ) {
1730 vframe->draw_pixel(sx, sy, 0, 0);
1735 void VFrame::smooth_draw(int x1, int y1, int x2, int y2, int x3, int y3)
1737 //printf("p smooth_draw( %d,%d, %d,%d, %d,%d )\n", x1,y1,x2,y2,x3,y3);
1738 if( y1 > y3 ) { // make y3 >= y1
1739 int xt = x1; x1 = x3; x3 = xt;
1740 int yt = y1; y1 = y3; y3 = yt;
1742 if( y1 > y2 && y3 > y2 ) {
1743 smooth_line lt(this), rt(this); // Q on bottom
1744 lt.init1(x1, y1, x2, y2, x3, y3);
1745 rt.init1(x3, y3, x2, y2, x1, y1);
1746 while( !lt.done || !rt.done ) {
1751 else if( y1 < y2 && y3 < y2 ) {
1752 smooth_line lt(this), rt(this); // Q on top
1753 lt.init0(x1, y1, x2, y2, x3, y3, 1);
1754 draw_pixel(lt.sx, lt.sy, 0, 0);
1755 rt.init0(x1, y1, x2, y2, x3, y3, -1);
1756 draw_pixel(rt.sx, rt.sy, 0, 0);
1757 while( !lt.done || !rt.done ) {
1763 smooth_line pt(this); // Q in between
1764 pt.init0(x1, y1, x2, y2, x3, y3, 0);
1765 draw_pixel(pt.sx, pt.sy, 0, 1);
1773 void VFrame::draw_rect(int x1, int y1, int x2, int y2)
1775 draw_line(x1, y1, x2, y1);
1776 draw_line(x2, y1 + 1, x2, y2);
1777 draw_line(x2 - 1, y2, x1, y2);
1778 draw_line(x1, y2 - 1, x1, y1 + 1);
1782 void VFrame::draw_oval(int x1, int y1, int x2, int y2)
1786 int center_x = (x2 + x1) / 2;
1787 int center_y = (y2 + y1) / 2;
1790 //printf("VFrame::draw_oval %d %d %d %d %d\n", __LINE__, x1, y1, x2, y2);
1792 for(int i = 0; i < h / 2; i++) {
1793 // A^2 = -(B^2) + C^2
1794 x_table[i] = (int)(sqrt(-SQR(h / 2 - i) + SQR(h / 2)) * w / h);
1795 //printf("VFrame::draw_oval %d i=%d x=%d\n", __LINE__, i, x_table[i]);
1798 for(int i = 0; i < h / 2 - 1; i++) {
1799 int x3 = x_table[i];
1800 int x4 = x_table[i + 1];
1803 for(int j = x3; j < x4; j++) {
1804 draw_pixel(center_x + j, y1 + i);
1805 draw_pixel(center_x - j, y1 + i);
1806 draw_pixel(center_x + j, y2 - i - 1);
1807 draw_pixel(center_x - j, y2 - i - 1);
1811 draw_pixel(center_x + x3, y1 + i);
1812 draw_pixel(center_x - x3, y1 + i);
1813 draw_pixel(center_x + x3, y2 - i - 1);
1814 draw_pixel(center_x - x3, y2 - i - 1);
1818 draw_pixel(center_x, y1);
1819 draw_pixel(center_x, y2 - 1);
1820 draw_pixel(x1, center_y);
1821 draw_pixel(x2 - 1, center_y);
1822 draw_pixel(x1, center_y - 1);
1823 draw_pixel(x2 - 1, center_y - 1);
1827 void VFrame::draw_arrow(int x1, int y1, int x2, int y2, int sz)
1829 double angle = atan((float)(y2 - y1) / (float)(x2 - x1));
1830 double angle1 = angle + (float)145 / 360 * 2 * M_PI;
1831 double angle2 = angle - (float)145 / 360 * 2 * M_PI;
1832 int s = x2 < x1 ? -1 : 1;
1833 int x3 = x2 + s * (int)(sz * cos(angle1));
1834 int y3 = y2 + s * (int)(sz * sin(angle1));
1835 int x4 = x2 + s * (int)(sz * cos(angle2));
1836 int y4 = y2 + s * (int)(sz * sin(angle2));
1839 draw_line(x1, y1, x2, y2);
1840 // draw_line(x1, y1 + 1, x2, y2 + 1);
1843 if(abs(y2 - y1) || abs(x2 - x1)) draw_line(x2, y2, x3, y3);
1845 if(abs(y2 - y1) || abs(x2 - x1)) draw_line(x2, y2, x4, y4);
1848 void VFrame::draw_x(int x, int y, int sz)
1850 draw_line(x-sz,y-sz, x+sz,y+sz);
1851 draw_line(x+sz,y-sz, x-sz,y+sz);
1853 void VFrame::draw_t(int x, int y, int sz)
1855 draw_line(x,y-sz, x,y+sz);
1856 draw_line(x+sz,y, x-sz,y);
1861 class jpeg_err : public jpeg_error_mgr
1863 static void s_error_exit(j_common_ptr cp);
1864 static void s_output_message(j_common_ptr cp);
1867 jpeg_std_error((jpeg_error_mgr *)this);
1868 error_exit = s_error_exit;
1869 output_message = s_output_message;
1874 class jpeg_src : public jpeg_source_mgr
1876 static void s_init_source(j_decompress_ptr jp);
1877 static boolean s_fill_input_buffer(j_decompress_ptr jp);
1878 static void s_skip_input_data(j_decompress_ptr jp, long len);
1879 static void s_term_source(j_decompress_ptr jp);
1880 static boolean s_resync_to_restart(j_decompress_ptr jp, int v);
1884 int jpeg_file(int fd);
1885 int jpeg_mem(const unsigned char *bfr, long len);
1888 unsigned char *mbfr;
1890 enum { buffer_sz=0x10000, file_sz=0x100000, };
1891 unsigned char *buffer;
1892 boolean fill_buffer();
1893 void skip_data(long len);
1896 class JpegVFrame : public jpeg_decompress_struct
1901 int read_jpeg(VFrame *vfrm, double xs, double ys, int jpeg_model);
1909 void jpeg_err:: s_error_exit(j_common_ptr cp)
1911 JpegVFrame *jpeg = (JpegVFrame *)cp;
1913 if( !jpeg->debug ) return;
1914 printf("s_error_exit()\n");
1918 s_output_message(j_common_ptr cp)
1920 JpegVFrame *jpeg = (JpegVFrame *)cp;
1921 if( !jpeg->debug ) return;
1922 char msg[JMSG_LENGTH_MAX];
1923 (*cp->err->format_message)(cp, msg);
1924 printf("s_output_message() = %s\n",&msg[0]);
1928 jpeg_src::jpeg_src()
1930 init_source = s_init_source;
1931 fill_input_buffer = s_fill_input_buffer;
1932 skip_input_data = s_skip_input_data;
1933 resync_to_restart = s_resync_to_restart;
1934 term_source = s_term_source;
1942 jpeg_src::~jpeg_src()
1944 if( mbfr ) ::munmap(mbfr, mlen);
1948 int jpeg_src::jpeg_file(int fd)
1952 if( fstat(fd, &st) || !st.st_size ) return 0;
1953 if( st.st_size < file_sz ) {
1954 mbfr = (unsigned char *)::mmap(0, mlen = st.st_size,
1955 PROT_READ, MAP_SHARED, fd, 0);
1956 if( mbfr == MAP_FAILED ) return 0;
1957 next_input_byte = mbfr;
1958 bytes_in_buffer = mlen;
1961 buffer = new unsigned char[buffer_sz];
1962 next_input_byte = &buffer[0];
1963 bytes_in_buffer = 0;
1967 int jpeg_src::jpeg_mem(const unsigned char *bfr, long len)
1969 next_input_byte = bfr;
1970 bytes_in_buffer = len;
1974 void jpeg_src::s_init_source(j_decompress_ptr jp) {}
1975 void jpeg_src::s_term_source(j_decompress_ptr jp) {}
1977 boolean jpeg_src::s_resync_to_restart(j_decompress_ptr jp, int v)
1979 return jpeg_resync_to_restart(jp, v);
1982 boolean jpeg_src::s_fill_input_buffer(j_decompress_ptr jp)
1984 JpegVFrame *jpeg = (JpegVFrame *)jp;
1985 return jpeg->jsrc.fill_buffer();
1988 boolean jpeg_src::fill_buffer()
1990 if( mbfr || fd < 0 ) return 0;
1991 long n = ::read(fd, buffer, buffer_sz);
1992 if( n < 0 ) perror("jpeg read");
1994 next_input_byte = buffer;
1995 bytes_in_buffer = n;
1999 void jpeg_src::s_skip_input_data(j_decompress_ptr jp, long len)
2001 JpegVFrame *jpeg = (JpegVFrame *)jp;
2002 jpeg->jsrc.skip_data(len);
2005 void jpeg_src::skip_data(long len)
2007 while( len > (long) bytes_in_buffer ) {
2008 len -= (long) bytes_in_buffer;
2009 if( !fill_buffer() ) return;
2011 next_input_byte += len;
2012 bytes_in_buffer -= len;
2016 JpegVFrame::JpegVFrame()
2018 jpeg_create_decompress(this);
2020 err = &jerr; src = &jsrc;
2022 JpegVFrame::~JpegVFrame()
2024 jpeg_destroy_decompress(this);
2027 int JpegVFrame::read_jpeg(VFrame *vfrm, double xs, double ys, int jpeg_model)
2029 VFrame *xfrm = vfrm;
2030 int color_model = xfrm->get_color_model();
2031 if( color_model == BC_COMPRESSED ) color_model = jpeg_model;
2032 jpeg_abort((jpeg_common_struct *)this);
2033 if( jpeg_read_header(this, TRUE) != JPEG_HEADER_OK ) return 0;
2034 jpeg_calc_output_dimensions(this);
2035 quantize_colors = FALSE;
2037 jpeg_model == BC_YUV888 ? JCS_YCbCr :
2038 jpeg_model == BC_GREY8 ? JCS_GRAYSCALE : JCS_RGB;
2039 jpeg_calc_output_dimensions(this);
2040 int w = bmax(image_width*xs, 1.);
2041 int h = bmax(image_height*ys, 1.);
2042 vfrm->reallocate(0, -1, 0, 0, 0, w, h, color_model, -1);
2043 if( w != (int)image_width || h != (int)image_height ||
2044 color_model != jpeg_model )
2045 xfrm = new VFrame(image_width, image_height, jpeg_model);
2046 unsigned char *pic = xfrm->get_data();
2047 int linesz = xfrm->get_bytes_per_line();
2048 jpeg_start_decompress(this);
2049 while( !ret && output_scanline < image_height ) {
2050 JSAMPROW rowptr = (JSAMPROW) &pic[output_scanline * linesz];
2051 jpeg_read_scanlines(this, &rowptr, (JDIMENSION) 1);
2053 jpeg_finish_decompress(this);
2054 if( vfrm != xfrm ) {
2055 vfrm->transfer_from(xfrm);
2061 int VFrameJpeg::read_jpeg(const unsigned char *data, long sz,
2062 double xscale, double yscale, int jpeg_model)
2065 jpeg.jsrc.jpeg_mem(data, sz);
2066 return jpeg.read_jpeg(this, xscale, yscale, jpeg_model);
2069 VFrameJpeg::VFrameJpeg(const unsigned char *jpeg_data, double s)
2072 ((long)jpeg_data[0] << 24) | ((long)jpeg_data[1] << 16) |
2073 ((long)jpeg_data[2] << 8) | (long)jpeg_data[3];
2074 if( !s ) s = BC_WindowBase::get_resources()->icon_scale;
2075 read_jpeg(jpeg_data+4, image_size, s, s, BC_RGB888);
2078 VFrameJpeg::VFrameJpeg(const unsigned char *jpeg_data, long image_size, double xs, double ys)
2080 if( !xs ) xs = BC_WindowBase::get_resources()->icon_scale;
2081 if( !ys ) ys = BC_WindowBase::get_resources()->icon_scale;
2082 read_jpeg(jpeg_data, image_size, xs, ys, BC_RGB888);
2085 VFrameJpeg::~VFrameJpeg()
2090 VFrame *VFrameJpeg::vframe_jpeg(int fd, double xs, double ys, int jpeg_model)
2093 jpeg.jsrc.jpeg_file(fd);
2094 VFrame *vfrm = new VFrame();
2095 if( !jpeg.read_jpeg(vfrm, xs, ys, jpeg_model) ) {
2096 delete vfrm; vfrm = 0;
2101 VFrame *VFrameJpeg::vframe_jpeg(const char *jpeg_path, double xs, double ys, int jpeg_model)
2104 int fd = ::open(jpeg_path, O_RDONLY);
2106 vframe = vframe_jpeg(fd, xs, ys, jpeg_model);