d40d72709d925f01f8b893898904f7d11a87990f
[goodguy/history.git] / cinelerra-5.0 / guicast / vframe.C
1
2 /*
3  * CINELERRA
4  * Copyright (C) 2011 Adam Williams <broadcast at earthling dot net>
5  *
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.
10  *
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.
15  *
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
19  *
20  */
21
22 #include <errno.h>
23 #include <png.h>
24 #include <stdio.h>
25 #include <string.h>
26 #include <stdint.h>
27 #include <sys/shm.h>
28
29 #include "bcbitmap.h"
30 #include "bchash.h"
31 #include "bcpbuffer.h"
32 #include "bcresources.h"
33 #include "bcsignals.h"
34 #include "bcsynchronous.h"
35 #include "bctexture.h"
36 #include "bcwindowbase.h"
37 #include "clip.h"
38 #include "bccmodels.h"
39 #include "vframe.h"
40
41 class PngReadFunction
42 {
43 public:
44         static void png_read_function(png_structp png_ptr,
45                    png_bytep data, png_size_t length)
46         {
47                 VFrame *frame = (VFrame*)png_get_io_ptr(png_ptr);
48                 if(frame->image_size - frame->image_offset < (long)length)
49                 {
50                         printf("PngReadFunction::png_read_function %d: overrun\n", __LINE__);
51                         length = frame->image_size - frame->image_offset;
52                 }
53
54                 memcpy(data, &frame->image[frame->image_offset], length);
55                 frame->image_offset += length;
56         };
57 };
58
59
60
61
62
63
64
65 VFrameScene::VFrameScene()
66 {
67 }
68
69 VFrameScene::~VFrameScene()
70 {
71 }
72
73
74
75
76
77
78
79 //static BCCounter counter;
80
81
82 VFrame::VFrame(unsigned char *png_data)
83 {
84         reset_parameters(1);
85         params = new BC_Hash;
86         read_png(png_data);
87 }
88
89 VFrame::VFrame(unsigned char *png_data, long image_size)
90 {
91         reset_parameters(1);
92         params = new BC_Hash;
93         read_png(png_data, image_size);
94 }
95
96 VFrame::VFrame(VFrame &frame)
97 {
98         reset_parameters(1);
99         params = new BC_Hash;
100         allocate_data(0, -1, 0, 0, 0, frame.w, frame.h,
101                 frame.color_model, frame.bytes_per_line);
102         memcpy(data, frame.data, bytes_per_line * h);
103         copy_stacks(&frame);
104 }
105
106 VFrame::VFrame(int w, int h, int color_model, long bytes_per_line)
107 {
108         reset_parameters(1);
109         params = new BC_Hash;
110         allocate_data(data, -1, 0, 0, 0, w, h,
111                 color_model, bytes_per_line);
112 }
113
114 VFrame::VFrame(unsigned char *data, int shmid, int w, int h,
115         int color_model, long bytes_per_line)
116 {
117         reset_parameters(1);
118         params = new BC_Hash;
119         allocate_data(data, shmid, 0, 0, 0, w, h,
120                 color_model, bytes_per_line);
121 }
122
123 VFrame::VFrame(unsigned char *data, int shmid,
124                 long y_offset, long u_offset, long v_offset,
125                 int w, int h, int color_model, long bytes_per_line)
126 {
127         reset_parameters(1);
128         params = new BC_Hash;
129         allocate_data(data, shmid, y_offset, u_offset, v_offset, w, h,
130                 color_model, bytes_per_line);
131 }
132
133 VFrame::VFrame(BC_Bitmap *bitmap, int w, int h,
134                  int color_model, long bytes_per_line)
135 {
136         reset_parameters(1);
137         params = new BC_Hash;
138         int shmid = 0;
139         unsigned char *data = 0;
140         if( bitmap->is_shared() )
141                 shmid = bitmap->get_shmid();
142         else
143                 data = bitmap->get_data();
144         allocate_data(data, shmid,
145                 bitmap->get_y_offset(),
146                 bitmap->get_u_offset(),
147                 bitmap->get_v_offset(),
148                 w, h, color_model, bytes_per_line);
149 }
150
151 VFrame::VFrame()
152 {
153         reset_parameters(1);
154         params = new BC_Hash;
155         this->color_model = BC_COMPRESSED;
156 }
157
158
159
160 VFrame::~VFrame()
161 {
162         clear_objects(1);
163 // Delete effect stack
164         prev_effects.remove_all_objects();
165         next_effects.remove_all_objects();
166         delete params;
167         delete scene;
168 }
169
170 int VFrame::equivalent(VFrame *src, int test_stacks)
171 {
172         return (src->get_color_model() == get_color_model() &&
173                 src->get_w() == get_w() &&
174                 src->get_h() == get_h() &&
175                 src->bytes_per_line == bytes_per_line &&
176                 (!test_stacks || equal_stacks(src)));
177 }
178
179 int VFrame::data_matches(VFrame *frame)
180 {
181         if(data && frame->get_data() &&
182                 frame->params_match(get_w(), get_h(), get_color_model()) &&
183                 get_data_size() == frame->get_data_size())
184         {
185                 int data_size = get_data_size();
186                 unsigned char *ptr1 = get_data();
187                 unsigned char *ptr2 = frame->get_data();
188                 for(int i = 0; i < data_size; i++)
189                 {
190                         if(*ptr1++ != *ptr2++) return 0;
191                 }
192                 return 1;
193         }
194         return 0;
195 }
196
197 // long VFrame::set_shm_offset(long offset)
198 // {
199 //      shm_offset = offset;
200 //      return 0;
201 // }
202 //
203 // long VFrame::get_shm_offset()
204 // {
205 //      return shm_offset;
206 // }
207 //
208 int VFrame::get_memory_type()
209 {
210         return memory_type;
211 }
212
213 int VFrame::params_match(int w, int h, int color_model)
214 {
215         return (this->w == w &&
216                 this->h == h &&
217                 this->color_model == color_model);
218 }
219
220
221 int VFrame::reset_parameters(int do_opengl)
222 {
223         status = 1;
224         scene = 0;
225         field2_offset = -1;
226         memory_type = VFrame::PRIVATE;
227 //      shm_offset = 0;
228         shmid = -1;
229         use_shm = 1;
230         bytes_per_line = 0;
231         data = 0;
232         rows = 0;
233         color_model = 0;
234         compressed_allocated = 0;
235         compressed_size = 0;   // Size of current image
236         w = 0;
237         h = 0;
238         y = u = v = a = 0;
239         y_offset = 0;
240         u_offset = 0;
241         v_offset = 0;
242         sequence_number = -1;
243         timestamp = -1.;
244         is_keyframe = 0;
245
246         if(do_opengl)
247         {
248 // By default, anything is going to be done in RAM
249                 opengl_state = VFrame::RAM;
250                 pbuffer = 0;
251                 texture = 0;
252         }
253
254         prev_effects.set_array_delete();
255         next_effects.set_array_delete();
256         return 0;
257 }
258
259 int VFrame::clear_objects(int do_opengl)
260 {
261 // Remove texture
262         if(do_opengl)
263         {
264                 delete texture;
265                 texture = 0;
266
267                 delete pbuffer;
268                 pbuffer = 0;
269         }
270
271 // Delete data
272         switch(memory_type)
273         {
274                 case VFrame::PRIVATE:
275 // Memory check
276 // if(this->w * this->h > 1500 * 1100)
277 // printf("VFrame::clear_objects 2 this=%p data=%p\n", this, data);
278                         if(data)
279                         {
280 //printf("VFrame::clear_objects %d this=%p shmid=%p data=%p\n", __LINE__, this, shmid, data);
281                                 if(shmid >= 0)
282                                         shmdt(data);
283                                 else
284                                         free(data);
285 //PRINT_TRACE
286                         }
287
288                         data = 0;
289                         shmid = -1;
290                         break;
291
292                 case VFrame::SHMGET:
293                         if(data)
294                                 shmdt(data);
295                         data = 0;
296                         shmid = -1;
297                         break;
298         }
299
300 // Delete row pointers
301         switch(color_model)
302         {
303                 case BC_COMPRESSED:
304                 case BC_YUV410P:
305                 case BC_YUV411P:
306                 case BC_YUV420P:
307                 case BC_YUV422P:
308                 case BC_YUV444P:
309                 case BC_RGB_FLOATP:
310                 case BC_RGBA_FLOATP:
311                         break;
312
313                 default:
314                         delete [] rows;
315                         rows = 0;
316                         break;
317         }
318
319
320         return 0;
321 }
322
323 int VFrame::get_field2_offset()
324 {
325         return field2_offset;
326 }
327
328 int VFrame::set_field2_offset(int value)
329 {
330         this->field2_offset = value;
331         return 0;
332 }
333
334 void VFrame::set_keyframe(int value)
335 {
336         this->is_keyframe = value;
337 }
338
339 int VFrame::get_keyframe()
340 {
341         return is_keyframe;
342 }
343
344
345 VFrameScene* VFrame::get_scene()
346 {
347         return scene;
348 }
349
350 int VFrame::calculate_bytes_per_pixel(int color_model)
351 {
352         return BC_CModels::calculate_pixelsize(color_model);
353 }
354
355 long VFrame::get_bytes_per_line()
356 {
357         return bytes_per_line;
358 }
359
360 long VFrame::get_data_size()
361 {
362         return calculate_data_size(w, h, bytes_per_line, color_model) - 4;
363 }
364
365 long VFrame::calculate_data_size(int w, int h, int bytes_per_line, int color_model)
366 {
367         return BC_CModels::calculate_datasize(w, h, bytes_per_line, color_model);
368 }
369
370 void VFrame::create_row_pointers()
371 {
372         int sz = w * h;
373         switch(color_model) {
374         case BC_YUV410P:
375                 if( this->v_offset ) break;
376                 this->y_offset = 0;
377                 this->u_offset = sz;
378                 this->v_offset = sz + w / 4 * h / 4;
379                 break;
380
381         case BC_YUV420P:
382         case BC_YUV411P:
383                 if( this->v_offset ) break;
384                 this->y_offset = 0;
385                 this->u_offset = sz;
386                 this->v_offset = sz + sz / 4;
387                 break;
388
389         case BC_YUV422P:
390                 if( this->v_offset ) break;
391                 this->y_offset = 0;
392                 this->u_offset = sz;
393                 this->v_offset = sz + sz / 2;
394                 break;
395         case BC_YUV444P:
396                 if( this->v_offset ) break;
397                 this->y_offset = 0;
398                 this->u_offset = sz;
399                 this->v_offset = sz + sz;
400                 break;
401         case BC_RGBA_FLOATP:
402                 if( this->v_offset || a ) break;
403                 a = this->data + 3 * sz * sizeof(float);
404         case BC_RGB_FLOATP:
405                 if( this->v_offset ) break;
406                 this->y_offset = 0;
407                 this->u_offset = sz * sizeof(float);
408                 this->v_offset = 2 * sz * sizeof(float);
409                 break;
410
411         default:
412                 rows = new unsigned char*[h];
413                 for(int i = 0; i < h; i++)
414                         rows[i] = &this->data[i * this->bytes_per_line];
415                 return;
416         }
417         y = this->data + this->y_offset;
418         u = this->data + this->u_offset;
419         v = this->data + this->v_offset;
420 }
421
422 int VFrame::allocate_data(unsigned char *data, int shmid,
423                 long y_offset, long u_offset, long v_offset, int w, int h,
424                 int color_model, long bytes_per_line)
425 {
426         this->w = w;
427         this->h = h;
428         this->color_model = color_model;
429         this->bytes_per_pixel = calculate_bytes_per_pixel(color_model);
430         this->y_offset = this->u_offset = this->v_offset = 0;
431 //      if(shmid == 0) {
432 //              printf("VFrame::allocate_data %d shmid == 0\n", __LINE__, shmid);
433 //      }
434
435         this->bytes_per_line = bytes_per_line >= 0 ?
436                 bytes_per_line : this->bytes_per_pixel * w;
437
438 // Allocate data + padding for MMX
439         if(data) {
440 //printf("VFrame::allocate_data %d %p\n", __LINE__, this->data);
441                 memory_type = VFrame::SHARED;
442                 this->data = data;
443                 this->shmid = -1;
444                 this->y_offset = y_offset;
445                 this->u_offset = u_offset;
446                 this->v_offset = v_offset;
447         }
448         else if(shmid >= 0) {
449                 memory_type = VFrame::SHMGET;
450                 this->data = (unsigned char*)shmat(shmid, NULL, 0);
451 //printf("VFrame::allocate_data %d shmid=%d data=%p\n", __LINE__, shmid, this->data);
452                 this->shmid = shmid;
453                 this->y_offset = y_offset;
454                 this->u_offset = u_offset;
455                 this->v_offset = v_offset;
456         }
457         else {
458                 memory_type = VFrame::PRIVATE;
459                 int size = calculate_data_size(this->w, this->h,
460                         this->bytes_per_line, this->color_model);
461                 if(BC_WindowBase::get_resources()->use_vframe_shm() && use_shm) {
462                         this->shmid = shmget(IPC_PRIVATE, size, IPC_CREAT | 0777);
463                         if(this->shmid < 0) {
464                                 printf("VFrame::allocate_data %d could not allocate shared memory\n", __LINE__);
465                         }
466
467                         this->data = (unsigned char*)shmat(this->shmid, NULL, 0);
468 //printf("VFrame::allocate_data %d %d %d\n", __LINE__, size, this->shmid);
469
470 //printf("VFrame::allocate_data %d %p\n", __LINE__, this->data);
471 // This causes it to automatically delete when the program exits.
472                         shmctl(this->shmid, IPC_RMID, 0);
473                 }
474                 else {
475 // Have to use malloc for libpng
476                         this->data = (unsigned char *)malloc(size);
477                 }
478
479 // Memory check
480 // if(this->w * this->h > 1500 * 1100)
481 // printf("VFrame::allocate_data 2 this=%p w=%d h=%d this->data=%p\n",
482 // this, this->w, this->h, this->data);
483
484                 if(!this->data)
485                         printf("VFrame::allocate_data %dx%d: memory exhausted.\n", this->w, this->h);
486
487 //printf("VFrame::allocate_data %d %p data=%p %d %d\n", __LINE__, this, this->data, this->w, this->h);
488 //if(size > 1000000) printf("VFrame::allocate_data %d\n", size);
489         }
490
491 // Create row pointers
492         create_row_pointers();
493         return 0;
494 }
495
496 void VFrame::set_memory(unsigned char *data,
497         int shmid,
498         long y_offset,
499         long u_offset,
500         long v_offset)
501 {
502         clear_objects(0);
503
504         if(data)
505         {
506                 memory_type = VFrame::SHARED;
507                 this->data = data;
508                 this->shmid = -1;
509                 this->y_offset = y_offset;
510                 this->u_offset = u_offset;
511                 this->v_offset = v_offset;
512         }
513         else
514         if(shmid >= 0)
515         {
516                 memory_type = VFrame::SHMGET;
517                 this->data = (unsigned char*)shmat(shmid, NULL, 0);
518                 this->shmid = shmid;
519         }
520
521         y = this->data + this->y_offset;
522         u = this->data + this->u_offset;
523         v = this->data + this->v_offset;
524
525         create_row_pointers();
526 }
527
528 void VFrame::set_memory(BC_Bitmap *bitmap)
529 {
530         int shmid = 0;
531         unsigned char *data = 0;
532         if( bitmap->is_shared() )
533                 shmid = bitmap->get_shmid();
534         else
535                 data = bitmap->get_data();
536         set_memory(data, shmid,
537                 bitmap->get_y_offset(),
538                 bitmap->get_u_offset(),
539                 bitmap->get_v_offset());
540 }
541
542 void VFrame::set_compressed_memory(unsigned char *data,
543         int shmid,
544         int data_size,
545         int data_allocated)
546 {
547         clear_objects(0);
548
549         if(data)
550         {
551                 memory_type = VFrame::SHARED;
552                 this->data = data;
553                 this->shmid = -1;
554         }
555         else
556         if(shmid >= 0)
557         {
558                 memory_type = VFrame::SHMGET;
559                 this->data = (unsigned char*)shmat(shmid, NULL, 0);
560                 this->shmid = shmid;
561         }
562
563         this->compressed_allocated = data_allocated;
564         this->compressed_size = data_size;
565 }
566
567
568 // Reallocate uncompressed buffer with or without alpha
569 int VFrame::reallocate(
570         unsigned char *data,
571         int shmid,
572         long y_offset,
573         long u_offset,
574         long v_offset,
575         int w,
576         int h,
577         int color_model,
578         long bytes_per_line)
579 {
580 //      if(shmid == 0) printf("VFrame::reallocate %d shmid=%d\n", __LINE__, shmid);
581         clear_objects(0);
582 //      reset_parameters(0);
583         allocate_data(data,
584                 shmid,
585                 y_offset,
586                 u_offset,
587                 v_offset,
588                 w,
589                 h,
590                 color_model,
591                 bytes_per_line);
592         return 0;
593 }
594
595 int VFrame::allocate_compressed_data(long bytes)
596 {
597         if(bytes < 1) return 1;
598
599 // Want to preserve original contents
600         if(data && compressed_allocated < bytes)
601         {
602                 int new_shmid = -1;
603                 unsigned char *new_data = 0;
604                 if(BC_WindowBase::get_resources()->use_vframe_shm() && use_shm)
605                 {
606                         new_shmid = shmget(IPC_PRIVATE,
607                                 bytes,
608                                 IPC_CREAT | 0777);
609                         new_data = (unsigned char*)shmat(new_shmid, NULL, 0);
610                         shmctl(new_shmid, IPC_RMID, 0);
611                 }
612                 else
613                 {
614 // Have to use malloc for libpng
615                         new_data = (unsigned char *)malloc(bytes);
616                 }
617
618                 bcopy(data, new_data, compressed_allocated);
619 UNBUFFER(data);
620
621                 if(memory_type == VFrame::PRIVATE)
622                 {
623                         if(shmid > 0) {
624                                 if(data)
625                                         shmdt(data);
626                         }
627                         else
628                                 free(data);
629                 }
630                 else
631                 if(memory_type == VFrame::SHMGET)
632                 {
633                         if(data)
634                                 shmdt(data);
635                 }
636
637                 data = new_data;
638                 shmid = new_shmid;
639                 compressed_allocated = bytes;
640         }
641         else
642         if(!data)
643         {
644                 if(BC_WindowBase::get_resources()->use_vframe_shm() && use_shm)
645                 {
646                         shmid = shmget(IPC_PRIVATE,
647                                 bytes,
648                                 IPC_CREAT | 0777);
649                         data = (unsigned char*)shmat(shmid, NULL, 0);
650                         shmctl(shmid, IPC_RMID, 0);
651                 }
652                 else
653                 {
654 // Have to use malloc for libpng
655                         data = (unsigned char *)malloc(bytes);
656                 }
657
658                 compressed_allocated = bytes;
659                 compressed_size = 0;
660         }
661
662         return 0;
663 }
664
665 int VFrame::read_png(const unsigned char *data, long img_sz)
666 {
667 // Test for RAW format
668         if(data[0] == 'R' && data[1] == 'A' && data[2] == 'W' && data[3] == ' ') {
669                 int new_color_model = BC_RGBA8888;
670                 w = data[4] | (data[5] << 8) | (data[6]  << 16) | (data[7]  << 24);
671                 h = data[8] | (data[9] << 8) | (data[10] << 16) | (data[11] << 24);
672                 int components = data[12];
673                 new_color_model = components == 3 ? BC_RGB888 : BC_RGBA8888;
674 // This shares the data directly
675 //              reallocate(data + 20, 0, 0, 0, w, h, new_color_model, -1);
676
677 // Can't use shared data for theme since button constructions overlay the
678 // images directly.
679                 reallocate(NULL, -1, 0, 0, 0, w, h, new_color_model, -1);
680                 memcpy(get_data(), data + 16, w * h * components);
681
682         }
683         else if(data[0] == 0x89 && data[1] == 'P' && data[2] == 'N' && data[3] == 'G') {
684                 int have_alpha = 0;
685                 png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
686                 png_infop info_ptr = png_create_info_struct(png_ptr);
687                 int new_color_model;
688
689                 image_offset = 0;
690                 image = data;  image_size = img_sz;
691                 png_set_read_fn(png_ptr, this, PngReadFunction::png_read_function);
692                 png_read_info(png_ptr, info_ptr);
693
694                 w = png_get_image_width(png_ptr, info_ptr);
695                 h = png_get_image_height(png_ptr, info_ptr);
696
697                 int src_color_model = png_get_color_type(png_ptr, info_ptr);
698
699                 /* tell libpng to strip 16 bit/color files down to 8 bits/color */
700                 png_set_strip_16(png_ptr);
701
702                 /* extract multiple pixels with bit depths of 1, 2, and 4 from a single
703                  * byte into separate bytes (useful for paletted and grayscale images).
704                  */
705                 png_set_packing(png_ptr);
706
707                 /* expand paletted colors into true RGB triplets */
708                 if (src_color_model == PNG_COLOR_TYPE_PALETTE)
709                         png_set_expand(png_ptr);
710
711                 /* expand grayscale images to the full 8 bits from 1, 2, or 4 bits/pixel */
712                 if (src_color_model == PNG_COLOR_TYPE_GRAY && png_get_bit_depth(png_ptr, info_ptr) < 8)
713                         png_set_expand(png_ptr);
714
715                 if (src_color_model == PNG_COLOR_TYPE_GRAY ||
716                     src_color_model == PNG_COLOR_TYPE_GRAY_ALPHA)
717                         png_set_gray_to_rgb(png_ptr);
718
719                 /* expand paletted or RGB images with transparency to full alpha channels
720                  * so the data will be available as RGBA quartets */
721                 if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)){
722                         have_alpha = 1;
723                         png_set_expand(png_ptr);
724                 }
725
726                 switch(src_color_model)
727                 {
728                         case PNG_COLOR_TYPE_GRAY:
729                         case PNG_COLOR_TYPE_RGB:
730                                 new_color_model = BC_RGB888;
731                                 break;
732
733                         case PNG_COLOR_TYPE_GRAY_ALPHA:
734                         case PNG_COLOR_TYPE_RGB_ALPHA:
735                         default:
736                                 new_color_model = BC_RGBA8888;
737                                 break;
738
739                         case PNG_COLOR_TYPE_PALETTE:
740                                 if(have_alpha)
741                                         new_color_model = BC_RGBA8888;
742                                 else
743                                         new_color_model = BC_RGB888;
744                 }
745
746                 reallocate(NULL, -1, 0, 0, 0, w, h, new_color_model, -1);
747
748 //printf("VFrame::read_png %d %d %d %p\n", __LINE__, w, h, get_rows());
749                 png_read_image(png_ptr, get_rows());
750                 png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
751         }
752         else {
753                 printf("VFrame::read_png %d: unknown file format"
754                         " 0x%02x 0x%02x 0x%02x 0x%02x\n",
755                         __LINE__, data[4], data[5], data[6], data[7]);
756         }
757         return 0;
758 }
759
760 int VFrame::read_png(const unsigned char *data)
761 {
762         long img_sz =
763                 ((long)data[0] << 24) | ((long)data[1] << 16) |
764                 ((long)data[2] << 8)  |  (long)data[3];
765         return read_png(data+4, img_sz);
766 }
767
768 int VFrame::write_png(const char *path)
769 {
770         png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
771         png_infop info_ptr = png_create_info_struct(png_ptr);
772         FILE *out_fd = fopen(path, "w");
773         if(!out_fd)
774         {
775                 printf("VFrame::write_png %d %s %s\n", __LINE__, path, strerror(errno));
776                 return 1;
777         }
778
779         int png_cmodel = PNG_COLOR_TYPE_RGB;
780         switch(get_color_model())
781         {
782                 case BC_RGB888:
783                 case BC_YUV888:
784                         png_cmodel = PNG_COLOR_TYPE_RGB;
785                         break;
786
787                 case BC_A8:
788                         png_cmodel = PNG_COLOR_TYPE_GRAY;
789                         break;
790         }
791
792         png_init_io(png_ptr, out_fd);
793         png_set_compression_level(png_ptr, 9);
794         png_set_IHDR(png_ptr,
795                 info_ptr,
796                 get_w(),
797                 get_h(),
798         8,
799                 png_cmodel,
800                 PNG_INTERLACE_NONE,
801                 PNG_COMPRESSION_TYPE_DEFAULT,
802                 PNG_FILTER_TYPE_DEFAULT);
803         png_write_info(png_ptr, info_ptr);
804         png_write_image(png_ptr, get_rows());
805         png_write_end(png_ptr, info_ptr);
806         png_destroy_write_struct(&png_ptr, &info_ptr);
807         fclose(out_fd);
808         return 0;
809 }
810
811
812 #define ZERO_YUV(components, type, max) \
813 { \
814         for(int i = 0; i < h; i++) \
815         { \
816                 type *row = (type*)get_rows()[i]; \
817                 for(int j = 0; j < w; j++) \
818                 { \
819                         row[j * components] = 0; \
820                         row[j * components + 1] = (max + 1) / 2; \
821                         row[j * components + 2] = (max + 1) / 2; \
822                         if(components == 4) row[j * components + 3] = 0; \
823                 } \
824         } \
825 }
826
827 int VFrame::clear_frame()
828 {
829         int sz = w * h;
830 //printf("VFrame::clear_frame %d\n", __LINE__);
831         switch(color_model) {
832         case BC_COMPRESSED:
833                 break;
834
835         case BC_YUV410P:
836                 bzero(get_y(), sz);
837                 bzero(get_u(), w / 4 * h / 4);
838                 bzero(get_v(), w / 4 * h / 4);
839                 break;
840
841         case BC_YUV411P:
842         case BC_YUV420P:
843                 bzero(get_y(), sz);
844                 bzero(get_u(), sz / 4);
845                 bzero(get_v(), sz / 4);
846                 break;
847
848         case BC_YUV422P:
849                 bzero(get_y(), sz);
850                 bzero(get_u(), sz / 2);
851                 bzero(get_v(), sz / 2);
852                 break;
853
854         case BC_RGBA_FLOATP: if( a ) {
855                 float *ap = (float *)a;
856                 for( int i=sz; --i>=0; ++ap ) *ap = 1.f; }
857         case BC_RGB_FLOATP: {
858                 float *rp = (float *)y;
859                 for( int i=sz; --i>=0; ++rp ) *rp = 0.f;
860                 float *gp = (float *)u;
861                 for( int i=sz; --i>=0; ++gp ) *gp = 0.f;
862                 float *bp = (float *)v;
863                 for( int i=sz; --i>=0; ++bp ) *bp = 0.f;
864                 break; }
865         case BC_YUV444P:
866                 bzero(get_y(), sz);
867                 bzero(get_u(), sz);
868                 bzero(get_v(), sz);
869                 break;
870
871         case BC_YUV888:
872                 ZERO_YUV(3, unsigned char, 0xff);
873                 break;
874
875         case BC_YUVA8888:
876                 ZERO_YUV(4, unsigned char, 0xff);
877                 break;
878
879         case BC_YUV161616:
880                 ZERO_YUV(3, uint16_t, 0xffff);
881                 break;
882
883         case BC_YUVA16161616:
884                 ZERO_YUV(4, uint16_t, 0xffff);
885                 break;
886
887         default:
888                 bzero(data, calculate_data_size(w, h, bytes_per_line, color_model));
889                 break;
890         }
891         return 0;
892 }
893
894 void VFrame::rotate90()
895 {
896 // Allocate new frame
897         int new_w = h, new_h = w, new_bytes_per_line = bytes_per_pixel * new_w;
898         unsigned char *new_data = new unsigned char[calculate_data_size(new_w, new_h, new_bytes_per_line, color_model)];
899         unsigned char **new_rows = new unsigned char*[new_h];
900         for(int i = 0; i < new_h; i++)
901                 new_rows[i] = &new_data[new_bytes_per_line * i];
902
903 // Copy data
904         for(int in_y = 0, out_x = new_w - 1; in_y < h; in_y++, out_x--)
905         {
906                 for(int in_x = 0, out_y = 0; in_x < w; in_x++, out_y++)
907                 {
908                         for(int k = 0; k < bytes_per_pixel; k++)
909                         {
910                                 new_rows[out_y][out_x * bytes_per_pixel + k] =
911                                         rows[in_y][in_x * bytes_per_pixel + k];
912                         }
913                 }
914         }
915
916 // Swap frames
917         clear_objects(0);
918         data = new_data;
919         rows = new_rows;
920         bytes_per_line = new_bytes_per_line;
921         w = new_w;
922         h = new_h;
923 }
924
925 void VFrame::rotate270()
926 {
927 // Allocate new frame
928         int new_w = h, new_h = w, new_bytes_per_line = bytes_per_pixel * new_w;
929         unsigned char *new_data = new unsigned char[calculate_data_size(new_w, new_h, new_bytes_per_line, color_model)];
930         unsigned char **new_rows = new unsigned char*[new_h];
931         for(int i = 0; i < new_h; i++)
932                 new_rows[i] = &new_data[new_bytes_per_line * i];
933
934 // Copy data
935         for(int in_y = 0, out_x = 0; in_y < h; in_y++, out_x++)
936         {
937                 for(int in_x = 0, out_y = new_h - 1; in_x < w; in_x++, out_y--)
938                 {
939                         for(int k = 0; k < bytes_per_pixel; k++)
940                         {
941                                 new_rows[out_y][out_x * bytes_per_pixel + k] =
942                                         rows[in_y][in_x * bytes_per_pixel + k];
943                         }
944                 }
945         }
946
947 // Swap frames
948         clear_objects(0);
949         data = new_data;
950         rows = new_rows;
951         bytes_per_line = new_bytes_per_line;
952         w = new_w;
953         h = new_h;
954 }
955
956 void VFrame::flip_vert()
957 {
958         unsigned char *temp = new unsigned char[bytes_per_line];
959         for(int i = 0, j = h - 1; i < j; i++, j--)
960         {
961                 memcpy(temp, rows[j], bytes_per_line);
962                 memcpy(rows[j], rows[i], bytes_per_line);
963                 memcpy(rows[i], temp, bytes_per_line);
964         }
965         delete [] temp;
966 }
967
968 void VFrame::flip_horiz()
969 {
970         unsigned char temp[32];
971         for(int i = 0; i < h; i++)
972         {
973                 unsigned char *row = rows[i];
974                 for(int j = 0; j < bytes_per_line / 2; j += bytes_per_pixel)
975                 {
976                         memcpy(temp, row + j, bytes_per_pixel);
977                         memcpy(row + j, row + bytes_per_line - j - bytes_per_pixel, bytes_per_pixel);
978                         memcpy(row + bytes_per_line - j - bytes_per_pixel, temp, bytes_per_pixel);
979                 }
980         }
981 }
982
983
984
985 int VFrame::copy_from(VFrame *frame)
986 {
987         int w = MIN(this->w, frame->get_w());
988         int h = MIN(this->h, frame->get_h());
989         timestamp = frame->timestamp;
990
991         switch(frame->color_model)
992         {
993                 case BC_COMPRESSED:
994                         allocate_compressed_data(frame->compressed_size);
995                         memcpy(data, frame->data, frame->compressed_size);
996                         this->compressed_size = frame->compressed_size;
997                         break;
998
999                 case BC_YUV410P:
1000                         memcpy(get_y(), frame->get_y(), w * h);
1001                         memcpy(get_u(), frame->get_u(), w / 4 * h / 4);
1002                         memcpy(get_v(), frame->get_v(), w / 4 * h / 4);
1003                         break;
1004
1005                 case BC_YUV420P:
1006                 case BC_YUV411P:
1007 //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());
1008                         memcpy(get_y(), frame->get_y(), w * h);
1009                         memcpy(get_u(), frame->get_u(), w * h / 4);
1010                         memcpy(get_v(), frame->get_v(), w * h / 4);
1011                         break;
1012
1013                 case BC_YUV422P:
1014 //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());
1015                         memcpy(get_y(), frame->get_y(), w * h);
1016                         memcpy(get_u(), frame->get_u(), w * h / 2);
1017                         memcpy(get_v(), frame->get_v(), w * h / 2);
1018                         break;
1019
1020                 case BC_YUV444P:
1021 //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());
1022                         memcpy(get_y(), frame->get_y(), w * h);
1023                         memcpy(get_u(), frame->get_u(), w * h);
1024                         memcpy(get_v(), frame->get_v(), w * h);
1025                         break;
1026                 default:
1027 // printf("VFrame::copy_from %d\n", calculate_data_size(w,
1028 //                              h,
1029 //                              -1,
1030 //                              frame->color_model));
1031 // Copy without extra 4 bytes in case the source is a hardware device
1032                         memmove(data, frame->data, get_data_size());
1033                         break;
1034         }
1035
1036         return 0;
1037 }
1038
1039 int VFrame::transfer_from(VFrame *that, int bg_color)
1040 {
1041         if( this->get_color_model() == that->get_color_model() &&
1042             this->get_w() == that->get_w() && this->get_h() == that->get_h() )
1043                 return this->copy_from(that);
1044
1045         timestamp = that->timestamp;
1046 #if 0
1047         BC_CModels::transfer(
1048                 this->get_rows(), that->get_rows(),          // Packed data out/in
1049                 this->get_y(), this->get_u(), this->get_v(), // Planar data out/in
1050                 that->get_y(), that->get_u(), that->get_v(),
1051                 0, 0, that->get_w(), that->get_h(),          // Dimensions in/out
1052                 0, 0, this->get_w(), this->get_h(),
1053                 that->get_color_model(), this->get_color_model(), // Color models in/out
1054                 bg_color,                                    // alpha blend bg_color
1055                 that->get_w(), this->get_w());               // rowspans (of luma for YUV)
1056 #else
1057         unsigned char *in_ptrs[4], *out_ptrs[4];
1058         unsigned char **inp, **outp;
1059         if( BC_CModels::is_planar(that->get_color_model()) ) {
1060                 in_ptrs[0] = that->get_y();
1061                 in_ptrs[1] = that->get_u();
1062                 in_ptrs[2] = that->get_v();
1063                 in_ptrs[3] = that->get_a();
1064                 inp = in_ptrs;
1065         }
1066         else
1067                 inp = that->get_rows(); 
1068         if( BC_CModels::is_planar(this->get_color_model()) ) {
1069                 out_ptrs[0] = this->get_y();
1070                 out_ptrs[1] = this->get_u();
1071                 out_ptrs[2] = this->get_v();
1072                 out_ptrs[3] = this->get_a();
1073                 outp = out_ptrs;
1074         }
1075         else
1076                 outp = this->get_rows();        
1077         BC_CModels::transfer(outp, this->get_color_model(),
1078                         0, 0, this->get_w(), this->get_h(), this->get_w(),
1079                 inp, that->get_color_model(),
1080                         0, 0, that->get_w(), that->get_h(), that->get_w(),
1081                 bg_color);
1082 #endif
1083         return 0;
1084 }
1085
1086
1087
1088
1089
1090
1091 #define OVERLAY(type, max, components) \
1092 { \
1093         type **in_rows = (type**)src->get_rows(); \
1094         type **out_rows = (type**)get_rows(); \
1095         int in_w = src->get_w(); \
1096         int in_h = src->get_h(); \
1097  \
1098         for(int i = 0; i < in_h; i++) \
1099         { \
1100                 if(i + out_y1 >= 0 && i + out_y1 < h) \
1101                 { \
1102                         type *src_row = in_rows[i]; \
1103                         type *dst_row = out_rows[i + out_y1] + out_x1 * components; \
1104  \
1105                         for(int j = 0; j < in_w; j++) \
1106                         { \
1107                                 if(j + out_x1 >= 0 && j + out_x1 < w) \
1108                                 { \
1109                                         int opacity = src_row[3]; \
1110                                         int transparency = dst_row[3] * (max - src_row[3]) / max; \
1111                                         dst_row[0] = (transparency * dst_row[0] + opacity * src_row[0]) / max; \
1112                                         dst_row[1] = (transparency * dst_row[1] + opacity * src_row[1]) / max; \
1113                                         dst_row[2] = (transparency * dst_row[2] + opacity * src_row[2]) / max; \
1114                                         dst_row[3] = MAX(dst_row[3], src_row[3]); \
1115                                 } \
1116  \
1117                                 dst_row += components; \
1118                                 src_row += components; \
1119                         } \
1120                 } \
1121         } \
1122 }
1123
1124
1125 void VFrame::overlay(VFrame *src,
1126                 int out_x1,
1127                 int out_y1)
1128 {
1129         switch(get_color_model())
1130         {
1131                 case BC_RGBA8888:
1132                         OVERLAY(unsigned char, 0xff, 4);
1133                         break;
1134         }
1135 }
1136
1137
1138
1139 int VFrame::get_scale_tables(int *column_table, int *row_table,
1140                         int in_x1, int in_y1, int in_x2, int in_y2,
1141                         int out_x1, int out_y1, int out_x2, int out_y2)
1142 {
1143         int i;
1144         float w_in = in_x2 - in_x1;
1145         float h_in = in_y2 - in_y1;
1146         int w_out = out_x2 - out_x1;
1147         int h_out = out_y2 - out_y1;
1148
1149         float hscale = w_in / w_out;
1150         float vscale = h_in / h_out;
1151
1152         for(i = 0; i < w_out; i++)
1153         {
1154                 column_table[i] = (int)(hscale * i);
1155         }
1156
1157         for(i = 0; i < h_out; i++)
1158         {
1159                 row_table[i] = (int)(vscale * i) + in_y1;
1160         }
1161         return 0;
1162 }
1163
1164 void VFrame::push_prev_effect(const char *name)
1165 {
1166         char *ptr;
1167         prev_effects.append(ptr = new char[strlen(name) + 1]);
1168         strcpy(ptr, name);
1169         if(prev_effects.total > MAX_STACK_ELEMENTS) prev_effects.remove_object(0);
1170 }
1171
1172 void VFrame::pop_prev_effect()
1173 {
1174         if(prev_effects.total)
1175                 prev_effects.remove_object(prev_effects.last());
1176 }
1177
1178 void VFrame::push_next_effect(const char *name)
1179 {
1180         char *ptr;
1181         next_effects.append(ptr = new char[strlen(name) + 1]);
1182         strcpy(ptr, name);
1183         if(next_effects.total > MAX_STACK_ELEMENTS) next_effects.remove_object(0);
1184 }
1185
1186 void VFrame::pop_next_effect()
1187 {
1188         if(next_effects.total)
1189                 next_effects.remove_object(next_effects.last());
1190 }
1191
1192 const char* VFrame::get_next_effect(int number)
1193 {
1194         if(!next_effects.total) return "";
1195         else
1196         if(number > next_effects.total - 1) number = next_effects.total - 1;
1197
1198         return next_effects.values[next_effects.total - number - 1];
1199 }
1200
1201 const char* VFrame::get_prev_effect(int number)
1202 {
1203         if(!prev_effects.total) return "";
1204         else
1205         if(number > prev_effects.total - 1) number = prev_effects.total - 1;
1206
1207         return prev_effects.values[prev_effects.total - number - 1];
1208 }
1209
1210 BC_Hash* VFrame::get_params()
1211 {
1212         return params;
1213 }
1214
1215 void VFrame::clear_stacks()
1216 {
1217         next_effects.remove_all_objects();
1218         prev_effects.remove_all_objects();
1219         params->clear();
1220         status = 1;
1221 }
1222
1223 void VFrame::copy_params(VFrame *src)
1224 {
1225         status = src->status;
1226         params->copy_from(src->params);
1227 }
1228
1229 void VFrame::copy_stacks(VFrame *src)
1230 {
1231         clear_stacks();
1232
1233         for(int i = 0; i < src->next_effects.total; i++)
1234         {
1235                 char *ptr;
1236                 next_effects.append(ptr = new char[strlen(src->next_effects.values[i]) + 1]);
1237                 strcpy(ptr, src->next_effects.values[i]);
1238         }
1239         for(int i = 0; i < src->prev_effects.total; i++)
1240         {
1241                 char *ptr;
1242                 prev_effects.append(ptr = new char[strlen(src->prev_effects.values[i]) + 1]);
1243                 strcpy(ptr, src->prev_effects.values[i]);
1244         }
1245
1246         copy_params(src);
1247 }
1248
1249 int VFrame::equal_stacks(VFrame *src)
1250 {
1251         for(int i = 0; i < src->next_effects.total && i < next_effects.total; i++)
1252         {
1253                 if(strcmp(src->next_effects.values[i], next_effects.values[i])) return 0;
1254         }
1255
1256         for(int i = 0; i < src->prev_effects.total && i < prev_effects.total; i++)
1257         {
1258                 if(strcmp(src->prev_effects.values[i], prev_effects.values[i])) return 0;
1259         }
1260
1261         if(!params->equivalent(src->params)) return 0;
1262         return 1;
1263 }
1264
1265 void VFrame::dump_stacks()
1266 {
1267         printf("VFrame::dump_stacks\n");
1268         printf("        next_effects:\n");
1269         for(int i = next_effects.total - 1; i >= 0; i--)
1270                 printf("                %s\n", next_effects.values[i]);
1271         printf("        prev_effects:\n");
1272         for(int i = prev_effects.total - 1; i >= 0; i--)
1273                 printf("                %s\n", prev_effects.values[i]);
1274 }
1275
1276 void VFrame::dump_params()
1277 {
1278         params->dump();
1279 }
1280
1281 void VFrame::dump()
1282 {
1283         printf("VFrame::dump %d this=%p\n", __LINE__, this);
1284         printf("    w=%d h=%d colormodel=%d rows=%p use_shm=%d shmid=%d\n",
1285                 w, h, color_model, rows, use_shm, shmid);
1286 }
1287
1288 int VFrame::filefork_size()
1289 {
1290         return sizeof(int) * 13 + sizeof(long);
1291 }
1292
1293
1294 void VFrame::to_filefork(unsigned char *buffer)
1295 {
1296         *(int*)(buffer + 0) = shmid;
1297         *(int*)(buffer + 4) = y_offset;
1298         *(int*)(buffer + 8) = u_offset;
1299         *(int*)(buffer + 12) = v_offset;
1300         *(int*)(buffer + 16) = w;
1301         *(int*)(buffer + 20) = h;
1302         *(int*)(buffer + 24) = color_model;
1303         *(int*)(buffer + 28) = bytes_per_line;
1304         *(int*)(buffer + 32) = compressed_allocated;
1305         *(int*)(buffer + 36) = compressed_size;
1306         *(int*)(buffer + 40) = is_keyframe;
1307         *(int*)(buffer + 44) = status;
1308         *(long*)(buffer + 48) = sequence_number;
1309
1310
1311 //printf("VFrame::to_filefork %d %lld\n", __LINE__, sequence_number);
1312 // printf("VFrame::to_filefork %d", __LINE__);
1313 // for(int i = 0; i < 40; i++)
1314 // {
1315 // printf(" %02x", buffer[i]);
1316 // }
1317 // printf("\n");
1318 // dump();
1319 }
1320
1321
1322 void VFrame::from_filefork(unsigned char *buffer)
1323 {
1324 // This frame will always be preallocated shared memory
1325 //printf("VFrame::from_filefork %d %d\n", __LINE__, *(int*)(buffer + 24));
1326         if(*(int*)(buffer + 24) == BC_COMPRESSED)
1327         {
1328                 set_compressed_memory(0,
1329                         *(int*)(buffer + 0), // shmid
1330                         *(int*)(buffer + 36), // compressed_size
1331                         *(int*)(buffer + 32)); // compressed_allocated
1332                 color_model = BC_COMPRESSED;
1333 //printf("VFrame::from_filefork %d %d\n", __LINE__, get_compressed_size());
1334
1335         }
1336         else
1337         {
1338 // printf("VFrame::from_filefork %d", __LINE__);
1339 // for(int i = 0; i < 40; i++)
1340 // {
1341 // printf(" %02x", buffer[i]);
1342 // }
1343 // printf("\n");
1344                 reallocate(0,
1345                         *(int*)(buffer + 0), // shmid
1346                         *(int*)(buffer + 4), // y_offset
1347                         *(int*)(buffer + 8), // u_offset
1348                         *(int*)(buffer + 12), // v_offset
1349                         *(int*)(buffer + 16), // w
1350                         *(int*)(buffer + 20), // h
1351                         *(int*)(buffer + 24), // colormodel
1352                         *(int*)(buffer + 28)); // bytes per line
1353 //dump();
1354         }
1355
1356         is_keyframe = *(int*)(buffer + 40);
1357         status = *(int*)(buffer + 44);
1358         sequence_number = *(long*)(buffer + 48);
1359 //printf("VFrame::from_filefork %d %lld\n", __LINE__, sequence_number);
1360 }
1361
1362 int VFrame::get_memory_usage()
1363 {
1364         if(get_compressed_allocated()) return get_compressed_allocated();
1365         return get_h() * get_bytes_per_line();
1366 }
1367
1368 void VFrame::draw_pixel(int x, int y)
1369 {
1370         if(!(x >= 0 && y >= 0 && x < get_w() && y < get_h())) return;
1371
1372 #define DRAW_PIXEL(x, y, components, do_yuv, max, type) \
1373 { \
1374         type **rows = (type**)get_rows(); \
1375         rows[y][x * components] = max - rows[y][x * components]; \
1376         if(!do_yuv) \
1377         { \
1378                 rows[y][x * components + 1] = max - rows[y][x * components + 1]; \
1379                 rows[y][x * components + 2] = max - rows[y][x * components + 2]; \
1380         } \
1381         else \
1382         { \
1383                 rows[y][x * components + 1] = (max / 2 + 1) - rows[y][x * components + 1]; \
1384                 rows[y][x * components + 2] = (max / 2 + 1) - rows[y][x * components + 2]; \
1385         } \
1386         if(components == 4) \
1387                 rows[y][x * components + 3] = max; \
1388 }
1389
1390
1391         switch(get_color_model())
1392         {
1393                 case BC_RGB888:
1394                         DRAW_PIXEL(x, y, 3, 0, 0xff, unsigned char);
1395                         break;
1396                 case BC_RGBA8888:
1397                         DRAW_PIXEL(x, y, 4, 0, 0xff, unsigned char);
1398                         break;
1399                 case BC_RGB_FLOAT:
1400                         DRAW_PIXEL(x, y, 3, 0, 1.0, float);
1401                         break;
1402                 case BC_RGBA_FLOAT:
1403                         DRAW_PIXEL(x, y, 4, 0, 1.0, float);
1404                         break;
1405                 case BC_YUV888:
1406                         DRAW_PIXEL(x, y, 3, 1, 0xff, unsigned char);
1407                         break;
1408                 case BC_YUVA8888:
1409                         DRAW_PIXEL(x, y, 4, 1, 0xff, unsigned char);
1410                         break;
1411                 case BC_RGB161616:
1412                         DRAW_PIXEL(x, y, 3, 0, 0xffff, uint16_t);
1413                         break;
1414                 case BC_YUV161616:
1415                         DRAW_PIXEL(x, y, 3, 1, 0xffff, uint16_t);
1416                         break;
1417                 case BC_RGBA16161616:
1418                         DRAW_PIXEL(x, y, 4, 0, 0xffff, uint16_t);
1419                         break;
1420                 case BC_YUVA16161616:
1421                         DRAW_PIXEL(x, y, 4, 1, 0xffff, uint16_t);
1422                         break;
1423         }
1424 }
1425
1426
1427 void VFrame::draw_line(int x1, int y1, int x2, int y2)
1428 {
1429         int w = labs(x2 - x1);
1430         int h = labs(y2 - y1);
1431 //printf("FindObjectMain::draw_line 1 %d %d %d %d\n", x1, y1, x2, y2);
1432
1433         if(!w && !h)
1434         {
1435                 draw_pixel(x1, y1);
1436         }
1437         else
1438         if(w > h)
1439         {
1440 // Flip coordinates so x1 < x2
1441                 if(x2 < x1)
1442                 {
1443                         y2 ^= y1;
1444                         y1 ^= y2;
1445                         y2 ^= y1;
1446                         x1 ^= x2;
1447                         x2 ^= x1;
1448                         x1 ^= x2;
1449                 }
1450                 int numerator = y2 - y1;
1451                 int denominator = x2 - x1;
1452                 for(int i = x1; i <= x2; i++)
1453                 {
1454                         int y = y1 + (int64_t)(i - x1) * (int64_t)numerator / (int64_t)denominator;
1455                         draw_pixel(i, y);
1456                 }
1457         }
1458         else
1459         {
1460 // Flip coordinates so y1 < y2
1461                 if(y2 < y1)
1462                 {
1463                         y2 ^= y1;
1464                         y1 ^= y2;
1465                         y2 ^= y1;
1466                         x1 ^= x2;
1467                         x2 ^= x1;
1468                         x1 ^= x2;
1469                 }
1470                 int numerator = x2 - x1;
1471                 int denominator = y2 - y1;
1472                 for(int i = y1; i <= y2; i++)
1473                 {
1474                         int x = x1 + (int64_t)(i - y1) * (int64_t)numerator / (int64_t)denominator;
1475                         draw_pixel(x, i);
1476                 }
1477         }
1478 //printf("FindObjectMain::draw_line 2\n");
1479 }
1480
1481 void VFrame::draw_rect(int x1, int y1, int x2, int y2)
1482 {
1483         draw_line(x1, y1, x2, y1);
1484         draw_line(x2, y1 + 1, x2, y2);
1485         draw_line(x2 - 1, y2, x1, y2);
1486         draw_line(x1, y2 - 1, x1, y1 + 1);
1487 }
1488
1489 #define ARROW_SIZE 10
1490 void VFrame::draw_arrow(int x1, int y1, int x2, int y2)
1491 {
1492         double angle = atan((float)(y2 - y1) / (float)(x2 - x1));
1493         double angle1 = angle + (float)145 / 360 * 2 * 3.14159265;
1494         double angle2 = angle - (float)145 / 360 * 2 * 3.14159265;
1495         int x3;
1496         int y3;
1497         int x4;
1498         int y4;
1499         if(x2 < x1)
1500         {
1501                 x3 = x2 - (int)(ARROW_SIZE * cos(angle1));
1502                 y3 = y2 - (int)(ARROW_SIZE * sin(angle1));
1503                 x4 = x2 - (int)(ARROW_SIZE * cos(angle2));
1504                 y4 = y2 - (int)(ARROW_SIZE * sin(angle2));
1505         }
1506         else
1507         {
1508                 x3 = x2 + (int)(ARROW_SIZE * cos(angle1));
1509                 y3 = y2 + (int)(ARROW_SIZE * sin(angle1));
1510                 x4 = x2 + (int)(ARROW_SIZE * cos(angle2));
1511                 y4 = y2 + (int)(ARROW_SIZE * sin(angle2));
1512         }
1513
1514 // Main vector
1515         draw_line(x1, y1, x2, y2);
1516 //      draw_line(x1, y1 + 1, x2, y2 + 1);
1517
1518 // Arrow line
1519         if(abs(y2 - y1) || abs(x2 - x1)) draw_line(x2, y2, x3, y3);
1520 // Arrow line
1521         if(abs(y2 - y1) || abs(x2 - x1)) draw_line(x2, y2, x4, y4);
1522 }
1523
1524
1525
1526