Bugfix: PGS YVU => YUV
[xy_vsfilter.git] / src / subtitles / draw_item.cpp
blob5d7cc0af93e15b23b77d119112903ae558681104
1 #include "stdafx.h"
2 #include "draw_item.h"
3 #include <vector>
4 #include <algorithm>
5 #include <boost/shared_ptr.hpp>
6 #include "xy_overlay_paint_machine.h"
7 #include "xy_clipper_paint_machine.h"
8 #include "../SubPic/ISubPic.h"
9 #include "xy_bitmap.h"
11 using namespace std;
13 //////////////////////////////////////////////////////////////////////////
15 // DrawItem
16 //
17 CRectCoor2 DrawItem::GetDirtyRect()
19 CRectCoor2 r;
20 if(!switchpts || !fBody && !fBorder) return(r);
22 ASSERT(overlay_paint_machine);
23 CRectCoor2 overlay_rect = overlay_paint_machine->CalcDirtyRect();
25 // Remember that all subtitle coordinates are specified in 1/8 pixels
26 // (x+4)>>3 rounds to nearest whole pixel.
27 // ??? What is xsub, ysub, mOffsetX and mOffsetY ?
28 int x = (xsub + overlay_rect.left + 4)>>3;
29 int y = (ysub + overlay_rect.top + 4)>>3;
30 int w = overlay_rect.Width()>>3;
31 int h = overlay_rect.Height()>>3;
32 r = clip_rect & CRect(x, y, x+w, y+h);
33 r &= clipper->CalcDirtyRect();
35 //expand the rect, so that it is possible to perform chroma sub-sampling
36 r.left &= ~1;
37 r.right = (r.right + 1)&~1;
38 r.top &= ~1;
39 r.bottom = (r.bottom + 1)&~1;
40 return r;
43 CRectCoor2 DrawItem::Draw( XyBitmap* bitmap, DrawItem& draw_item, const CRectCoor2& clip_rect )
45 CRect result;
46 SharedPtrGrayImage2 alpha_mask;
47 draw_item.clipper->Paint(&alpha_mask);
49 SharedPtrOverlay overlay;
50 ASSERT(draw_item.overlay_paint_machine);
51 draw_item.overlay_paint_machine->Paint(&overlay);
53 const SharedPtrByte& alpha = Rasterizer::CompositeAlphaMask(overlay, draw_item.clip_rect & clip_rect, alpha_mask.get(),
54 draw_item.xsub, draw_item.ysub, draw_item.switchpts, draw_item.fBody, draw_item.fBorder,
55 &result);
57 Rasterizer::Draw(bitmap, overlay, result, alpha.get(),
58 draw_item.xsub, draw_item.ysub, draw_item.switchpts, draw_item.fBody, draw_item.fBorder);
59 return result;
62 DrawItem* DrawItem::CreateDrawItem( const SharedPtrOverlayPaintMachine& overlay_paint_machine, const CRect& clipRect,
63 const SharedPtrCClipperPaintMachine &clipper, int xsub, int ysub, const DWORD* switchpts, bool fBody, bool fBorder )
65 DrawItem* result = new DrawItem();
66 result->overlay_paint_machine = overlay_paint_machine;
67 result->clip_rect = clipRect;
68 result->clipper = clipper;
69 result->xsub = xsub;
70 result->ysub = ysub;
72 memcpy(result->switchpts, switchpts, sizeof(result->switchpts));
73 result->fBody = fBody;
74 result->fBorder = fBorder;
76 result->m_key.reset( new DrawItemHashKey(*result) );
77 result->m_key->UpdateHashValue();
79 return result;
82 const SharedPtrDrawItemHashKey& DrawItem::GetHashKey()
84 return m_key;
87 //////////////////////////////////////////////////////////////////////////
89 // CompositeDrawItem
90 //
92 CRectCoor2 CompositeDrawItem::GetDirtyRect( CompositeDrawItem& item )
94 CRectCoor2 result;
95 if (item.shadow)
97 result |= item.shadow->GetDirtyRect();
99 if (item.outline)
101 result |= item.outline->GetDirtyRect();
103 if (item.body)
105 result |= *item.body->GetDirtyRect();
107 return result;
110 //temporary data struct for the complex dirty rect splitting and draw item grouping algorithm
111 struct CompositeDrawItemEx
113 CompositeDrawItem *item;
114 CAtlList<int> rect_id_list;
118 typedef CAtlList<CompositeDrawItemEx*> PCompositeDrawItemExList;
119 typedef CAtlArray<CompositeDrawItemEx> CompositeDrawItemExVec;
120 typedef CAtlArray<CompositeDrawItemExVec> CompositeDrawItemExTree;
122 typedef ::boost::shared_ptr<PCompositeDrawItemExList> SharedPCompositeDrawItemExList;
124 class XyRectEx: public CRect
126 public:
127 SharedPCompositeDrawItemExList item_ex_list;
129 void SetRect(const RECT& rect)
131 __super::operator=(rect);
133 void SetRect(
134 _In_ int x1,
135 _In_ int y1,
136 _In_ int x2,
137 _In_ int y2) throw()
139 __super::SetRect(x1,y1,x2,y2);
143 typedef CAtlList<XyRectEx> XyRectExList;
145 void MergeRects(const XyRectExList& input, XyRectExList* output);
146 void CreateDrawItemExTree( CompositeDrawItemListList& input,
147 CompositeDrawItemExTree *out_draw_item_ex_tree,
148 XyRectExList *out_rect_ex_list );
150 void CompositeDrawItem::Draw( XySubRenderFrame**output, CompositeDrawItemListList& compDrawItemListList )
152 if (!output)
154 return;
156 *output = NULL;
158 CompositeDrawItemExTree draw_item_ex_tree;
159 XyRectExList rect_ex_list;
160 CreateDrawItemExTree(compDrawItemListList, &draw_item_ex_tree, &rect_ex_list);
162 XyRectExList grouped_rect_exs;
163 MergeRects(rect_ex_list, &grouped_rect_exs);
165 CAtlArray<GroupedDrawItems> grouped_draw_items;
167 grouped_draw_items.SetCount(grouped_rect_exs.GetCount());
169 POSITION pos = grouped_rect_exs.GetHeadPosition();
170 for(int rect_id=0;pos;rect_id++)
172 XyRectEx& item = grouped_rect_exs.GetNext(pos);
173 grouped_draw_items.GetAt(rect_id).clip_rect = item;
174 POSITION pos_item = item.item_ex_list->GetHeadPosition();
175 while(pos_item)
177 CompositeDrawItemEx* draw_item_ex = item.item_ex_list->GetNext(pos_item);
178 if( draw_item_ex->rect_id_list.GetTail() != rect_id )//wipe out repeated item. this safe since the list has a dummy item -1
179 draw_item_ex->rect_id_list.AddTail(rect_id);
182 for (unsigned i=0;i<draw_item_ex_tree.GetCount();i++)
184 CompositeDrawItemExVec &draw_item_ex_vec = draw_item_ex_tree[i];
185 for (unsigned j=0;j<draw_item_ex_vec.GetCount();j++)
187 CompositeDrawItemEx &draw_item_ex = draw_item_ex_vec[j];
188 if (draw_item_ex.item->shadow)
190 pos = draw_item_ex.rect_id_list.GetHeadPosition();;
191 draw_item_ex.rect_id_list.GetNext(pos);
192 while(pos)
194 int id = draw_item_ex.rect_id_list.GetNext(pos);
195 grouped_draw_items[id].draw_item_list.AddTail( draw_item_ex.item->shadow );
199 for (unsigned j=0;j<draw_item_ex_vec.GetCount();j++)
201 CompositeDrawItemEx &draw_item_ex = draw_item_ex_vec[j];
202 if (draw_item_ex.item->outline)
204 pos = draw_item_ex.rect_id_list.GetHeadPosition();;
205 draw_item_ex.rect_id_list.GetNext(pos);
206 while(pos)
208 int id = draw_item_ex.rect_id_list.GetNext(pos);
209 grouped_draw_items[id].draw_item_list.AddTail( draw_item_ex.item->outline );
213 for (unsigned j=0;j<draw_item_ex_vec.GetCount();j++)
215 CompositeDrawItemEx &draw_item_ex = draw_item_ex_vec[j];
216 if (draw_item_ex.item->body)
218 pos = draw_item_ex.rect_id_list.GetHeadPosition();;
219 draw_item_ex.rect_id_list.GetNext(pos);
220 while(pos)
222 int id = draw_item_ex.rect_id_list.GetNext(pos);
223 grouped_draw_items[id].draw_item_list.AddTail( draw_item_ex.item->body );
229 XySubRenderFrameCreater *render_frame_creater = XySubRenderFrameCreater::GetDefaultCreater();
231 *output = render_frame_creater->NewXySubRenderFrame(grouped_draw_items.GetCount());
232 XySubRenderFrame& sub_render_frame = **output;
234 for (unsigned i=0;i<grouped_draw_items.GetCount();i++)
236 grouped_draw_items[i].Draw(&(sub_render_frame.m_bitmaps.GetAt(i)), &(sub_render_frame.m_bitmap_ids.GetAt(i)));
240 void CreateDrawItemExTree( CompositeDrawItemListList& input,
241 CompositeDrawItemExTree *out_draw_item_ex_tree,
242 XyRectExList *out_rect_ex_list )
244 ASSERT(out_draw_item_ex_tree!=NULL && out_rect_ex_list!=NULL);
246 int list_count = input.GetCount();
247 out_draw_item_ex_tree->SetCount(list_count);
248 POSITION list_pos = input.GetHeadPosition();
249 for (int list_id=0;list_id<list_count;list_id++)
251 CompositeDrawItemList& compDrawItemList = input.GetNext(list_pos);
252 int count = compDrawItemList.GetCount();
253 CompositeDrawItemExVec& out_draw_item_exs = out_draw_item_ex_tree->GetAt(list_id);
254 out_draw_item_exs.SetCount(count);
255 POSITION item_pos = compDrawItemList.GetHeadPosition();
256 for (int item_id=0; item_id<count; item_id++ )
258 CompositeDrawItem& comp_draw_item = compDrawItemList.GetNext(item_pos);
259 CompositeDrawItemEx& comp_draw_item_ex = out_draw_item_exs.GetAt(item_id);
260 comp_draw_item_ex.item = &comp_draw_item;
261 comp_draw_item_ex.rect_id_list.AddHead(-1);//dummy head
263 XyRectEx &rect_ex = out_rect_ex_list->GetAt(out_rect_ex_list->AddTail());
264 rect_ex.item_ex_list.reset(new PCompositeDrawItemExList());
265 rect_ex.item_ex_list->AddTail( &comp_draw_item_ex);
266 rect_ex.SetRect( CompositeDrawItem::GetDirtyRect(comp_draw_item) );
271 void MergeRects(const XyRectExList& input, XyRectExList* output)
273 int input_count = input.GetCount();
274 if(output==NULL || input_count==0)
275 return;
277 typedef CAtlList<XyRectEx> Segment;
279 struct BreakPoint
281 int x;
282 const XyRectEx* rect;
284 inline bool operator<(const BreakPoint& breakpoint ) const
286 return (x < breakpoint.x);
290 std::vector<int> vertical_breakpoints(2*input_count);
291 std::vector<BreakPoint> herizon_breakpoints(input_count);
293 POSITION pos = input.GetHeadPosition();
294 for(int i=0; i<input_count; i++)
296 const XyRectEx& rect = input.GetNext(pos);
297 vertical_breakpoints[2*i]=rect.top;
298 vertical_breakpoints[2*i+1]=rect.bottom;
300 herizon_breakpoints[i].x = rect.left;
301 herizon_breakpoints[i].rect = &rect;
304 std::sort(vertical_breakpoints.begin(), vertical_breakpoints.end());
305 std::sort(herizon_breakpoints.begin(), herizon_breakpoints.end());
307 CAtlArray<Segment> tempSegments;
308 tempSegments.SetCount(vertical_breakpoints.size()-1);
309 int prev = vertical_breakpoints[0], count = 0;
310 for(unsigned ptr = 1; ptr<vertical_breakpoints.size(); ptr++)
312 if(vertical_breakpoints[ptr] != prev)
314 Segment& seg = tempSegments[count];
315 seg.AddTail();
316 seg.GetTail().SetRect(INT_MIN, prev, INT_MIN, vertical_breakpoints[ptr]);
317 seg.GetTail().item_ex_list.reset(new PCompositeDrawItemExList());
319 prev = vertical_breakpoints[ptr];
320 count++;
324 for(int i=0; i<input_count; i++)
326 const XyRectEx& rect = *herizon_breakpoints[i].rect;
328 int start = 0, mid, end = count;
330 while(start<end)
332 mid = (start+end)>>1;
333 if(tempSegments[mid].GetTail().top < rect.top)
335 start = mid+1;
337 else
339 end = mid;
342 for(; start < count; start++)
344 CAtlList<XyRectEx>& cur_line = tempSegments[start];
345 XyRectEx & item = cur_line.GetTail();
346 if (item.top >= rect.bottom)
348 break;
350 if (item.right<rect.left)
352 cur_line.AddTail();
353 XyRectEx & new_item = cur_line.GetTail();
354 new_item.SetRect( rect.left, item.top, rect.right, item.bottom );
355 new_item.item_ex_list.reset(new PCompositeDrawItemExList());
356 new_item.item_ex_list->AddTailList( rect.item_ex_list.get() );
358 else
360 if (item.right<rect.right)
362 item.right = rect.right;
364 item.item_ex_list->AddTailList( rect.item_ex_list.get() );
369 for (int i=count-1;i>0;i--)
371 CAtlList<XyRectEx>& cur_line = tempSegments[i];
372 CAtlList<XyRectEx>& upper_line = tempSegments[i-1];
374 POSITION pos_cur_line = cur_line.GetTailPosition();
375 XyRectEx *cur_rect = &cur_line.GetPrev(pos_cur_line);
376 if(cur_rect->top == upper_line.GetTail().bottom)
378 POSITION pos = upper_line.GetTailPosition();
379 while(pos)
381 XyRectEx& upper_rect = upper_line.GetPrev(pos);
382 while( upper_rect.right<cur_rect->right || upper_rect.left<cur_rect->left )
384 output->AddHead(*cur_rect);
385 //if(!cur_line.IsEmpty())
386 cur_rect = &cur_line.GetPrev(pos_cur_line);
388 if(!pos_cur_line)
389 break;
391 if(upper_rect.right==cur_rect->right && upper_rect.left==cur_rect->left)
393 upper_rect.bottom = cur_rect->bottom;
394 upper_rect.item_ex_list->AddTailList( cur_rect->item_ex_list.get() );
395 //if(!cur_line.IsEmpty())
396 cur_rect = &cur_line.GetPrev(pos_cur_line);
398 //else if ( upper_rect.right>cur_rect.right || upper_rect.left>cur_rect.left )
401 while(pos_cur_line)
403 output->AddHead(*cur_rect);
404 cur_rect = &cur_line.GetPrev(pos_cur_line);
407 if(count>0)
409 CAtlList<XyRectEx>& cur_line = tempSegments[0];
410 POSITION pos_cur_line = cur_line.GetTailPosition();
411 XyRectEx *cur_rect = &cur_line.GetPrev(pos_cur_line);
412 while(pos_cur_line)
414 output->AddHead(*cur_rect);
415 cur_rect = &cur_line.GetPrev(pos_cur_line);
420 //////////////////////////////////////////////////////////////////////////
422 // GroupedDrawItems
425 void GroupedDrawItems::Draw( SharedPtrXyBitmap *bitmap, int *bitmap_identity_num )
427 ASSERT(bitmap && bitmap_identity_num);
428 BitmapMruCache *bitmap_cache = CacheManager::GetBitmapMruCache();
429 GroupedDrawItemsHashKey *key = new GroupedDrawItemsHashKey();
430 CreateHashKey(key);
431 XyFwGroupedDrawItemsHashKey::IdType key_id = XyFwGroupedDrawItemsHashKey(key).GetId();
432 POSITION pos = bitmap_cache->Lookup( key_id );
433 if (pos==NULL)
435 POSITION pos = draw_item_list.GetHeadPosition();
436 XyBitmap *tmp = XySubRenderFrameCreater::GetDefaultCreater()->CreateBitmap(clip_rect);
437 bitmap->reset(tmp);
438 while(pos)
440 DrawItem::Draw(tmp, *draw_item_list.GetNext(pos), clip_rect);
442 bitmap_cache->UpdateCache(key_id, *bitmap);
444 else
446 *bitmap = bitmap_cache->GetAt(pos);
447 bitmap_cache->UpdateCache(pos);
449 *bitmap_identity_num = key_id;
452 void GroupedDrawItems::CreateHashKey(GroupedDrawItemsHashKey *key)
454 ASSERT(key);
455 key->m_clip_rect = clip_rect;
456 GroupedDrawItemsHashKey::Keys *inner_key = new GroupedDrawItemsHashKey::Keys();
457 ASSERT(inner_key);
458 key->m_key.reset(inner_key);
459 inner_key->SetCount(draw_item_list.GetCount());
460 POSITION pos = draw_item_list.GetHeadPosition();
461 for (unsigned i=0;i<inner_key->GetCount();i++)
463 inner_key->GetAt(i) = draw_item_list.GetNext(pos)->GetHashKey();
465 key->UpdateHashValue();