Subversion Repositories Kolibri OS

Rev

Rev 2427 | Go to most recent revision | Blame | Last modification | View Log | Download | RSS feed

  1.  
  2. #include <stdint.h>
  3. #include <libavcodec/avcodec.h>
  4. #include <libavformat/avformat.h>
  5. #include <libswscale/swscale.h>
  6. #include <libavutil/imgutils.h>
  7. #include "system.h"
  8. #include "../winlib/winlib.h"
  9. #include "sound.h"
  10. #include "fplay.h"
  11.  
  12. #define CAPTION_HEIGHT      24
  13.  
  14. extern int res_pause_btn[];
  15. extern int res_pause_btn_pressed[];
  16.  
  17. extern int res_play_btn[];
  18. extern int res_play_btn_pressed[];
  19.  
  20. extern int64_t stream_duration;
  21.  
  22. typedef struct
  23. {
  24.     AVPicture      picture;
  25.     double         pts;
  26.     volatile int   ready;
  27. }vframe_t;
  28.  
  29. vframe_t           frames[4];
  30.  
  31. struct SwsContext *cvt_ctx = NULL;
  32.  
  33. int vfx    = 0;
  34. int dfx    = 0;
  35.  
  36. render_t   *main_render;
  37.  
  38. int width;
  39. int height;
  40.  
  41. AVRational video_time_base;
  42. AVFrame  *Frame;
  43.  
  44. volatile uint32_t driver_lock;
  45.  
  46. void get_client_rect(rect_t *rc);
  47.  
  48. void flush_video()
  49. {
  50.     int i;
  51.  
  52.     for(i = 0; i < 4; i++)
  53.     {    
  54.         frames[i].pts    = 0;
  55.         frames[i].ready  = 0;
  56.     };
  57.     vfx    = 0;
  58.     dfx    = 0;
  59. };
  60.  
  61. int init_video(AVCodecContext *ctx)
  62. {
  63.     int        i;
  64.  
  65.     width = ctx->width;
  66.     height = ctx->height;
  67.  
  68.  
  69.     printf("w = %d  h = %d\n\r", width, height);
  70.  
  71. //    __asm__ __volatile__("int3");
  72.  
  73.     main_render = create_render(ctx->width, ctx->height,
  74.                            ctx->pix_fmt, HW_BIT_BLIT|HW_TEX_BLIT);
  75. //    render = create_render(ctx->width, ctx->height,
  76. //                           ctx->pix_fmt, 0);
  77. //
  78.     if( main_render == NULL)
  79.     {
  80.         printf("Cannot create render\n\r");
  81.         return 0;
  82.     };
  83.  
  84.     Frame = avcodec_alloc_frame();
  85.     if ( Frame == NULL )
  86.     {
  87.         printf("Cannot alloc video frame\n\r");
  88.         return 0;
  89.     };
  90.  
  91.     for( i=0; i < 4; i++)
  92.     {
  93.         int ret;
  94.  
  95. //        printf("alloc picture %d %d %x\n",
  96. //                   ctx->width, ctx->height, ctx->pix_fmt );
  97.  
  98.         ret = avpicture_alloc(&frames[i].picture, ctx->pix_fmt,
  99.                                ctx->width, ctx->height);
  100.         if ( ret != 0 )
  101.         {
  102.             printf("Cannot alloc video buffer\n\r");
  103.             return 0;
  104.         };
  105.  
  106.         frames[i].pts    = 0;
  107.         frames[i].ready  = 0;
  108.     };
  109.  
  110.     create_thread(video_thread, ctx, 1024*1024);
  111.  
  112.     delay(50);
  113.     return 1;
  114. };
  115.  
  116. int decode_video(AVCodecContext  *ctx, queue_t *qv)
  117. {
  118.     AVPacket   pkt;
  119.     double     pts;
  120.     int frameFinished;
  121.     double current_clock;
  122.  
  123.     if(frames[dfx].ready != 0 )
  124.         return 1;
  125.  
  126.     if( get_packet(qv, &pkt) == 0 )
  127.         return 0;
  128.  
  129.     current_clock = -90.0 + get_master_clock();
  130.  
  131.     if( pkt.dts == AV_NOPTS_VALUE &&
  132.         Frame->reordered_opaque != AV_NOPTS_VALUE)
  133.         pts = Frame->reordered_opaque;
  134.     else if(pkt.dts != AV_NOPTS_VALUE)
  135.         pts= pkt.dts;
  136.     else
  137.         pts= 0;
  138.        
  139.  
  140.     pts *= av_q2d(video_time_base)*1000.0;
  141.  
  142.     if( 1 /*pts > current_clock*/)
  143.     {
  144.         frameFinished = 0;
  145.  
  146.         ctx->reordered_opaque = pkt.pts;
  147.  
  148.         if(avcodec_decode_video2(ctx, Frame, &frameFinished, &pkt) <= 0)
  149.             printf("video decoder error\n");
  150.  
  151.         if(frameFinished)
  152.         {
  153.             AVPicture *dst_pic;
  154.  
  155.             if( pkt.dts == AV_NOPTS_VALUE &&
  156.                 Frame->reordered_opaque != AV_NOPTS_VALUE)
  157.                 pts = Frame->reordered_opaque;
  158.             else if(pkt.dts != AV_NOPTS_VALUE)
  159.                 pts= pkt.dts;
  160.             else
  161.                 pts= 0;
  162.  
  163. //        pts = *(int64_t*)av_opt_ptr(avcodec_get_frame_class(),
  164. //                                Frame, "best_effort_timestamp");
  165.  
  166. //        if (pts == AV_NOPTS_VALUE)
  167. //            pts = 0;
  168.  
  169.             pts *= av_q2d(video_time_base);
  170.  
  171.             dst_pic = &frames[dfx].picture;
  172.  
  173.             av_image_copy(dst_pic->data, dst_pic->linesize,
  174.                       (const uint8_t**)Frame->data,
  175.                       Frame->linesize, ctx->pix_fmt, ctx->width, ctx->height);
  176.  
  177.             frames[dfx].pts = pts*1000.0;
  178. //            printf("pts %f\n", frames[dfx].pts);
  179.  
  180.             frames[dfx].ready = 1;
  181.  
  182.             dfx++;
  183.             dfx&= 3;
  184.         };
  185.     };
  186.     av_free_packet(&pkt);
  187.  
  188.     return 1;
  189. }
  190.  
  191. extern volatile enum player_state player_state;
  192. //rect_t     win_rect;
  193.  
  194. extern int64_t rewind_pos;
  195.  
  196. int MainWindowProc(ctrl_t *ctrl, uint32_t msg, uint32_t arg1, uint32_t arg2)
  197. {
  198.     window_t  *win;
  199.  
  200.     win = (window_t*)ctrl;
  201.  
  202.     switch(msg)
  203.     {
  204.         case MSG_SIZE:
  205.             //printf("MSG_SIZE\n");
  206.             render_adjust_size(main_render, win);
  207.             break;
  208.  
  209.         case MSG_DRAW_CLIENT:
  210.             render_draw_client(main_render);
  211.             break;
  212.  
  213.         case MSG_LBTNDOWN:
  214.             if(player_state == PAUSE)
  215.             {
  216.                 win->panel.play_btn->img_default = res_pause_btn;
  217.                 win->panel.play_btn->img_hilite  = res_pause_btn;
  218.                 win->panel.play_btn->img_pressed = res_pause_btn_pressed;
  219.                 send_message(win->panel.play_btn, MSG_PAINT, 0, 0);
  220.                 player_state = PAUSE_2_PLAY;
  221.  
  222.             }
  223.             else if(player_state == PLAY)
  224.             {
  225.                 win->panel.play_btn->img_default = res_play_btn;
  226.                 win->panel.play_btn->img_hilite  = res_play_btn;
  227.                 win->panel.play_btn->img_pressed = res_play_btn_pressed;
  228.                 send_message(win->panel.play_btn, MSG_PAINT, 0, 0);
  229.                 player_state = PAUSE;
  230.             }
  231.             break;
  232.  
  233.         case MSG_COMMAND:
  234.             switch((short)arg1)
  235.             {
  236.                 case ID_PLAY:
  237.                     if(player_state == PAUSE)
  238.                     {
  239.                         win->panel.play_btn->img_default  = res_pause_btn;
  240.                         win->panel.play_btn->img_hilite   = res_pause_btn;
  241.                         win->panel.play_btn->img_pressed = res_pause_btn_pressed;
  242.                         player_state = PAUSE_2_PLAY;
  243.                     }
  244.                     else if(player_state == PLAY)
  245.                     {
  246.                         win->panel.play_btn->img_default = res_play_btn;
  247.                         win->panel.play_btn->img_hilite  = res_play_btn;
  248.                         win->panel.play_btn->img_pressed  = res_play_btn_pressed;
  249.                         player_state = PAUSE;
  250.                     }
  251.                     break;
  252.  
  253.                 case 101:  //ID_PROGRESS:
  254.                     if(player_state != REWIND)
  255.                     {
  256.                         progress_t *prg = (progress_t*)arg2;
  257.                    
  258.                         rewind_pos = (int64_t)prg->pos *
  259.                               (prg->max - prg->min)/prg->ctrl.w;
  260.                              
  261. //                        printf("progress action %f\n", (double)rewind_pos);
  262.                         player_state = REWIND;
  263.                         main_render->win->panel.prg->current = rewind_pos;
  264.                         send_message(&main_render->win->panel.ctrl, MSG_PAINT, 0, 0);
  265.                     };
  266.                     break;
  267.                      
  268.                 default:
  269.                     break;
  270.             }
  271.             break;
  272.  
  273.         default:
  274.             def_window_proc(ctrl,msg,arg1,arg2);
  275.     };
  276.     return 0;
  277. };
  278.  
  279. #define VERSION_A          1
  280.  
  281. void render_time(render_t *render)
  282. {
  283.     double ctime;            /*    milliseconds    */
  284.     double fdelay;           /*    milliseconds    */
  285.  
  286. //again:
  287.  
  288.     if(player_state == CLOSED)
  289.     {
  290.         render->win->win_command = WIN_CLOSED;
  291.         return;
  292.     }
  293.     else if(player_state != PLAY)
  294.     {
  295.         yield();
  296.         return;
  297.     };
  298.  
  299. #ifdef VERSION_A
  300.     if(frames[vfx].ready == 1 )
  301.     {
  302.         int sys_time;
  303.  
  304.         ctime = get_master_clock();
  305.         fdelay = (frames[vfx].pts - ctime);
  306.  
  307. //        printf("pts %f time %f delay %f\n",
  308. //                frames[vfx].pts, ctime, fdelay);
  309.  
  310.         if(fdelay > 15.0)
  311.         {
  312.             delay(1);
  313. //            yield();
  314.             return;
  315.         };
  316.  
  317.         ctime = get_master_clock();
  318.         fdelay = (frames[vfx].pts - ctime);
  319.  
  320.         sys_time = get_tick_count();
  321.  
  322. //      if(fdelay < 0)
  323. //            printf("systime %d pts %f time %f delay %f\n",
  324. //                    sys_time*10, frames[vfx].pts, ctime, fdelay);
  325.  
  326.         main_render->draw(main_render, &frames[vfx].picture);
  327.         main_render->win->panel.prg->current = frames[vfx].pts*1000;
  328.         send_message(&render->win->panel.prg->ctrl, MSG_PAINT, 0, 0);
  329.         frames[vfx].ready = 0;
  330.         vfx++;
  331.         vfx&= 3;
  332.     }
  333.     else yield();
  334.  
  335. #else
  336.  
  337.     if(frames[vfx].ready == 1 )
  338.     {
  339.         ctime = get_master_clock();
  340.         fdelay = (frames[vfx].pts - ctime);
  341.  
  342. //            printf("pts %f time %f delay %f\n",
  343. //                    frames[vfx].pts, ctime, fdelay);
  344.  
  345.         if(fdelay < 0.0 )
  346.         {
  347.             int  next_vfx;
  348.             fdelay = 0;
  349.             next_vfx = (vfx+1) & 3;
  350.             if( frames[next_vfx].ready == 1 )
  351.             {
  352.                 if(frames[next_vfx].pts <= ctime)
  353.                 {
  354.                     frames[vfx].ready = 0;                  // skip this frame
  355.                     vfx++;
  356.                     vfx&= 3;
  357.                 }
  358.                 else
  359.                 {
  360.                     if( (frames[next_vfx].pts - ctime) <
  361.                         ( ctime - frames[vfx].pts) )
  362.                     {
  363.                         frames[vfx].ready = 0;                  // skip this frame
  364.                         vfx++;
  365.                         vfx&= 3;
  366.                         fdelay = (frames[next_vfx].pts - ctime);
  367.                     }
  368.                 }
  369.             };
  370.         };
  371.  
  372.         if(fdelay > 10.0)
  373.         {
  374.            int val = fdelay;
  375.            printf("pts %f time %f delay %d\n",
  376.                    frames[vfx].pts, ctime, val);
  377.            delay(val/10);
  378.         };
  379.  
  380.         ctime = get_master_clock();
  381.         fdelay = (frames[vfx].pts - ctime);
  382.  
  383.         printf("pts %f time %f delay %f\n",
  384.                 frames[vfx].pts, ctime, fdelay);
  385.  
  386.         main_render->draw(main_render, &frames[vfx].picture);
  387.         main_render->win->panel.prg->current = frames[vfx].pts;
  388. //        send_message(&render->win->panel.prg->ctrl, MSG_PAINT, 0, 0);
  389.         frames[vfx].ready = 0;
  390.         vfx++;
  391.         vfx&= 3;
  392.     }
  393.     else yield();
  394. #endif
  395.  
  396. }
  397.  
  398.  
  399.  
  400.  
  401. extern char *movie_file;
  402.  
  403. int video_thread(void *param)
  404. {
  405.     window_t    *MainWindow;
  406.  
  407.     init_winlib();
  408.  
  409.     MainWindow = create_window(movie_file,0,
  410.                                10,10,width,height+29+55,MainWindowProc);
  411.  
  412.     MainWindow->panel.prg->max = stream_duration;
  413. //    printf("MainWindow %x\n", MainWindow);
  414.  
  415.     main_render->win = MainWindow;
  416.  
  417.     show_window(MainWindow, NORMAL);
  418.  
  419.     render_draw_client(main_render);
  420.     player_state = PAUSE_2_PLAY;
  421.  
  422.     run_render(MainWindow, main_render);
  423.  
  424. //    printf("exit thread\n");
  425.     player_state = CLOSED;
  426.     return 0;
  427. };
  428.  
  429.  
  430. void draw_hw_picture(render_t *render, AVPicture *picture);
  431. void draw_sw_picture(render_t *render, AVPicture *picture);
  432.  
  433. render_t *create_render(uint32_t width, uint32_t height,
  434.                         uint32_t ctx_format, uint32_t flags)
  435. {
  436.     render_t *render;
  437.  
  438. //    __asm__ __volatile__("int3");
  439.  
  440.     render = (render_t*)malloc(sizeof(render_t));
  441.     memset(render, 0, sizeof(render_t));
  442.  
  443.     render->ctx_width  = width;
  444.     render->ctx_height = height;
  445.     render->ctx_format = ctx_format;
  446.  
  447.     mutex_lock(&driver_lock);
  448.     render->caps = InitPixlib(flags);
  449.     mutex_unlock(&driver_lock);
  450.  
  451.     if(render->caps==0)
  452.     {
  453.         printf("FPlay render engine: Hardware acceleration disabled\n");
  454.         render->draw = draw_sw_picture;
  455.     }
  456.     else
  457.     {
  458.         render->target = 0;
  459.         render->draw   = draw_hw_picture;
  460.     };
  461.  
  462.     render->state = EMPTY;
  463.     return render;
  464. };
  465.  
  466. int render_set_size(render_t *render, int width, int height)
  467. {
  468.     int i;
  469.  
  470.     render->layout = 0;
  471.     render->rcvideo.l = 0;
  472.     render->rcvideo.t = 0;
  473.     render->rcvideo.r = width;
  474.     render->rcvideo.b = height;
  475.  
  476.     if( render->win_height > height )
  477.     {
  478.         int yoffs;
  479.         yoffs = (render->win_height-height)/2;
  480.         if(yoffs)
  481.         {
  482.             render->rctop.t = 0;
  483.             render->rctop.b = yoffs;
  484.             render->rcvideo.t  = yoffs;
  485.             render->layout |= HAS_TOP;
  486.         }
  487.  
  488.         yoffs = render->win_height-(render->rcvideo.t+render->rcvideo.b);
  489.         if(yoffs)
  490.         {
  491.             render->rcbottom.t = render->rcvideo.t+render->rcvideo.b;
  492.             render->rcbottom.b = yoffs;
  493.             render->layout |= HAS_BOTTOM;
  494.         }
  495.     }
  496.  
  497.     if( render->win_width > width )
  498.     {
  499.         int xoffs;
  500.         xoffs = (render->win_width-width)/2;
  501.         if(xoffs)
  502.         {
  503.             render->rcleft.r  = xoffs;
  504.             render->rcvideo.l = xoffs;
  505.             render->layout |= HAS_LEFT;
  506.         }
  507.         xoffs = render->win_width-(render->rcvideo.l+render->rcvideo.r);
  508.         if(xoffs)
  509.         {
  510.             render->rcright.l = render->rcvideo.l+render->rcvideo.r;
  511.             render->rcright.r = xoffs;
  512.             render->layout |= HAS_RIGHT;
  513.         }
  514.     };
  515.  
  516.     if(render->state == EMPTY)
  517.     {
  518.         if(render->caps & HW_TEX_BLIT)
  519.         {
  520.             for( i=0; i < 4; i++)
  521.             {
  522.                 render->bitmap[i].width  = render->ctx_width;
  523.                 render->bitmap[i].height = render->ctx_height;
  524.  
  525.                 if( create_bitmap(&render->bitmap[i]) != 0 )
  526.                 {
  527.                     player_state = CLOSED;
  528. /*
  529.  *  Epic fail. Need  exit_thread() here
  530.  *
  531. */
  532.                     return 0;
  533.                 };
  534.             }
  535.         }
  536.         else
  537.         {
  538.             render->bitmap[0].width  = width;
  539.             render->bitmap[0].height = height;
  540.  
  541.             if( create_bitmap(&render->bitmap[0]) != 0 )
  542.                 return 0;
  543.         };
  544.         render->state = INIT;
  545.         return 0;
  546.     };
  547.  
  548.     if(render->caps & HW_TEX_BLIT)          /*  hw scaler  */
  549.         return 0;
  550.  
  551.     render->bitmap[0].width  = width;
  552.     render->bitmap[0].height = height;
  553.     resize_bitmap(&render->bitmap[0]);
  554.  
  555.     return 0;
  556. };
  557.  
  558. void render_adjust_size(render_t *render, window_t *win)
  559. {
  560.     uint32_t right, bottom, new_w, new_h;
  561.     uint32_t s, sw, sh;
  562.     uint8_t  state;
  563.  
  564.  
  565.     right  = win->w;
  566.     bottom = win->h-CAPTION_HEIGHT-55;
  567.     render->win_state  = win->win_state;
  568.  
  569.     if(render->win_state == MINIMIZED)
  570.         return;
  571.  
  572.     if(render->win_state == ROLLED)
  573.         return;
  574.  
  575.     if( right  == render->win_width &&
  576.         bottom == render->win_height)
  577.         return;
  578.  
  579.     new_w = bottom*render->ctx_width/render->ctx_height;
  580.     new_h = right*render->ctx_height/render->ctx_width;
  581.  
  582. //    printf("new_w %d new_h %d\n", new_w, new_h);
  583.  
  584.     s  = right * bottom;
  585.     sw = right * new_h;
  586.     sh = bottom * new_w;
  587.  
  588.     if( abs(s-sw) > abs(s-sh))
  589.         new_h = bottom;
  590.     else
  591.         new_w = right;
  592.  
  593.     if(new_w < 64)
  594.     {
  595.         new_w = 64;
  596.         new_h = 64*render->ctx_height/render->ctx_width;
  597.     };
  598.  
  599.     render->win_width  = win->w;
  600.     render->win_height = win->h-CAPTION_HEIGHT-55;
  601.     render_set_size(render, new_w, new_h);
  602. };
  603.  
  604. void draw_hw_picture(render_t *render, AVPicture *picture)
  605. {
  606.     int      dst_width, dst_height;
  607.     bitmap_t   *bitmap;
  608.     uint8_t    *data[4];
  609.     int      linesize[4];
  610.     int ret;
  611.  
  612.     if(render->win_state == MINIMIZED ||
  613.        render->win_state == ROLLED)
  614.         return;
  615.  
  616.     if(render->caps & HW_TEX_BLIT)
  617.     {
  618.         dst_width  = render->ctx_width;
  619.         dst_height = render->ctx_height;
  620.     }
  621.     else
  622.     {
  623.         dst_width  = render->win_width;
  624.         dst_height = render->win_height;
  625.     };
  626.  
  627.     cvt_ctx = sws_getCachedContext(cvt_ctx,
  628.               render->ctx_width, render->ctx_height, render->ctx_format,
  629.               dst_width, dst_height, PIX_FMT_BGRA,
  630.               SWS_FAST_BILINEAR, NULL, NULL, NULL);
  631.     if(cvt_ctx == NULL)
  632.     {
  633.         printf("Cannot initialize the conversion context!\n");
  634.         return ;
  635.     };
  636.  
  637.     bitmap = &render->bitmap[render->target];
  638.  
  639.     ret = lock_bitmap(bitmap);
  640.     if( ret != 0)
  641.     {
  642.         printf("Cannot lock the bitmap!\n");
  643.         return ;
  644.     }
  645.  
  646. //    printf("sws_getCachedContext\n");
  647.     data[0] = bitmap->data;
  648.     data[1] = bitmap->data+1;
  649.     data[2] = bitmap->data+2;
  650.     data[3] = bitmap->data+3;
  651.  
  652.     linesize[0] = bitmap->pitch;
  653.     linesize[1] = bitmap->pitch;
  654.     linesize[2] = bitmap->pitch;
  655.     linesize[3] = bitmap->pitch;
  656.  
  657.     sws_scale(cvt_ctx, (const uint8_t* const *)picture->data,
  658.               picture->linesize, 0, render->ctx_height, data, linesize);
  659. //    printf("sws_scale\n");
  660.  
  661.     blit_bitmap(bitmap, render->rcvideo.l,
  662.                  CAPTION_HEIGHT+render->rcvideo.t,
  663.                  render->rcvideo.r, render->rcvideo.b);
  664.     render->last_bitmap = bitmap;
  665. //    printf("blit_bitmap\n");
  666.  
  667.  
  668.     render->target++;
  669.     render->target&= 3;
  670. }
  671.  
  672. void draw_sw_picture(render_t *render, AVPicture *picture)
  673. {
  674.     uint8_t     *data[4];
  675.     int      linesize[4];
  676.  
  677.     if(render->win_state == MINIMIZED ||
  678.        render->win_state == ROLLED)
  679.         return;
  680.  
  681.     cvt_ctx = sws_getCachedContext(cvt_ctx,
  682.               render->ctx_width, render->ctx_height,
  683.               render->ctx_format,
  684.               render->rcvideo.r, render->rcvideo.b,
  685.               PIX_FMT_BGRA, SWS_FAST_BILINEAR, NULL, NULL, NULL);
  686.     if(cvt_ctx == NULL)
  687.     {
  688.         printf("Cannot initialize the conversion context!\n");
  689.         return ;
  690.     }
  691.  
  692.     data[0] = render->bitmap[0].data;
  693.     data[1] = render->bitmap[0].data+1;
  694.     data[2] = render->bitmap[0].data+2;
  695.     data[3] = render->bitmap[0].data+3;
  696.  
  697.  
  698.     linesize[0] = render->bitmap[0].pitch;
  699.     linesize[1] = render->bitmap[0].pitch;
  700.     linesize[2] = render->bitmap[0].pitch;
  701.     linesize[3] = render->bitmap[0].pitch;
  702.  
  703.     sws_scale(cvt_ctx, (const uint8_t* const *)picture->data,
  704.               picture->linesize, 0, render->ctx_height, data, linesize);
  705.  
  706.     blit_bitmap(&render->bitmap[0], render->rcvideo.l,
  707.                 render->rcvideo.t+CAPTION_HEIGHT,
  708.                 render->rcvideo.r, render->rcvideo.b);
  709.     render->last_bitmap = &render->bitmap[0];
  710. }
  711.  
  712. void render_draw_client(render_t *render)
  713. {
  714.     if(render->win_state == MINIMIZED ||
  715.        render->win_state == ROLLED)
  716.         return;
  717.  
  718.     if((player_state == PAUSE) ||
  719.        (player_state == PLAY_INIT) )
  720.     {
  721.          if(frames[vfx].ready == 1 )
  722.             main_render->draw(main_render, &frames[vfx].picture);
  723.          else
  724.             draw_bar(0, CAPTION_HEIGHT, render->win_width,
  725.                  render->rcvideo.b, 0);
  726.     };
  727.  
  728.     if(render->layout & HAS_TOP)
  729.         draw_bar(0, CAPTION_HEIGHT, render->win_width,
  730.                  render->rctop.b, 0);
  731.     if(render->layout & HAS_LEFT)
  732.         draw_bar(0, render->rcvideo.t+CAPTION_HEIGHT, render->rcleft.r,
  733.                  render->rcvideo.b, 0);
  734.     if(render->layout & HAS_RIGHT)
  735.         draw_bar(render->rcright.l, render->rcvideo.t+CAPTION_HEIGHT,
  736.                  render->rcright.r, render->rcvideo.b, 0);
  737.     if(render->layout & HAS_BOTTOM)
  738.         draw_bar(0, render->rcbottom.t+CAPTION_HEIGHT,
  739.                  render->win_width, render->rcbottom.b, 0);
  740. }
  741.  
  742.  
  743.  
  744.  
  745.  
  746.