Paint Machine. [Part 5]
[xy_vsfilter.git] / src / subtitles / draw_item.cpp
blobfe773175beaf450736e7cc82abbbc0ed0dac2d6e
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"
9 using namespace std;
11 //////////////////////////////////////////////////////////////////////////
13 // DrawItem
14 //
15 CRect DrawItem::GetDirtyRect()
17 CRect r;
18 if(!switchpts || !fBody && !fBorder) return(r);
20 ASSERT(overlay_paint_machine);
21 CRect overlay_rect = overlay_paint_machine->CalcDirtyRect();
23 // Remember that all subtitle coordinates are specified in 1/8 pixels
24 // (x+4)>>3 rounds to nearest whole pixel.
25 // ??? What is xsub, ysub, mOffsetX and mOffsetY ?
26 int x = (xsub + overlay_rect.left + 4)>>3;
27 int y = (ysub + overlay_rect.top + 4)>>3;
28 int w = overlay_rect.Width()>>3;
29 int h = overlay_rect.Height()>>3;
30 r = clip_rect & CRect(x, y, x+w, y+h);
31 r &= clipper->CalcDirtyRect();
32 return r;
35 CRect DrawItem::Draw( SubPicDesc& spd, DrawItem& draw_item, const CRect& clip_rect )
37 CRect result;
38 SharedPtrGrayImage2 alpha_mask;
39 draw_item.clipper->Paint(&alpha_mask);
41 SharedPtrOverlay overlay;
42 ASSERT(draw_item.overlay_paint_machine);
43 draw_item.overlay_paint_machine->Paint(&overlay);
45 const SharedPtrByte& alpha = Rasterizer::CompositeAlphaMask(spd, overlay, draw_item.clip_rect & clip_rect, alpha_mask.get(),
46 draw_item.xsub, draw_item.ysub, draw_item.switchpts, draw_item.fBody, draw_item.fBorder,
47 &result);
48 Rasterizer::Draw(spd, overlay, result, alpha.get(),
49 draw_item.xsub, draw_item.ysub, draw_item.switchpts, draw_item.fBody, draw_item.fBorder);
50 return result;
53 DrawItem* DrawItem::CreateDrawItem( const SharedPtrOverlayPaintMachine& overlay_paint_machine, const CRect& clipRect,
54 const SharedPtrCClipperPaintMachine &clipper, int xsub, int ysub, const DWORD* switchpts, bool fBody, bool fBorder )
56 DrawItem* result = new DrawItem();
57 result->overlay_paint_machine = overlay_paint_machine;
58 result->clip_rect = clipRect;
59 result->clipper = clipper;
60 result->xsub = xsub;
61 result->ysub = ysub;
63 memcpy(result->switchpts, switchpts, sizeof(result->switchpts));
64 result->fBody = fBody;
65 result->fBorder = fBorder;
66 return result;
69 //////////////////////////////////////////////////////////////////////////
71 // CompositeDrawItem
72 //
74 CRect CompositeDrawItem::GetDirtyRect( CompositeDrawItem& item )
76 CRect result;
77 if (item.shadow)
79 result |= item.shadow->GetDirtyRect();
81 if (item.outline)
83 result |= item.outline->GetDirtyRect();
85 if (item.body)
87 result |= *item.body->GetDirtyRect();
89 return result;
92 struct GroupedDrawItems
94 CAtlList<SharedPtrDrawItem> draw_item_list;
95 CRect clip_rect;
98 //temporary data struct for the complex dirty rect splitting and draw item grouping algorithm
99 struct CompositeDrawItemEx
101 CompositeDrawItem *item;
102 CAtlList<int> rect_id_list;
106 typedef CAtlList<CompositeDrawItemEx*> PCompositeDrawItemExList;
107 typedef CAtlArray<CompositeDrawItemEx> CompositeDrawItemExVec;
108 typedef CAtlArray<CompositeDrawItemExVec> CompositeDrawItemExTree;
110 typedef ::boost::shared_ptr<PCompositeDrawItemExList> SharedPCompositeDrawItemExList;
112 class XyRectEx: public CRect
114 public:
115 SharedPCompositeDrawItemExList item_ex_list;
117 void SetRect(const RECT& rect)
119 __super::operator=(rect);
121 void SetRect(
122 _In_ int x1,
123 _In_ int y1,
124 _In_ int x2,
125 _In_ int y2) throw()
127 __super::SetRect(x1,y1,x2,y2);
131 typedef CAtlList<XyRectEx> XyRectExList;
133 void MergeRects(const XyRectExList& input, XyRectExList* output);
134 void CreateDrawItemExTree( CompositeDrawItemListList& input,
135 CompositeDrawItemExTree *out_draw_item_ex_tree,
136 XyRectExList *out_rect_ex_list );
138 void CompositeDrawItem::Draw( SubPicDesc& spd, CompositeDrawItemListList& compDrawItemListList )
140 CompositeDrawItemExTree draw_item_ex_tree;
141 XyRectExList rect_ex_list;
142 CreateDrawItemExTree(compDrawItemListList, &draw_item_ex_tree, &rect_ex_list);
144 XyRectExList grouped_rect_exs;
145 MergeRects(rect_ex_list, &grouped_rect_exs);
147 CAtlArray<GroupedDrawItems> grouped_draw_items;
149 grouped_draw_items.SetCount(grouped_rect_exs.GetCount());
151 POSITION pos = grouped_rect_exs.GetHeadPosition();
152 for(int rect_id=0;pos;rect_id++)
154 XyRectEx& item = grouped_rect_exs.GetNext(pos);
155 grouped_draw_items.GetAt(rect_id).clip_rect = item;
156 POSITION pos_item = item.item_ex_list->GetHeadPosition();
157 while(pos_item)
159 CompositeDrawItemEx* draw_item_ex = item.item_ex_list->GetNext(pos_item);
160 if( draw_item_ex->rect_id_list.GetTail() != rect_id )//wipe out repeated item. this safe since the list has a dummy item -1
161 draw_item_ex->rect_id_list.AddTail(rect_id);
164 for (int i=0;i<draw_item_ex_tree.GetCount();i++)
166 CompositeDrawItemExVec &draw_item_ex_vec = draw_item_ex_tree[i];
167 for (int j=0;j<draw_item_ex_vec.GetCount();j++)
169 CompositeDrawItemEx &draw_item_ex = draw_item_ex_vec[j];
170 if (draw_item_ex.item->shadow)
172 pos = draw_item_ex.rect_id_list.GetHeadPosition();;
173 draw_item_ex.rect_id_list.GetNext(pos);
174 while(pos)
176 int id = draw_item_ex.rect_id_list.GetNext(pos);
177 grouped_draw_items[id].draw_item_list.AddTail( draw_item_ex.item->shadow );
181 for (int j=0;j<draw_item_ex_vec.GetCount();j++)
183 CompositeDrawItemEx &draw_item_ex = draw_item_ex_vec[j];
184 if (draw_item_ex.item->outline)
186 pos = draw_item_ex.rect_id_list.GetHeadPosition();;
187 draw_item_ex.rect_id_list.GetNext(pos);
188 while(pos)
190 int id = draw_item_ex.rect_id_list.GetNext(pos);
191 grouped_draw_items[id].draw_item_list.AddTail( draw_item_ex.item->outline );
195 for (int j=0;j<draw_item_ex_vec.GetCount();j++)
197 CompositeDrawItemEx &draw_item_ex = draw_item_ex_vec[j];
198 if (draw_item_ex.item->body)
200 pos = draw_item_ex.rect_id_list.GetHeadPosition();;
201 draw_item_ex.rect_id_list.GetNext(pos);
202 while(pos)
204 int id = draw_item_ex.rect_id_list.GetNext(pos);
205 grouped_draw_items[id].draw_item_list.AddTail( draw_item_ex.item->body );
211 for (int i=0;i<grouped_draw_items.GetCount();i++)
213 GroupedDrawItems& item = grouped_draw_items[i];
214 pos = item.draw_item_list.GetHeadPosition();
215 while(pos)
217 DrawItem::Draw(spd, *item.draw_item_list.GetNext(pos), item.clip_rect);
222 void CreateDrawItemExTree( CompositeDrawItemListList& input,
223 CompositeDrawItemExTree *out_draw_item_ex_tree,
224 XyRectExList *out_rect_ex_list )
226 ASSERT(out_draw_item_ex_tree!=NULL && out_rect_ex_list!=NULL);
228 int list_count = input.GetCount();
229 out_draw_item_ex_tree->SetCount(list_count);
230 POSITION list_pos = input.GetHeadPosition();
231 for (int list_id=0;list_id<list_count;list_id++)
233 CompositeDrawItemList& compDrawItemList = input.GetNext(list_pos);
234 int count = compDrawItemList.GetCount();
235 CompositeDrawItemExVec& out_draw_item_exs = out_draw_item_ex_tree->GetAt(list_id);
236 out_draw_item_exs.SetCount(count);
237 POSITION item_pos = compDrawItemList.GetHeadPosition();
238 for (int item_id=0; item_id<count; item_id++ )
240 CompositeDrawItem& comp_draw_item = compDrawItemList.GetNext(item_pos);
241 CompositeDrawItemEx& comp_draw_item_ex = out_draw_item_exs.GetAt(item_id);
242 comp_draw_item_ex.item = &comp_draw_item;
243 comp_draw_item_ex.rect_id_list.AddHead(-1);//dummy head
245 XyRectEx &rect_ex = out_rect_ex_list->GetAt(out_rect_ex_list->AddTail());
246 rect_ex.item_ex_list.reset(new PCompositeDrawItemExList());
247 rect_ex.item_ex_list->AddTail( &comp_draw_item_ex);
248 rect_ex.SetRect( CompositeDrawItem::GetDirtyRect(comp_draw_item) );
253 void MergeRects(const XyRectExList& input, XyRectExList* output)
255 int input_count = input.GetCount();
256 if(output==NULL || input_count==0)
257 return;
259 typedef CAtlList<XyRectEx> Segment;
261 struct BreakPoint
263 int x;
264 const XyRectEx* rect;
266 inline bool operator<(const BreakPoint& breakpoint ) const
268 return (x < breakpoint.x);
272 std::vector<int> vertical_breakpoints(2*input_count);
273 std::vector<BreakPoint> herizon_breakpoints(input_count);
275 POSITION pos = input.GetHeadPosition();
276 for(int i=0; i<input_count; i++)
278 const XyRectEx& rect = input.GetNext(pos);
279 vertical_breakpoints[2*i]=rect.top;
280 vertical_breakpoints[2*i+1]=rect.bottom;
282 herizon_breakpoints[i].x = rect.left;
283 herizon_breakpoints[i].rect = &rect;
286 std::sort(vertical_breakpoints.begin(), vertical_breakpoints.end());
287 std::sort(herizon_breakpoints.begin(), herizon_breakpoints.end());
289 CAtlArray<Segment> tempSegments;
290 tempSegments.SetCount(vertical_breakpoints.size()-1);
291 int prev = vertical_breakpoints[0], count = 0;
292 for(int ptr = 1; ptr<vertical_breakpoints.size(); ptr++)
294 if(vertical_breakpoints[ptr] != prev)
296 Segment& seg = tempSegments[count];
297 seg.AddTail();
298 seg.GetTail().SetRect(INT_MIN, prev, INT_MIN, vertical_breakpoints[ptr]);
299 seg.GetTail().item_ex_list.reset(new PCompositeDrawItemExList());
301 prev = vertical_breakpoints[ptr];
302 count++;
306 for(int i=0; i<input_count; i++)
308 const XyRectEx& rect = *herizon_breakpoints[i].rect;
310 int start = 0, mid, end = count;
312 while(start<end)
314 mid = (start+end)>>1;
315 if(tempSegments[mid].GetTail().top < rect.top)
317 start = mid+1;
319 else
321 end = mid;
324 for(; start < count; start++)
326 CAtlList<XyRectEx>& cur_line = tempSegments[start];
327 XyRectEx & item = cur_line.GetTail();
328 if (item.top >= rect.bottom)
330 break;
332 if (item.right<rect.left)
334 cur_line.AddTail();
335 XyRectEx & new_item = cur_line.GetTail();
336 new_item.SetRect( rect.left, item.top, rect.right, item.bottom );
337 new_item.item_ex_list.reset(new PCompositeDrawItemExList());
338 new_item.item_ex_list->AddTailList( rect.item_ex_list.get() );
340 else
342 if (item.right<rect.right)
344 item.right = rect.right;
346 item.item_ex_list->AddTailList( rect.item_ex_list.get() );
351 for (int i=count-1;i>0;i--)
353 CAtlList<XyRectEx>& cur_line = tempSegments[i];
354 CAtlList<XyRectEx>& upper_line = tempSegments[i-1];
356 POSITION pos_cur_line = cur_line.GetTailPosition();
357 XyRectEx *cur_rect = &cur_line.GetPrev(pos_cur_line);
358 if(cur_rect->top == upper_line.GetTail().bottom)
360 POSITION pos = upper_line.GetTailPosition();
361 while(pos)
363 XyRectEx& upper_rect = upper_line.GetPrev(pos);
364 while( upper_rect.right<cur_rect->right || upper_rect.left<cur_rect->left )
366 output->AddHead(*cur_rect);
367 //if(!cur_line.IsEmpty())
368 cur_rect = &cur_line.GetPrev(pos_cur_line);
370 if(!pos_cur_line)
371 break;
373 if(upper_rect.right==cur_rect->right && upper_rect.left==cur_rect->left)
375 upper_rect.bottom = cur_rect->bottom;
376 upper_rect.item_ex_list->AddTailList( cur_rect->item_ex_list.get() );
377 //if(!cur_line.IsEmpty())
378 cur_rect = &cur_line.GetPrev(pos_cur_line);
380 //else if ( upper_rect.right>cur_rect.right || upper_rect.left>cur_rect.left )
383 while(pos_cur_line)
385 output->AddHead(*cur_rect);
386 cur_rect = &cur_line.GetPrev(pos_cur_line);
389 if(count>0)
391 CAtlList<XyRectEx>& cur_line = tempSegments[0];
392 POSITION pos_cur_line = cur_line.GetTailPosition();
393 XyRectEx *cur_rect = &cur_line.GetPrev(pos_cur_line);
394 while(pos_cur_line)
396 output->AddHead(*cur_rect);
397 cur_rect = &cur_line.GetPrev(pos_cur_line);