1 /*$
2  Copyright (C) 2016-2020 Azel.
3 
4  This file is part of AzPainterB.
5 
6  AzPainterB 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 3 of the License, or
9  (at your option) any later version.
10 
11  AzPainterB 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, see <http://www.gnu.org/licenses/>.
18 $*/
19 
20 /*****************************************
21  * DrawData
22  *
23  * 更新関連
24  *****************************************/
25 
26 #include "mDef.h"
27 #include "mWindowDef.h"
28 #include "mWidget.h"
29 #include "mPixbuf.h"
30 #include "mRectBox.h"
31 
32 #include "defConfig.h"
33 #include "defDraw.h"
34 #include "defWidgets.h"
35 #include "defGridData.h"
36 
37 #include "draw_op_def.h"
38 #include "draw_main.h"
39 #include "draw_calc.h"
40 
41 #include "LayerList.h"
42 #include "LayerItem.h"
43 #include "TileImage.h"
44 #include "ImageBuf24.h"
45 #include "PixbufDraw.h"
46 
47 #include "Docks_external.h"
48 
49 
50 
51 /** キャンバスエリアを更新 */
52 
drawUpdate_canvasArea()53 void drawUpdate_canvasArea()
54 {
55 	mWidgetUpdate(M_WIDGET(APP_WIDGETS->canvas_area));
56 }
57 
58 /** すべて更新
59  *
60  * [ 合成イメージ、キャンバスエリア、(Dock)キャンバスビュー ] */
61 
drawUpdate_all()62 void drawUpdate_all()
63 {
64 	drawUpdate_blendImage_full(APP_DRAW);
65 	drawUpdate_canvasArea();
66 
67 	DockCanvasView_update();
68 }
69 
70 /** 全体 + レイヤ一覧を更新 */
71 
drawUpdate_all_layer()72 void drawUpdate_all_layer()
73 {
74 	drawUpdate_all();
75 
76 	DockLayer_update_all();
77 }
78 
79 /** 合成イメージを全体更新
80  *
81  * 背景とレイヤイメージ */
82 
drawUpdate_blendImage_full(DrawData * p)83 void drawUpdate_blendImage_full(DrawData *p)
84 {
85 	mBox box;
86 
87 	box.x = box.y = 0;
88 	box.w = p->imgw, box.h = p->imgh;
89 
90 	//背景
91 
92 	if(APP_CONF->fView & CONFIG_VIEW_F_BKGND_PLAID)
93 	{
94 		ImageBuf24_fillPlaid_box(p->blendimg, &box,
95 			APP_CONF->colBkgndPlaid[0], APP_CONF->colBkgndPlaid[1]);
96 	}
97 	else
98 		ImageBuf24_fillWhite(p->blendimg);
99 
100 	//合成
101 
102 	drawUpdate_blendImage_layer(p, &box);
103 }
104 
105 /** 合成イメージ:レイヤイメージを範囲更新
106  *
107  * [!] 背景は描画しない */
108 
drawUpdate_blendImage_layer(DrawData * p,mBox * box)109 void drawUpdate_blendImage_layer(DrawData *p,mBox *box)
110 {
111 	LayerItem *pi;
112 	int opacity,mode;
113 
114 	mode = p->sel.mode;
115 
116 	pi = LayerList_getItem_bottomVisibleImage(p->layerlist);
117 
118 	if(mode == DRAW_SELMODE_MOVECOPY_PASTE
119 		|| mode == DRAW_SELMODE_SELECT_PASTE)
120 	{
121 		//----- 貼付けモード時
122 
123 		for(; pi; pi = LayerItem_getPrevVisibleImage(pi))
124 		{
125 			opacity = LayerItem_getOpacity_real(pi);
126 
127 			TileImage_blendToImage24_rgba(pi->img, p->blendimg,
128 				box, opacity, pi->blendmode);
129 
130 			//貼付けイメージをカレントの上に挿入
131 
132 			if(pi == p->curlayer)
133 			{
134 				TileImage_blendToImage24_rgba(
135 					(mode == DRAW_SELMODE_SELECT_PASTE)? p->sel.img_selcopy: p->sel.img_movecopy,
136 					p->blendimg, box, opacity, pi->blendmode);
137 			}
138 		}
139 
140 		//カレントがフォルダの場合は表示されないので、最後に
141 
142 		if(!p->curlayer->img)
143 		{
144 			TileImage_blendToImage24_rgba(
145 				(mode == DRAW_SELMODE_SELECT_PASTE)? p->sel.img_selcopy: p->sel.img_movecopy,
146 				p->blendimg, box, 128, 0);
147 		}
148 	}
149 	else if(p->drawtext.in_dialog
150 		&& (p->drawtext.flags & DRAW_DRAWTEXT_F_PREVIEW))
151 	{
152 		//----- テキスト描画、ダイアログ中のプレビュー
153 
154 		for(; pi; pi = LayerItem_getPrevVisibleImage(pi))
155 		{
156 			opacity = LayerItem_getOpacity_real(pi);
157 
158 			TileImage_blendToImage24_rgba(pi->img, p->blendimg,
159 				box, opacity, pi->blendmode);
160 
161 			//プレビューイメージを挿入
162 
163 			if(pi == p->curlayer)
164 			{
165 				TileImage_blendToImage24_rgba(p->tileimgTmp,
166 					p->blendimg, box, opacity, pi->blendmode);
167 			}
168 		}
169 	}
170 	else
171 	{
172 		//----- 通常時
173 
174 		for(; pi; pi = LayerItem_getPrevVisibleImage(pi))
175 		{
176 			TileImage_blendToImage24_rgba(pi->img, p->blendimg,
177 				box, LayerItem_getOpacity_real(pi), pi->blendmode);
178 		}
179 	}
180 }
181 
182 /** キャンバスを描画
183  *
184  * 合成イメージをソースとして mPixbuf に描画。
185  *
186  * @param pixbuf 描画対象のキャンバスエリアの mPixbuf
187  * @param box    NULL で全体 */
188 
drawUpdate_drawCanvas(DrawData * p,mPixbuf * pixbuf,mBox * box)189 void drawUpdate_drawCanvas(DrawData *p,mPixbuf *pixbuf,mBox *box)
190 {
191 	CanvasDrawInfo di;
192 	mBox boximg;
193 	mRect rc;
194 	int n;
195 
196 	//描画情報
197 
198 	if(box)
199 		di.boxdst = *box;
200 	else
201 	{
202 		di.boxdst.x = di.boxdst.y = 0;
203 		di.boxdst.w = p->szCanvas.w;
204 		di.boxdst.h = p->szCanvas.h;
205 	}
206 
207 	di.originx = p->imgoriginX;
208 	di.originy = p->imgoriginY;
209 	di.scrollx = p->ptScroll.x - (p->szCanvas.w >> 1);
210 	di.scrolly = p->ptScroll.y - (p->szCanvas.h >> 1);
211 	di.mirror  = p->canvas_mirror;
212 	di.imgw = p->imgw;
213 	di.imgh = p->imgh;
214 	di.bkgndcol = APP_CONF->colCanvasBkgnd;
215 	di.param = &p->viewparam;
216 
217 	//------ 描画
218 
219 	if(p->canvas_angle)
220 	{
221 		//回転あり
222 
223 		n = p->canvas_angle;
224 
225 		if(p->bCanvasLowQuality
226 			|| (p->canvas_zoom == 1000 && (n == 9000 || n == 18000 || n == 27000)))
227 			//キャンバス移動中、または90 度単位 (倍率100%) の場合は低品質
228 			ImageBuf24_drawMainCanvas_rotate_normal(p->blendimg, pixbuf, &di);
229 		else
230 			ImageBuf24_drawMainCanvas_rotate_oversamp(p->blendimg, pixbuf, &di);
231 	}
232 	else
233 	{
234 		//回転なし (200%以下 [!] 100%は除く 時は高品質で)
235 
236 		if(!p->bCanvasLowQuality && p->canvas_zoom != 1000 && p->canvas_zoom < 2000)
237 			ImageBuf24_drawMainCanvas_oversamp(p->blendimg, pixbuf, &di);
238 		else
239 			ImageBuf24_drawMainCanvas_nearest(p->blendimg, pixbuf, &di);
240 	}
241 
242 	//------ グリッド
243 
244 	if((APP_CONF->fView & CONFIG_VIEW_F_GRID)
245 		&& drawCalc_areaToimage_box(p, &boximg, &di.boxdst))
246 	{
247 		GridListData *pi;
248 
249 		//リストで上にあるものほど前面にしたいので、後ろから描画
250 
251 		for(pi = (GridListData *)APP_CONF->grid_list.bottom; pi; pi = (GridListData *)pi->i.prev)
252 		{
253 			n = pi->flags;
254 
255 			if(n & GRIDDATA_F_ON)
256 			{
257 				//表示倍率条件
258 
259 				if((n & GRIDDATA_F_HAVE_ZOOM)
260 					&& (p->canvas_zoom < pi->zoom_min || p->canvas_zoom > pi->zoom_max))
261 					continue;
262 
263 				//範囲
264 
265 				if(n & GRIDDATA_F_HAVE_AREA)
266 				{
267 					rc.x1 = pi->area[0], rc.y1 = pi->area[1];
268 					rc.x2 = pi->area[2], rc.y2 = pi->area[3];
269 
270 					//始点がイメージの範囲外なら表示しない
271 
272 					if(rc.x1 >= p->imgw || rc.y1 >= p->imgh)
273 						continue;
274 
275 					//イメージの範囲内に収める
276 
277 					if(rc.x2 > p->imgw) rc.x2 = p->imgw;
278 					if(rc.y2 > p->imgh) rc.y2 = p->imgh;
279 				}
280 
281 				//描画
282 
283 				pixbufDrawGrid(pixbuf, &di.boxdst, &boximg,
284 					pi->w, pi->h, pi->col,
285 					(n & GRIDDATA_F_HAVE_AREA)? &rc: NULL, &di);
286 			}
287 		}
288 	}
289 
290 	//------ 選択範囲
291 
292 	if(p->sel.boxsel.w)
293 		pixbufDrawSelectBox(pixbuf, &p->sel.boxsel, &di);
294 }
295 
296 /** 合成イメージの範囲更新
297  *
298  * @param boximg  イメージ範囲内であること */
299 
drawUpdate_rect_blendimg(DrawData * p,mBox * boximg)300 void drawUpdate_rect_blendimg(DrawData *p,mBox *boximg)
301 {
302 	//背景
303 
304 	if(APP_CONF->fView & CONFIG_VIEW_F_BKGND_PLAID)
305 	{
306 		ImageBuf24_fillPlaid_box(p->blendimg, boximg,
307 			APP_CONF->colBkgndPlaid[0], APP_CONF->colBkgndPlaid[1]);
308 	}
309 	else
310 		ImageBuf24_fillBox(p->blendimg, boximg, 0xffffff);
311 
312 	//レイヤ
313 
314 	drawUpdate_blendImage_layer(p, boximg);
315 }
316 
317 /** キャンバスエリアの範囲更新 */
318 
drawUpdate_rect_canvas(DrawData * p,mBox * boximg)319 void drawUpdate_rect_canvas(DrawData *p,mBox *boximg)
320 {
321 	mBox boxc;
322 	mWidget *wgarea;
323 	mPixbuf *pixbuf;
324 
325 	wgarea = M_WIDGET(APP_WIDGETS->canvas_area);
326 
327 	if(drawCalc_imageToarea_box(p, &boxc, boximg))
328 	{
329 		//キャンバス描画
330 
331 		pixbuf = mWidgetBeginDirectDraw(wgarea);
332 
333 		if(pixbuf)
334 		{
335 			drawUpdate_drawCanvas(p, pixbuf, &boxc);
336 
337 			//[debug]
338 			//mPixbufBox(pixbuf, boxc.x, boxc.y, boxc.w, boxc.h, 0xff0000);
339 
340 			mWidgetEndDirectDraw(wgarea, pixbuf);
341 
342 			//ウィンドウ更新
343 
344 			mWidgetUpdateBox_box(wgarea, &boxc);
345 		}
346 	}
347 }
348 
349 
350 //===========================
351 // 範囲更新
352 //===========================
353 
354 
355 /** 範囲更新 (合成イメージ + キャンバスエリア)
356  *
357  * @param boximg イメージ範囲内であること */
358 
drawUpdate_rect_imgcanvas(DrawData * p,mBox * boximg)359 void drawUpdate_rect_imgcanvas(DrawData *p,mBox *boximg)
360 {
361 	//合成イメージ
362 
363 	drawUpdate_rect_blendimg(p, boximg);
364 
365 	//キャンバス
366 
367 	drawUpdate_rect_canvas(p, boximg);
368 }
369 
370 /** 範囲更新、選択範囲用
371  *
372  * 選択範囲がイメージの範囲外でも表示されるように。
373  *
374  * @param rc  NULL で現在の選択範囲 */
375 
drawUpdate_rect_imgcanvas_forSelect(DrawData * p,mRect * rc)376 void drawUpdate_rect_imgcanvas_forSelect(DrawData *p,mRect *rc)
377 {
378 	mBox box;
379 	mRect rc2;
380 
381 	if(rc)
382 		rc2 = *rc;
383 	else
384 		mRectSetByBox(&rc2, &p->sel.boxsel);
385 
386 	//合成イメージ
387 
388 	if(drawCalc_getImageBox_rect(p, &box, &rc2))
389 		drawUpdate_rect_blendimg(p, &box);
390 
391 	//キャンバス
392 
393 	mBoxSetByRect(&box, &rc2);
394 
395 	box.x -= 2;
396 	box.y -= 2;
397 	box.w += 4;
398 	box.h += 4;
399 
400 	drawUpdate_rect_canvas(p, &box);
401 }
402 
403 /** 選択範囲のキャンバス領域を更新
404  *
405  * @param box NULL で現在の選択範囲 */
406 
drawUpdate_rect_canvas_select(DrawData * p,mBox * box)407 void drawUpdate_rect_canvas_select(DrawData *p,mBox *box)
408 {
409 	mBox boxu;
410 
411 	if(box)
412 		boxu = *box;
413 	else
414 		boxu = p->sel.boxsel;
415 
416 	//1px 拡張して表示しているので、更新範囲を拡張
417 
418 	boxu.x -= 2;
419 	boxu.y -= 2;
420 	boxu.w += 4;
421 	boxu.h += 4;
422 
423 	drawUpdate_rect_canvas(p, &boxu);
424 }
425 
426 /** 範囲更新 (mRect)
427  *
428  * @param rc  イメージ範囲 */
429 
drawUpdate_rect_imgcanvas_fromRect(DrawData * p,mRect * rc)430 void drawUpdate_rect_imgcanvas_fromRect(DrawData *p,mRect *rc)
431 {
432 	mBox box;
433 
434 	if(drawCalc_getImageBox_rect(p, &box, rc))
435 		drawUpdate_rect_imgcanvas(p, &box);
436 }
437 
438 /** 範囲更新 + [dock]キャンバスビュー */
439 
drawUpdate_rect_imgcanvas_canvasview_fromRect(DrawData * p,mRect * rc)440 void drawUpdate_rect_imgcanvas_canvasview_fromRect(DrawData *p,mRect *rc)
441 {
442 	mBox box;
443 
444 	if(drawCalc_getImageBox_rect(p, &box, rc))
445 	{
446 		drawUpdate_rect_imgcanvas(p, &box);
447 
448 		DockCanvasView_updateRect(&box);
449 	}
450 }
451 
452 /** 範囲更新 + [dock]キャンバスビュー (レイヤの表示イメージ部分)
453  *
454  * フォルダの場合、フォルダ下の全ての表示レイヤの範囲。
455  *
456  * @param item  NULL でカレントレイヤ */
457 
drawUpdate_rect_imgcanvas_canvasview_inLayerHave(DrawData * p,LayerItem * item)458 void drawUpdate_rect_imgcanvas_canvasview_inLayerHave(DrawData *p,LayerItem *item)
459 {
460 	mRect rc;
461 
462 	if(!item) item = p->curlayer;
463 
464 	if(LayerItem_getVisibleImageRect(item, &rc))
465 		drawUpdate_rect_imgcanvas_canvasview_fromRect(p, &rc);
466 }
467 
468 /** [dock]キャンバスビューのみ更新 (mRect) */
469 
drawUpdate_canvasview(DrawData * p,mRect * rc)470 void drawUpdate_canvasview(DrawData *p,mRect *rc)
471 {
472 	mBox box;
473 
474 	if(drawCalc_getImageBox_rect(p, &box, rc))
475 		DockCanvasView_updateRect(&box);
476 }
477 
478 /** [dock]キャンバスビューがルーペ時、更新
479  *
480  * ドットペンの押し時など、カーソルが移動されていない状態でイメージが更新されたときに使う。 */
481 
drawUpdate_canvasview_inLoupe()482 void drawUpdate_canvasview_inLoupe()
483 {
484 	if(APP_CONF->canvasview_flags & CONFIG_CANVASVIEW_F_LOUPE_MODE)
485 		DockCanvasView_update();
486 }
487 
488 /** 描画終了時の範囲更新
489  *
490  * @param boximg イメージ範囲。x < 0 で範囲なし */
491 
drawUpdate_endDraw_box(DrawData * p,mBox * boximg)492 void drawUpdate_endDraw_box(DrawData *p,mBox *boximg)
493 {
494 	//[Dock]キャンバスビュー
495 
496 	if(boximg->x >= 0)
497 		DockCanvasView_updateRect(boximg);
498 }
499