Blender V4.3
wm_draw.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2007 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
11#include <cstdlib>
12#include <cstring>
13
14#include "DNA_camera_types.h"
15#include "DNA_listBase.h"
16#include "DNA_object_types.h"
17#include "DNA_screen_types.h"
18#include "DNA_userdef_types.h"
19#include "DNA_view3d_types.h"
21
22#include "MEM_guardedalloc.h"
23
24#include "BLI_math_matrix.h"
26#include "BLI_utildefines.h"
27
28#include "BKE_context.hh"
29#include "BKE_image.hh"
30#include "BKE_scene.hh"
31#include "BKE_screen.hh"
32
33#include "GHOST_C-api.h"
34
35#include "ED_node.hh"
36#include "ED_screen.hh"
37#include "ED_view3d.hh"
38
39#include "GPU_batch_presets.hh"
40#include "GPU_capabilities.hh"
41#include "GPU_context.hh"
42#include "GPU_debug.hh"
43#include "GPU_framebuffer.hh"
44#include "GPU_immediate.hh"
45#include "GPU_matrix.hh"
46#include "GPU_state.hh"
47#include "GPU_texture.hh"
48#include "GPU_viewport.hh"
49
50#include "RE_engine.h"
51
52#include "WM_api.hh"
53#include "WM_toolsystem.hh"
54#include "WM_types.hh"
55#include "wm.hh"
56#include "wm_draw.hh"
57#include "wm_event_system.hh"
58#include "wm_surface.hh"
59#include "wm_window.hh"
60
61#include "UI_resources.hh"
62
63#ifdef WITH_OPENSUBDIV
64# include "BKE_subsurf.hh"
65#endif
66
67/* -------------------------------------------------------------------- */
75{
77 GHOST_TGrabCursorMode mode_dummy;
78 GHOST_TAxisFlag wrap_axis_dummy;
79 int bounds[4] = {0};
80 bool use_software_cursor_dummy = false;
81 GHOST_GetCursorGrabState(static_cast<GHOST_WindowHandle>(win->ghostwin),
82 &mode_dummy,
83 &wrap_axis_dummy,
84 bounds,
85 &use_software_cursor_dummy);
86 if ((bounds[0] != bounds[2]) || (bounds[1] != bounds[3])) {
87 return true;
88 }
89 }
90 return false;
91}
92
95/* -------------------------------------------------------------------- */
99static void wm_paintcursor_draw(bContext *C, ScrArea *area, ARegion *region)
100{
102 wmWindow *win = CTX_wm_window(C);
104
105 /* Don't draw paint cursors with locked interface. Painting is not possible
106 * then, and cursor drawing can use scene data that another thread may be
107 * modifying. */
108 if (wm->runtime->is_interface_locked) {
109 return;
110 }
111
112 if (!region->visible || region != screen->active_region) {
113 return;
114 }
115
117 if ((pc->space_type != SPACE_TYPE_ANY) && (area->spacetype != pc->space_type)) {
118 continue;
119 }
120
121 if (!ELEM(pc->region_type, RGN_TYPE_ANY, region->regiontype)) {
122 continue;
123 }
124
125 if (pc->poll == nullptr || pc->poll(C)) {
126 UI_SetTheme(area->spacetype, region->regiontype);
127
128 /* Prevent drawing outside region. */
129 GPU_scissor_test(true);
130 GPU_scissor(region->winrct.xmin,
131 region->winrct.ymin,
132 BLI_rcti_size_x(&region->winrct) + 1,
133 BLI_rcti_size_y(&region->winrct) + 1);
134 /* Reading the cursor location from the operating-system while the cursor is grabbed
135 * conflicts with grabbing logic that hides the cursor, then keeps it centered to accumulate
136 * deltas without it escaping from the window. In this case we never want to show the actual
137 * cursor coordinates so limit reading the cursor location to when the cursor is grabbed and
138 * wrapping in a region since this is the case when it would otherwise attempt to draw the
139 * cursor outside the view/window. See: #102792. */
140 const int *xy = win->eventstate->xy;
141 int xy_buf[2];
144 wm_cursor_position_get(win, &xy_buf[0], &xy_buf[1]))
145 {
146 xy = xy_buf;
147 }
148
149 pc->draw(C, xy[0], xy[1], pc->customdata);
150 GPU_scissor_test(false);
151 }
152 }
153}
154
157/* -------------------------------------------------------------------- */
167static struct {
169 int winid;
170 int xy[2];
172 /*enabled*/ -1,
173 /*winid*/ -1,
175
182
184{
185 if (UNLIKELY(g_software_cursor.enabled == -1)) {
187 }
188 return g_software_cursor.enabled;
189}
190
191static bool wm_software_cursor_needed_for_window(const wmWindow *win, GrabState *grab_state)
192{
194 if (GHOST_GetCursorVisibility(static_cast<GHOST_WindowHandle>(win->ghostwin))) {
195 /* NOTE: The value in `win->grabcursor` can't be used as it
196 * doesn't always match GHOST's value in the case of tablet events. */
197 bool use_software_cursor;
198 GHOST_GetCursorGrabState(static_cast<GHOST_WindowHandle>(win->ghostwin),
199 &grab_state->mode,
200 &grab_state->wrap_axis,
201 grab_state->bounds,
202 &use_software_cursor);
203 if (use_software_cursor) {
204 return true;
205 }
206 }
207 return false;
208}
209
211{
212 return (g_software_cursor.winid != win->winid) ||
213 (g_software_cursor.xy[0] != win->eventstate->xy[0]) ||
214 (g_software_cursor.xy[1] != win->eventstate->xy[1]);
215}
216
218{
219
220 g_software_cursor.winid = win->winid;
221 g_software_cursor.xy[0] = win->eventstate->xy[0];
222 g_software_cursor.xy[1] = win->eventstate->xy[1];
223}
224
226{
227 g_software_cursor.winid = -1;
228 g_software_cursor.xy[0] = -1;
229 g_software_cursor.xy[1] = -1;
230}
231
233{
234 if (g_software_cursor.winid == win->winid) {
236 }
237}
238
239static void wm_software_cursor_draw_bitmap(const int event_xy[2],
240 const GHOST_CursorBitmapRef *bitmap)
241{
243
244 float gl_matrix[4][4];
246 GPUTexture *texture = GPU_texture_create_2d(
247 "softeare_cursor", bitmap->data_size[0], bitmap->data_size[1], 1, GPU_RGBA8, usage, nullptr);
248 GPU_texture_update(texture, GPU_DATA_UBYTE, bitmap->data);
249 GPU_texture_filter_mode(texture, false);
250
252
253 const int scale = int(U.pixelsize);
254
255 unit_m4(gl_matrix);
256
257 gl_matrix[3][0] = event_xy[0] - (bitmap->hot_spot[0] * scale);
258 gl_matrix[3][1] = event_xy[1] - ((bitmap->data_size[1] - bitmap->hot_spot[1]) * scale);
259
260 gl_matrix[0][0] = bitmap->data_size[0] * scale;
261 gl_matrix[1][1] = bitmap->data_size[1] * scale;
262
263 GPU_matrix_mul(gl_matrix);
264
265 GPUVertFormat *imm_format = immVertexFormat();
267 uint texCoord = GPU_vertformat_attr_add(
268 imm_format, "texCoord", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
269
270 /* Use 3D image for correct display of planar tracked images. */
272
273 immBindTexture("image", texture);
274
276
277 immAttr2f(texCoord, 0.0f, 1.0f);
278 immVertex3f(pos, 0.0f, 0.0f, 0.0f);
279
280 immAttr2f(texCoord, 1.0f, 1.0f);
281 immVertex3f(pos, 1.0f, 0.0f, 0.0f);
282
283 immAttr2f(texCoord, 1.0f, 0.0f);
284 immVertex3f(pos, 1.0f, 1.0f, 0.0f);
285
286 immAttr2f(texCoord, 0.0f, 0.0f);
287 immVertex3f(pos, 0.0f, 1.0f, 0.0f);
288
289 immEnd();
290
292
294 GPU_texture_unbind(texture);
295 GPU_texture_free(texture);
296
298}
299
300static void wm_software_cursor_draw_crosshair(const int event_xy[2])
301{
302 /* Draw a primitive cross-hair cursor.
303 * NOTE: the `win->cursor` could be used for drawing although it's complicated as some cursors
304 * are set by the operating-system, where the pixel information isn't easily available. */
305 const float unit = max_ff(UI_SCALE_FAC, 1.0f);
309
310 immUniformColor4f(1, 1, 1, 1);
311 {
312 const int ofs_line = (8 * unit);
313 const int ofs_size = (2 * unit);
315 event_xy[0] - ofs_line,
316 event_xy[1] - ofs_size,
317 event_xy[0] + ofs_line,
318 event_xy[1] + ofs_size);
320 event_xy[0] - ofs_size,
321 event_xy[1] - ofs_line,
322 event_xy[0] + ofs_size,
323 event_xy[1] + ofs_line);
324 }
325 immUniformColor4f(0, 0, 0, 1);
326 {
327 const int ofs_line = (7 * unit);
328 const int ofs_size = (1 * unit);
330 event_xy[0] - ofs_line,
331 event_xy[1] - ofs_size,
332 event_xy[0] + ofs_line,
333 event_xy[1] + ofs_size);
335 event_xy[0] - ofs_size,
336 event_xy[1] - ofs_line,
337 event_xy[0] + ofs_size,
338 event_xy[1] + ofs_line);
339 }
341}
342
343static void wm_software_cursor_draw(wmWindow *win, const GrabState *grab_state)
344{
345 int event_xy[2] = {UNPACK2(win->eventstate->xy)};
346
347 if (grab_state->wrap_axis & GHOST_kAxisX) {
348 const int min = grab_state->bounds[0];
349 const int max = grab_state->bounds[2];
350 if (min != max) {
351 event_xy[0] = mod_i(event_xy[0] - min, max - min) + min;
352 }
353 }
354 if (grab_state->wrap_axis & GHOST_kAxisY) {
355 const int height = WM_window_native_pixel_y(win);
356 const int min = height - grab_state->bounds[1];
357 const int max = height - grab_state->bounds[3];
358 if (min != max) {
359 event_xy[1] = mod_i(event_xy[1] - max, min - max) + max;
360 }
361 }
362
363 GHOST_CursorBitmapRef bitmap = {nullptr};
364 if (GHOST_GetCursorBitmap(static_cast<GHOST_WindowHandle>(win->ghostwin), &bitmap) ==
366 {
367 wm_software_cursor_draw_bitmap(event_xy, &bitmap);
368 }
369 else {
371 }
372}
373
376/* -------------------------------------------------------------------- */
380static void wm_region_draw_overlay(bContext *C, const ScrArea *area, ARegion *region)
381{
382 const wmWindow *win = CTX_wm_window(C);
383
384 wmViewport(&region->winrct);
385 UI_SetTheme(area->spacetype, region->regiontype);
386 region->type->draw_overlay(C, region);
387 wmWindowViewport(win);
388}
389
392/* -------------------------------------------------------------------- */
397 ScrArea *area,
398 ARegion *region,
399 eStereoViews sview)
400{
401 /* We could detect better when stereo is actually needed, by inspecting the
402 * image in the image editor and sequencer. */
403 if (!ELEM(region->regiontype, RGN_TYPE_WINDOW, RGN_TYPE_PREVIEW)) {
404 return false;
405 }
406
407 switch (area->spacetype) {
408 case SPACE_IMAGE: {
409 if (region->regiontype == RGN_TYPE_WINDOW) {
410 SpaceImage *sima = static_cast<SpaceImage *>(area->spacedata.first);
411 sima->iuser.multiview_eye = sview;
412 return true;
413 }
414 break;
415 }
416 case SPACE_VIEW3D: {
417 if (region->regiontype == RGN_TYPE_WINDOW) {
418 View3D *v3d = static_cast<View3D *>(area->spacedata.first);
419 if (v3d->camera && v3d->camera->type == OB_CAMERA) {
420 RegionView3D *rv3d = static_cast<RegionView3D *>(region->regiondata);
421 RenderEngine *engine = rv3d->view_render ? RE_view_engine_get(rv3d->view_render) :
422 nullptr;
423 if (engine && !(engine->type->flag & RE_USE_STEREO_VIEWPORT)) {
424 return false;
425 }
426
427 Camera *cam = static_cast<Camera *>(v3d->camera->data);
428 CameraBGImage *bgpic = static_cast<CameraBGImage *>(cam->bg_images.first);
429 v3d->multiview_eye = sview;
430 if (bgpic) {
431 bgpic->iuser.multiview_eye = sview;
432 }
433 return true;
434 }
435 }
436 break;
437 }
438 case SPACE_NODE: {
439 if (region->regiontype == RGN_TYPE_WINDOW) {
440 SpaceNode *snode = static_cast<SpaceNode *>(area->spacedata.first);
441 if ((snode->flag & SNODE_BACKDRAW) && ED_node_is_compositor(snode)) {
442 Image *ima = BKE_image_ensure_viewer(bmain, IMA_TYPE_COMPOSITE, "Viewer Node");
443 ima->eye = sview;
444 return true;
445 }
446 }
447 break;
448 }
449 case SPACE_SEQ: {
450 SpaceSeq *sseq = static_cast<SpaceSeq *>(area->spacedata.first);
451 sseq->multiview_eye = sview;
452
453 if (region->regiontype == RGN_TYPE_PREVIEW) {
454 return true;
455 }
456 if (region->regiontype == RGN_TYPE_WINDOW) {
457 return (sseq->draw_flag & SEQ_DRAW_BACKDROP) != 0;
458 }
459 }
460 }
461
462 return false;
463}
464
466 ScrArea *area,
467 ARegion *region,
468 bool tag_redraw)
469{
470 if (region->gizmo_map == nullptr) {
471 return;
472 }
473
474 wmGizmoMap *gzmap = region->gizmo_map;
476 if (tag_redraw && (gzgroup->type->flag & WM_GIZMOGROUPTYPE_VR_REDRAWS)) {
477 ScrArea *ctx_area = CTX_wm_area(C);
478 ARegion *ctx_region = CTX_wm_region(C);
479
480 CTX_wm_area_set(C, area);
481 CTX_wm_region_set(C, region);
482
483 if (WM_gizmo_group_type_poll(C, gzgroup->type)) {
485 }
486
487 /* Reset. */
488 CTX_wm_area_set(C, ctx_area);
489 CTX_wm_region_set(C, ctx_region);
490 }
491
492 LISTBASE_FOREACH (wmGizmo *, gz, &gzgroup->gizmos) {
493 if (gz->do_draw) {
494 if (tag_redraw) {
496 }
497 gz->do_draw = false;
498 }
499 }
500 }
501}
502
503static void wm_region_test_render_do_draw(const Scene *scene,
504 Depsgraph *depsgraph,
505 ScrArea *area,
506 ARegion *region)
507{
508 /* Tag region for redraw from render engine preview running inside of it. */
509 if (area->spacetype == SPACE_VIEW3D && region->regiontype == RGN_TYPE_WINDOW) {
510 RegionView3D *rv3d = static_cast<RegionView3D *>(region->regiondata);
511 RenderEngine *engine = rv3d->view_render ? RE_view_engine_get(rv3d->view_render) : nullptr;
512 GPUViewport *viewport = WM_draw_region_get_viewport(region);
513
514 if (engine && (engine->flag & RE_ENGINE_DO_DRAW)) {
515 View3D *v3d = static_cast<View3D *>(area->spacedata.first);
516 rcti border_rect;
517
518 /* Do partial redraw when possible. */
519 if (ED_view3d_calc_render_border(scene, depsgraph, v3d, region, &border_rect)) {
520 ED_region_tag_redraw_partial(region, &border_rect, false);
521 }
522 else {
524 }
525
526 engine->flag &= ~RE_ENGINE_DO_DRAW;
527 }
528 else if (viewport && GPU_viewport_do_update(viewport)) {
530 }
531 }
532}
533
534#ifdef WITH_XR_OPENXR
535static void wm_region_test_xr_do_draw(const wmWindowManager *wm,
536 const ScrArea *area,
537 ARegion *region)
538{
539 if ((area->spacetype == SPACE_VIEW3D) && (region->regiontype == RGN_TYPE_WINDOW)) {
540 if (ED_view3d_is_region_xr_mirror_active(
541 wm, static_cast<const View3D *>(area->spacedata.first), region))
542 {
544 }
545 }
546}
547#endif
548
549static bool wm_region_use_viewport_by_type(short space_type, short region_type)
550{
551 return (ELEM(space_type, SPACE_VIEW3D, SPACE_IMAGE, SPACE_NODE) &&
552 region_type == RGN_TYPE_WINDOW) ||
553 ((space_type == SPACE_SEQ) && ELEM(region_type, RGN_TYPE_PREVIEW, RGN_TYPE_WINDOW));
554}
555
557{
558 return wm_region_use_viewport_by_type(area->spacetype, region->regiontype);
559}
560
561static const char *wm_area_name(ScrArea *area)
562{
563#define SPACE_NAME(space) \
564 case space: \
565 return #space;
566
567 switch (area->spacetype) {
587 default:
588 return "Unknown Space";
589 }
590}
591
594/* -------------------------------------------------------------------- */
602
603 void (*draw)(const wmWindow *win, void *customdata);
605};
606
608 void (*draw)(const wmWindow *win, void *customdata),
609 void *customdata)
610{
611 WindowDrawCB *wdc = static_cast<WindowDrawCB *>(MEM_callocN(sizeof(*wdc), "WindowDrawCB"));
612
613 BLI_addtail(&win->drawcalls, wdc);
614 wdc->draw = draw;
615 wdc->customdata = customdata;
616
617 return wdc;
618}
619
620void WM_draw_cb_exit(wmWindow *win, void *handle)
621{
622 LISTBASE_FOREACH (WindowDrawCB *, wdc, &win->drawcalls) {
623 if (wdc == (WindowDrawCB *)handle) {
624 BLI_remlink(&win->drawcalls, wdc);
625 MEM_freeN(wdc);
626 return;
627 }
628 }
629}
630
632{
633 LISTBASE_FOREACH (WindowDrawCB *, wdc, &win->drawcalls) {
634 wdc->draw(win, wdc->customdata);
635 }
636}
637
640/* -------------------------------------------------------------------- */
650{
651 if (region->draw_buffer) {
652 if (region->draw_buffer->viewport) {
653 GPU_viewport_free(region->draw_buffer->viewport);
654 }
655 if (region->draw_buffer->offscreen) {
656 GPU_offscreen_free(region->draw_buffer->offscreen);
657 }
658
659 MEM_freeN(region->draw_buffer);
660 region->draw_buffer = nullptr;
661 }
662}
663
665{
666 /* Setup offscreen color texture for drawing. */
667 GPUTexture *texture = GPU_offscreen_color_texture(offscreen);
668
669 /* No mipmaps or filtering. */
670 GPU_texture_mipmap_mode(texture, false, false);
671}
672
674{
675 bool use_hdr = false;
676 if (scene && ((scene->view_settings.flag & COLORMANAGE_VIEW_USE_HDR) != 0)) {
677 use_hdr = GPU_hdr_support();
678 }
679 eGPUTextureFormat desired_format = (use_hdr) ? GPU_RGBA16F : GPU_RGBA8;
680 return desired_format;
681}
682
684 ARegion *region,
685 bool stereo,
686 bool use_viewport)
687{
688
689 /* Determine desired offscreen format depending on HDR availability. */
690 eGPUTextureFormat desired_format = get_hdr_framebuffer_format(scene);
691
692 if (region->draw_buffer) {
693 if (region->draw_buffer->stereo != stereo) {
694 /* Free draw buffer on stereo changes. */
696 }
697 else {
698 /* Free offscreen buffer on size changes. Viewport auto resizes. */
699 GPUOffScreen *offscreen = region->draw_buffer->offscreen;
700 if (offscreen && (GPU_offscreen_width(offscreen) != region->winx ||
701 GPU_offscreen_height(offscreen) != region->winy ||
702 GPU_offscreen_format(offscreen) != desired_format))
703 {
705 }
706 }
707 }
708
709 if (!region->draw_buffer) {
710 if (use_viewport) {
711 /* Allocate viewport which includes an off-screen buffer with depth multi-sample, etc. */
712 region->draw_buffer = static_cast<wmDrawBuffer *>(
713 MEM_callocN(sizeof(wmDrawBuffer), "wmDrawBuffer"));
714 region->draw_buffer->viewport = stereo ? GPU_viewport_stereo_create() :
716 }
717 else {
718 /* Allocate off-screen buffer if it does not exist. This one has no
719 * depth or multi-sample buffers. 3D view creates its own buffers with
720 * the data it needs. */
721 GPUOffScreen *offscreen = GPU_offscreen_create(region->winx,
722 region->winy,
723 false,
724 desired_format,
726 nullptr);
727 if (!offscreen) {
728 WM_report(RPT_ERROR, "Region could not be drawn!");
729 return;
730 }
731
733
734 region->draw_buffer = static_cast<wmDrawBuffer *>(
735 MEM_callocN(sizeof(wmDrawBuffer), "wmDrawBuffer"));
736 region->draw_buffer->offscreen = offscreen;
737 }
738
739 region->draw_buffer->bound_view = -1;
740 region->draw_buffer->stereo = stereo;
741 }
742}
743
744static void wm_draw_region_bind(ARegion *region, int view)
745{
746 if (!region->draw_buffer) {
747 return;
748 }
749
750 if (region->draw_buffer->viewport) {
751 GPU_viewport_bind(region->draw_buffer->viewport, view, &region->winrct);
752 }
753 else {
754 GPU_offscreen_bind(region->draw_buffer->offscreen, false);
755
756 /* For now scissor is expected by region drawing, we could disable it
757 * and do the enable/disable in the specific cases that setup scissor. */
758 GPU_scissor_test(true);
759 GPU_scissor(0, 0, region->winx, region->winy);
760 }
761
762 region->draw_buffer->bound_view = view;
763}
764
765static void wm_draw_region_unbind(ARegion *region)
766{
767 if (!region->draw_buffer) {
768 return;
769 }
770
771 region->draw_buffer->bound_view = -1;
772
773 if (region->draw_buffer->viewport) {
774 GPU_viewport_unbind(region->draw_buffer->viewport);
775 }
776 else {
777 GPU_scissor_test(false);
778 GPU_offscreen_unbind(region->draw_buffer->offscreen, false);
779 }
780}
781
782static void wm_draw_region_blit(ARegion *region, int view)
783{
784 if (!region->draw_buffer) {
785 return;
786 }
787
788 if (view == -1) {
789 /* Non-stereo drawing. */
790 view = 0;
791 }
792 else if (view > 0) {
793 if (region->draw_buffer->viewport == nullptr) {
794 /* Region does not need stereo or failed to allocate stereo buffers. */
795 view = 0;
796 }
797 }
798
799 if (region->draw_buffer->viewport) {
800 GPU_viewport_draw_to_screen(region->draw_buffer->viewport, view, &region->winrct);
801 }
802 else {
804 region->draw_buffer->offscreen, region->winrct.xmin, region->winrct.ymin);
805 }
806}
807
808GPUTexture *wm_draw_region_texture(ARegion *region, int view)
809{
810 if (!region->draw_buffer) {
811 return nullptr;
812 }
813
814 GPUViewport *viewport = region->draw_buffer->viewport;
815 if (viewport) {
816 return GPU_viewport_color_texture(viewport, view);
817 }
818 return GPU_offscreen_color_texture(region->draw_buffer->offscreen);
819}
820
821void wm_draw_region_blend(ARegion *region, int view, bool blend)
822{
823 if (!region->draw_buffer) {
824 return;
825 }
826
827 /* Alpha is always 1, except when blend timer is running. */
828 float alpha = ED_region_blend_alpha(region);
829 if (alpha <= 0.0f) {
830 return;
831 }
832
833 if (!blend) {
834 alpha = 1.0f;
835 }
836
837 /* #wmOrtho for the screen has this same offset. */
838 const float halfx = GLA_PIXEL_OFS / (BLI_rcti_size_x(&region->winrct) + 1);
839 const float halfy = GLA_PIXEL_OFS / (BLI_rcti_size_y(&region->winrct) + 1);
840
841 rcti rect_geo = region->winrct;
842 rect_geo.xmax += 1;
843 rect_geo.ymax += 1;
844
845 rctf rect_tex;
846 rect_tex.xmin = halfx;
847 rect_tex.ymin = halfy;
848 rect_tex.xmax = 1.0f + halfx;
849 rect_tex.ymax = 1.0f + halfy;
850
851 float alpha_easing = 1.0f - alpha;
852 alpha_easing = 1.0f - alpha_easing * alpha_easing;
853
854 /* Slide vertical panels. */
855 float ofs_x = BLI_rcti_size_x(&region->winrct) * (1.0f - alpha_easing);
856 if (RGN_ALIGN_ENUM_FROM_MASK(region->alignment) == RGN_ALIGN_RIGHT) {
857 rect_geo.xmin += ofs_x;
858 rect_tex.xmax *= alpha_easing;
859 alpha = 1.0f;
860 }
861 else if (RGN_ALIGN_ENUM_FROM_MASK(region->alignment) == RGN_ALIGN_LEFT) {
862 rect_geo.xmax -= ofs_x;
863 rect_tex.xmin += 1.0f - alpha_easing;
864 alpha = 1.0f;
865 }
866
867 /* Not the same layout as #rctf/#rcti. */
868 const float rectt[4] = {rect_tex.xmin, rect_tex.ymin, rect_tex.xmax, rect_tex.ymax};
869 const float rectg[4] = {
870 float(rect_geo.xmin), float(rect_geo.ymin), float(rect_geo.xmax), float(rect_geo.ymax)};
871
872 if (blend) {
873 /* Regions drawn off-screen have pre-multiplied alpha. */
875 }
876
877 /* Setup actual texture. */
878 GPUTexture *texture = wm_draw_region_texture(region, view);
879
881 GPU_shader_bind(shader);
882
883 int color_loc = GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_COLOR);
884 int rect_tex_loc = GPU_shader_get_uniform(shader, "rect_icon");
885 int rect_geo_loc = GPU_shader_get_uniform(shader, "rect_geom");
886 int texture_bind_loc = GPU_shader_get_sampler_binding(shader, "image");
887
888 GPU_texture_bind(texture, texture_bind_loc);
889
890 GPU_shader_uniform_float_ex(shader, rect_tex_loc, 4, 1, rectt);
891 GPU_shader_uniform_float_ex(shader, rect_geo_loc, 4, 1, rectg);
892 GPU_shader_uniform_float_ex(shader, color_loc, 4, 1, blender::float4{1, 1, 1, 1});
893
894 blender::gpu::Batch *quad = GPU_batch_preset_quad();
895 GPU_batch_set_shader(quad, shader);
897
898 GPU_texture_unbind(texture);
899
900 if (blend) {
902 }
903}
904
906{
907 if (!region->draw_buffer) {
908 return nullptr;
909 }
910
911 GPUViewport *viewport = region->draw_buffer->viewport;
912 return viewport;
913}
914
916{
917 if (!region->draw_buffer || region->draw_buffer->bound_view == -1) {
918 return nullptr;
919 }
920
921 GPUViewport *viewport = region->draw_buffer->viewport;
922 return viewport;
923}
924
925static void wm_draw_window_offscreen(bContext *C, wmWindow *win, bool stereo)
926{
927 Main *bmain = CTX_data_main(C);
930
931 /* Draw screen areas into their own frame buffer. */
932 ED_screen_areas_iter (win, screen, area) {
933 CTX_wm_area_set(C, area);
935
936 /* Compute UI layouts for dynamically size regions. */
937 LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
938 if (region->flag & RGN_FLAG_POLL_FAILED) {
939 continue;
940 }
941 /* Dynamic region may have been flagged as too small because their size on init is 0.
942 * ARegion.visible is false then, as expected. The layout should still be created then, so
943 * the region size can be updated (it may turn out to be not too small then). */
944 const bool ignore_visibility = (region->flag & RGN_FLAG_DYNAMIC_SIZE) &&
945 (region->flag & RGN_FLAG_TOO_SMALL) &&
946 !(region->flag & RGN_FLAG_HIDDEN);
947
948 if ((region->visible || ignore_visibility) && region->do_draw && region->type &&
949 region->type->layout)
950 {
951 CTX_wm_region_set(C, region);
952 ED_region_do_layout(C, region);
953 CTX_wm_region_set(C, nullptr);
954 }
955 }
956
957 ED_area_update_region_sizes(wm, win, area);
958
959 if (area->flag & AREA_FLAG_ACTIVE_TOOL_UPDATE) {
960 if ((1 << area->spacetype) & WM_TOOLSYSTEM_SPACE_MASK) {
963 }
964 area->flag &= ~AREA_FLAG_ACTIVE_TOOL_UPDATE;
965 }
966
967 /* Then do actual drawing of regions. */
968 LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
969 if (!region->visible || !region->do_draw) {
970 continue;
971 }
972
973 CTX_wm_region_set(C, region);
974 bool use_viewport = WM_region_use_viewport(area, region);
975
976 GPU_debug_group_begin(use_viewport ? "Viewport" : "ARegion");
977
978 if (stereo && wm_draw_region_stereo_set(bmain, area, region, STEREO_LEFT_ID)) {
979 Scene *scene = WM_window_get_active_scene(win);
980 wm_draw_region_buffer_create(scene, region, true, use_viewport);
981
982 for (int view = 0; view < 2; view++) {
983 eStereoViews sview;
984 if (view == 0) {
985 sview = STEREO_LEFT_ID;
986 }
987 else {
988 sview = STEREO_RIGHT_ID;
989 wm_draw_region_stereo_set(bmain, area, region, sview);
990 }
991
992 wm_draw_region_bind(region, view);
993 ED_region_do_draw(C, region);
994 wm_draw_region_unbind(region);
995 }
996 if (use_viewport) {
997 GPUViewport *viewport = region->draw_buffer->viewport;
999 }
1000 }
1001 else {
1002 wm_draw_region_stereo_set(bmain, area, region, STEREO_LEFT_ID);
1003 Scene *scene = WM_window_get_active_scene(win);
1004 wm_draw_region_buffer_create(scene, region, false, use_viewport);
1005 wm_draw_region_bind(region, 0);
1006 ED_region_do_draw(C, region);
1007 wm_draw_region_unbind(region);
1008 }
1009
1011
1012 region->do_draw = 0;
1013 CTX_wm_region_set(C, nullptr);
1014 }
1015
1016 CTX_wm_area_set(C, nullptr);
1017
1019 }
1020
1021 /* Draw menus into their own frame-buffer. */
1022 LISTBASE_FOREACH (ARegion *, region, &screen->regionbase) {
1023 if (!region->visible) {
1024 continue;
1025 }
1026 CTX_wm_region_popup_set(C, region);
1027
1028 GPU_debug_group_begin("Menu");
1029
1030 if (region->type && region->type->layout) {
1031 /* UI code reads the OpenGL state, but we have to refresh
1032 * the UI layout beforehand in case the menu size changes. */
1033 wmViewport(&region->winrct);
1034 region->type->layout(C, region);
1035 }
1036
1037 Scene *scene = WM_window_get_active_scene(win);
1038 wm_draw_region_buffer_create(scene, region, false, false);
1039 wm_draw_region_bind(region, 0);
1040 GPU_clear_color(0.0f, 0.0f, 0.0f, 0.0f);
1041 ED_region_do_draw(C, region);
1042 wm_draw_region_unbind(region);
1043
1045
1046 region->do_draw = 0;
1047 CTX_wm_region_popup_set(C, nullptr);
1048 }
1049}
1050
1051static void wm_draw_window_onscreen(bContext *C, wmWindow *win, int view)
1052{
1054 bScreen *screen = WM_window_get_active_screen(win);
1055
1056 GPU_debug_group_begin("Window Redraw");
1057
1058 /* Draw into the window frame-buffer, in full window coordinates. */
1059 wmWindowViewport(win);
1060
1061/* We draw on all pixels of the windows so we don't need to clear them before.
1062 * Actually this is only a problem when resizing the window.
1063 * If it becomes a problem we should clear only when window size changes. */
1064#if 0
1065 GPU_clear_color(0, 0, 0, 0);
1066#endif
1067
1068 /* Blit non-overlapping area regions. */
1069 ED_screen_areas_iter (win, screen, area) {
1070 LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
1071 if (!region->visible) {
1072 continue;
1073 }
1074
1075 if (region->overlap == false) {
1076 /* Blit from off-screen buffer. */
1077 wm_draw_region_blit(region, view);
1078 }
1079 }
1080 }
1081
1082 /* Draw overlays and paint cursors. */
1083 ED_screen_areas_iter (win, screen, area) {
1084 LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
1085 if (!region->visible) {
1086 continue;
1087 }
1088 const bool do_paint_cursor = (wm->paintcursors.first && region == screen->active_region);
1089 const bool do_draw_overlay = (region->type && region->type->draw_overlay);
1090 if (!(do_paint_cursor || do_draw_overlay)) {
1091 continue;
1092 }
1093
1094 CTX_wm_area_set(C, area);
1095 CTX_wm_region_set(C, region);
1096 if (do_draw_overlay) {
1097 wm_region_draw_overlay(C, area, region);
1098 }
1099 if (do_paint_cursor) {
1100 wm_paintcursor_draw(C, area, region);
1101 }
1102 CTX_wm_region_set(C, nullptr);
1103 CTX_wm_area_set(C, nullptr);
1104 }
1105 }
1106 wmWindowViewport(win);
1107
1108 /* Blend in overlapping area regions. */
1109 ED_screen_areas_iter (win, screen, area) {
1110 LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
1111 if (!region->visible) {
1112 continue;
1113 }
1114 if (region->overlap) {
1115 wm_draw_region_blend(region, 0, true);
1116 }
1117 }
1118 }
1119
1120 /* After area regions so we can do area 'overlay' drawing. */
1121 UI_SetTheme(0, 0);
1123
1124 /* Needs zero offset here or it looks blurry. #128112. */
1125 wmWindowViewport_ex(win, 0.0f);
1126
1127 wm_draw_callbacks(win);
1128 wmWindowViewport(win);
1129
1130 /* Blend in floating regions (menus). */
1131 LISTBASE_FOREACH (ARegion *, region, &screen->regionbase) {
1132 if (!region->visible) {
1133 continue;
1134 }
1135 wm_draw_region_blend(region, 0, true);
1136 }
1137
1138 /* Always draw, not only when screen tagged. */
1139 if (win->gesture.first) {
1140 wm_gesture_draw(win);
1141 wmWindowViewport(win);
1142 }
1143
1144 /* Needs pixel coords in screen. */
1145 if (wm->drags.first) {
1146 wm_drags_draw(C, win);
1147 wmWindowViewport(win);
1148 }
1149
1151 GrabState grab_state;
1152 if (wm_software_cursor_needed_for_window(win, &grab_state)) {
1153 wm_software_cursor_draw(win, &grab_state);
1155 }
1156 else {
1157 /* Checking the window is needed so one window doesn't clear the cursor state of another. */
1159 }
1160 }
1161
1163}
1164
1165static void wm_draw_window(bContext *C, wmWindow *win)
1166{
1167 GPU_context_begin_frame(static_cast<GPUContext *>(win->gpuctx));
1168
1169 bScreen *screen = WM_window_get_active_screen(win);
1170 bool stereo = WM_stereo3d_enabled(win, false);
1171
1172 /* Avoid any BGL call issued before this to alter the window drawing. */
1173 GPU_bgl_end();
1174
1175 /* Draw area regions into their own frame-buffer. This way we can redraw
1176 * the areas that need it, and blit the rest from existing frame-buffers. */
1177 wm_draw_window_offscreen(C, win, stereo);
1178
1179 /* Now we draw into the window frame-buffer, in full window coordinates. */
1180 if (!stereo) {
1181 /* Regular mono drawing. */
1182 wm_draw_window_onscreen(C, win, -1);
1183 }
1185 /* For page-flip we simply draw to both back buffers. */
1187 wm_draw_window_onscreen(C, win, 1);
1188
1190 wm_draw_window_onscreen(C, win, 0);
1191 }
1193 /* For anaglyph and interlace, we draw individual regions with
1194 * stereo frame-buffers using different shaders. */
1195 wm_draw_window_onscreen(C, win, -1);
1196 }
1197 else {
1198 /* Determine desired offscreen format depending on HDR availability. */
1200
1201 /* For side-by-side and top-bottom, we need to render each view to an
1202 * an off-screen texture and then draw it. This used to happen for all
1203 * stereo methods, but it's less efficient than drawing directly. */
1204 const blender::int2 win_size = WM_window_native_pixel_size(win);
1206 win_size[0], win_size[1], false, desired_format, GPU_TEXTURE_USAGE_SHADER_READ, nullptr);
1207
1208 if (offscreen) {
1209 GPUTexture *texture = GPU_offscreen_color_texture(offscreen);
1211
1212 for (int view = 0; view < 2; view++) {
1213 /* Draw view into offscreen buffer. */
1214 GPU_offscreen_bind(offscreen, false);
1215 wm_draw_window_onscreen(C, win, view);
1216 GPU_offscreen_unbind(offscreen, false);
1217
1218 /* Draw offscreen buffer to screen. */
1219 GPU_texture_bind(texture, 0);
1220
1221 wmWindowViewport(win);
1223 wm_stereo3d_draw_sidebyside(win, view);
1224 }
1225 else {
1226 wm_stereo3d_draw_topbottom(win, view);
1227 }
1228
1229 GPU_texture_unbind(texture);
1230 }
1231
1232 GPU_offscreen_free(offscreen);
1233 }
1234 else {
1235 /* Still draw something in case of allocation failure. */
1236 wm_draw_window_onscreen(C, win, 0);
1237 }
1238 }
1239
1240 screen->do_draw = false;
1241
1242 GPU_context_end_frame(static_cast<GPUContext *>(win->gpuctx));
1243}
1244
1248static void wm_draw_surface(bContext *C, wmSurface *surface)
1249{
1251 wm_surface_make_drawable(surface);
1252
1253 GPU_context_begin_frame(surface->blender_gpu_context);
1254
1255 surface->draw(C);
1256
1257 GPU_context_end_frame(surface->blender_gpu_context);
1258
1259 /* Avoid interference with window drawable. */
1261}
1262
1265/* -------------------------------------------------------------------- */
1272 const wmWindow *win,
1273 int r_size[2])
1274{
1275 /* Don't assert as file-save uses this for a screenshot, where redrawing isn't an option
1276 * because of the side-effects of drawing a window on save.
1277 * In this case the thumbnail might not work and there are currently no better alternatives. */
1278 // BLI_assert(WM_capabilities_flag() & WM_CAPABILITY_GPU_FRONT_BUFFER_READ);
1279
1280 /* WARNING: Reading from the front-buffer immediately after drawing may fail,
1281 * for a slower but more reliable version of this function
1282 * #WM_window_pixels_read_from_offscreen should be preferred.
1283 * See it's comments for details on why it's needed, see also #98462. */
1284 bool setup_context = wm->windrawable != win;
1285
1286 if (setup_context) {
1287 GHOST_ActivateWindowDrawingContext(static_cast<GHOST_WindowHandle>(win->ghostwin));
1288 GPU_context_active_set(static_cast<GPUContext *>(win->gpuctx));
1289 }
1290
1291 const blender::int2 win_size = WM_window_native_pixel_size(win);
1292 const uint rect_len = win_size[0] * win_size[1];
1293 uint8_t *rect = static_cast<uint8_t *>(MEM_mallocN(4 * sizeof(uint8_t) * rect_len, __func__));
1294
1295 GPU_frontbuffer_read_color(0, 0, win_size[0], win_size[1], 4, GPU_DATA_UBYTE, rect);
1296
1297 if (setup_context) {
1298 if (wm->windrawable) {
1300 static_cast<GHOST_WindowHandle>(wm->windrawable->ghostwin));
1302 }
1303 }
1304
1305 /* Clear alpha, it is not set to a meaningful value in OpenGL. */
1306 uchar *cp = (uchar *)rect;
1307 uint i;
1308 for (i = 0, cp += 3; i < rect_len; i++, cp += 4) {
1309 *cp = 0xff;
1310 }
1311
1312 r_size[0] = win_size[0];
1313 r_size[1] = win_size[1];
1314 return rect;
1315}
1316
1318 const wmWindow *win,
1319 const int pos[2],
1320 float r_col[3])
1321{
1323 bool setup_context = wm->windrawable != win;
1324
1325 if (setup_context) {
1326 GHOST_ActivateWindowDrawingContext(static_cast<GHOST_WindowHandle>(win->ghostwin));
1327 GPU_context_active_set(static_cast<GPUContext *>(win->gpuctx));
1328 }
1329
1330 GPU_frontbuffer_read_color(pos[0], pos[1], 1, 1, 3, GPU_DATA_FLOAT, r_col);
1331
1332 if (setup_context) {
1333 if (wm->windrawable) {
1335 static_cast<GHOST_WindowHandle>(wm->windrawable->ghostwin));
1337 }
1338 }
1339}
1340
1342{
1343 /* NOTE(@ideasman42): There is a problem reading the windows front-buffer after redrawing
1344 * the window in some cases (typically to clear UI elements such as menus or search popup).
1345 * With EGL `eglSurfaceAttrib(..)` may support setting the `EGL_SWAP_BEHAVIOR` attribute to
1346 * `EGL_BUFFER_PRESERVED` however not all implementations support this.
1347 * Requesting the ability with `EGL_SWAP_BEHAVIOR_PRESERVED_BIT` can even cause the EGL context
1348 * not to initialize at all.
1349 * Confusingly there are some cases where this *does* work, depending on the state of the window
1350 * and prior calls to swap-buffers, however ensuring the state exactly as needed to satisfy a
1351 * particular GPU back-end is fragile, see #98462.
1352 *
1353 * So provide an alternative to #WM_window_pixels_read that avoids using the front-buffer. */
1354
1355 /* Draw into an off-screen buffer and read its contents. */
1356 const blender::int2 win_size = WM_window_native_pixel_size(win);
1357
1358 /* Determine desired offscreen format depending on HDR availability. */
1360
1362 win_size[0], win_size[1], false, desired_format, GPU_TEXTURE_USAGE_SHADER_READ, nullptr);
1363 if (UNLIKELY(!offscreen)) {
1364 return nullptr;
1365 }
1366
1367 const uint rect_len = win_size[0] * win_size[1];
1368 uint8_t *rect = static_cast<uint8_t *>(MEM_mallocN(4 * sizeof(uint8_t) * rect_len, __func__));
1369 GPU_offscreen_bind(offscreen, false);
1370 wm_draw_window_onscreen(C, win, -1);
1371 GPU_offscreen_unbind(offscreen, false);
1372 GPU_offscreen_read_color(offscreen, GPU_DATA_UBYTE, rect);
1373 GPU_offscreen_free(offscreen);
1374
1375 r_size[0] = win_size[0];
1376 r_size[1] = win_size[1];
1377 return rect;
1378}
1379
1381 wmWindow *win,
1382 const int pos[2],
1383 float r_col[3])
1384{
1385 /* A version of #WM_window_pixels_read_from_offscreen that reads a single sample. */
1386 const blender::int2 win_size = WM_window_native_pixel_size(win);
1387 zero_v3(r_col);
1388
1389 /* While this shouldn't happen, return in the case it does. */
1390 BLI_assert(uint(pos[0]) < uint(win_size[0]) && uint(pos[1]) < uint(win_size[1]));
1391 if (!(uint(pos[0]) < uint(win_size[0]) && uint(pos[1]) < uint(win_size[1]))) {
1392 return false;
1393 }
1394
1396 win_size[0], win_size[1], false, GPU_RGBA8, GPU_TEXTURE_USAGE_SHADER_READ, nullptr);
1397 if (UNLIKELY(!offscreen)) {
1398 return false;
1399 }
1400
1401 float rect_pixel[4];
1402 GPU_offscreen_bind(offscreen, false);
1403 wm_draw_window_onscreen(C, win, -1);
1404 GPU_offscreen_unbind(offscreen, false);
1405 GPU_offscreen_read_color_region(offscreen, GPU_DATA_FLOAT, pos[0], pos[1], 1, 1, rect_pixel);
1406 GPU_offscreen_free(offscreen);
1407 copy_v3_v3(r_col, rect_pixel);
1408 return true;
1409}
1410
1412{
1415 }
1416 return WM_window_pixels_read_from_offscreen(C, win, r_size);
1417}
1418
1419bool WM_window_pixels_read_sample(bContext *C, wmWindow *win, const int pos[2], float r_col[3])
1420{
1423 return true;
1424 }
1425 return WM_window_pixels_read_sample_from_offscreen(C, win, pos, r_col);
1426}
1427
1429{
1430 return GHOST_GetPixelAtCursor(r_col);
1431}
1432
1435/* -------------------------------------------------------------------- */
1439/* Quick test to prevent changing window drawable. */
1441{
1442 const wmWindowManager *wm = CTX_wm_manager(C);
1443 Scene *scene = WM_window_get_active_scene(win);
1444 ViewLayer *view_layer = WM_window_get_active_view_layer(win);
1445 Depsgraph *depsgraph = BKE_scene_ensure_depsgraph(bmain, scene, view_layer);
1446 bScreen *screen = WM_window_get_active_screen(win);
1447 bool do_draw = false;
1448
1449 LISTBASE_FOREACH (ARegion *, region, &screen->regionbase) {
1450 if (region->do_draw_paintcursor) {
1451 screen->do_draw_paintcursor = true;
1452 region->do_draw_paintcursor = false;
1453 }
1454 if (region->visible && region->do_draw) {
1455 do_draw = true;
1456 }
1457 }
1458
1459 ED_screen_areas_iter (win, screen, area) {
1460 LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
1461 wm_region_test_gizmo_do_draw(C, area, region, true);
1462 wm_region_test_render_do_draw(scene, depsgraph, area, region);
1463#ifdef WITH_XR_OPENXR
1464 wm_region_test_xr_do_draw(wm, area, region);
1465#endif
1466
1467 if (region->visible && region->do_draw) {
1468 do_draw = true;
1469 }
1470 }
1471 }
1472
1473 if (do_draw) {
1474 return true;
1475 }
1476
1477 if (screen->do_refresh) {
1478 return true;
1479 }
1480 if (screen->do_draw) {
1481 return true;
1482 }
1483 if (screen->do_draw_gesture) {
1484 return true;
1485 }
1486 if (screen->do_draw_paintcursor) {
1487 return true;
1488 }
1489 if (screen->do_draw_drag) {
1490 return true;
1491 }
1492
1494 GrabState grab_state;
1495 if (wm_software_cursor_needed_for_window(win, &grab_state)) {
1497 return true;
1498 }
1499 }
1500 else {
1501 /* Detect the edge case when the previous draw used the software cursor but this one doesn't,
1502 * it's important to redraw otherwise the software cursor will remain displayed. */
1503 if (g_software_cursor.winid == win->winid) {
1504 return true;
1505 }
1506 }
1507 }
1508
1509#ifndef WITH_XR_OPENXR
1510 UNUSED_VARS(wm);
1511#endif
1512
1513 return false;
1514}
1515
1516/* Clear drawing flags, after drawing is complete so any draw flags set during
1517 * drawing don't cause any additional redraws. */
1519{
1520 bScreen *screen = WM_window_get_active_screen(win);
1521
1522 ED_screen_areas_iter (win, screen, area) {
1523 LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
1524 wm_region_test_gizmo_do_draw(C, area, region, false);
1525 }
1526 }
1527
1528 screen->do_draw_gesture = false;
1529 screen->do_draw_paintcursor = false;
1530 screen->do_draw_drag = false;
1531}
1532
1534{
1535 if (win) {
1536 bScreen *screen = WM_window_get_active_screen(win);
1537 screen->do_draw_paintcursor = true;
1538 }
1539}
1540
1542{
1543 Main *bmain = CTX_data_main(C);
1545
1547
1550
1552
1553#ifdef WITH_METAL_BACKEND
1554 /* Reset drawable to ensure GPU context activation happens at least once per frame if only a
1555 * single context exists. This is required to ensure the default framebuffer is updated
1556 * to be the latest backbuffer. */
1558#endif
1559
1560 LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
1561#ifdef WIN32
1563 static_cast<GHOST_WindowHandle>(win->ghostwin));
1564
1566 /* Do not update minimized windows, gives issues on Intel (see #33223)
1567 * and AMD (see #50856). it seems logical to skip update for invisible window anyway. */
1568 continue;
1569 }
1570#endif
1571
1572 CTX_wm_window_set(C, win);
1573
1574 if (wm_draw_update_test_window(bmain, C, win)) {
1575 /* Sets context window+screen. */
1576 wm_window_make_drawable(wm, win);
1577
1578 /* Notifiers for screen redraw. */
1579 ED_screen_ensure_updated(C, wm, win);
1580
1581 wm_draw_window(C, win);
1583
1585 }
1586 }
1587
1588 CTX_wm_window_set(C, nullptr);
1589
1590 /* Draw non-windows (surfaces). */
1592
1595}
1596
1597void wm_draw_region_clear(wmWindow *win, ARegion * /*region*/)
1598{
1599 bScreen *screen = WM_window_get_active_screen(win);
1600 screen->do_draw = true;
1601}
1602
1604{
1606}
1607
1609{
1610 /* Function for redraw timer benchmark. */
1611 bool use_viewport = WM_region_use_viewport(area, region);
1612 wmWindow *win = CTX_wm_window(C);
1613 Scene *scene = WM_window_get_active_scene(win);
1614 wm_draw_region_buffer_create(scene, region, false, use_viewport);
1615 wm_draw_region_bind(region, 0);
1616 ED_region_do_draw(C, region);
1617 wm_draw_region_unbind(region);
1618 region->do_draw = 0;
1619}
1620
1622{
1623 wmWindow *win_prev = CTX_wm_window(C);
1624 ScrArea *area_prev = CTX_wm_area(C);
1625 ARegion *region_prev = CTX_wm_region(C);
1626
1627 wm_draw_update(C);
1628
1629 CTX_wm_window_set(C, win_prev);
1630 CTX_wm_area_set(C, area_prev);
1631 CTX_wm_region_set(C, region_prev);
1632}
1633
1636/* -------------------------------------------------------------------- */
1646void WM_draw_region_viewport_ensure(Scene *scene, ARegion *region, short space_type)
1647{
1648 bool use_viewport = wm_region_use_viewport_by_type(space_type, region->regiontype);
1649 wm_draw_region_buffer_create(scene, region, false, use_viewport);
1650}
1651
1653{
1654 wm_draw_region_bind(region, 0);
1655}
1656
1658{
1659 wm_draw_region_unbind(region);
1660}
1661
WorkSpace * CTX_wm_workspace(const bContext *C)
ScrArea * CTX_wm_area(const bContext *C)
wmWindow * CTX_wm_window(const bContext *C)
Scene * CTX_data_scene(const bContext *C)
void CTX_wm_window_set(bContext *C, wmWindow *win)
Main * CTX_data_main(const bContext *C)
void CTX_wm_area_set(bContext *C, ScrArea *area)
void CTX_wm_region_set(bContext *C, ARegion *region)
ARegion * CTX_wm_region(const bContext *C)
wmWindowManager * CTX_wm_manager(const bContext *C)
void CTX_wm_region_popup_set(bContext *C, ARegion *region_popup)
ViewLayer * CTX_data_view_layer(const bContext *C)
Image * BKE_image_ensure_viewer(Main *bmain, int type, const char *name)
void BKE_image_free_unused_gpu_textures(void)
Definition image_gpu.cc:521
Depsgraph * BKE_scene_ensure_depsgraph(Main *bmain, Scene *scene, ViewLayer *view_layer)
Definition scene.cc:3377
#define BLI_assert(a)
Definition BLI_assert.h:50
#define LISTBASE_FOREACH(type, var, list)
#define LISTBASE_FOREACH_MUTABLE(type, var, list)
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:110
void BLI_remlink(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:130
MINLINE float max_ff(float a, float b)
MINLINE int mod_i(int i, int n)
void unit_m4(float m[4][4])
Definition rct.c:1127
MINLINE void copy_v3_v3(float r[3], const float a[3])
MINLINE void zero_v3(float r[3])
BLI_INLINE int BLI_rcti_size_y(const struct rcti *rct)
Definition BLI_rect.h:193
BLI_INLINE int BLI_rcti_size_x(const struct rcti *rct)
Definition BLI_rect.h:189
unsigned char uchar
unsigned int uint
#define UNPACK2(a)
#define UNUSED_VARS(...)
#define UNLIKELY(x)
#define ELEM(...)
@ COLORMANAGE_VIEW_USE_HDR
@ IMA_TYPE_COMPOSITE
These structs are the foundation for all linked lists in the library system.
Object is a sort of wrapper for general info.
@ OB_CAMERA
@ S3D_DISPLAY_ANAGLYPH
@ S3D_DISPLAY_INTERLACE
@ S3D_DISPLAY_SIDEBYSIDE
@ S3D_DISPLAY_PAGEFLIP
eStereoViews
@ STEREO_LEFT_ID
@ STEREO_RIGHT_ID
#define RGN_ALIGN_ENUM_FROM_MASK(align)
@ AREA_FLAG_ACTIVE_TOOL_UPDATE
@ RGN_ALIGN_LEFT
@ RGN_ALIGN_RIGHT
@ RGN_TYPE_WINDOW
@ RGN_TYPE_PREVIEW
#define RGN_TYPE_ANY
@ RGN_FLAG_DYNAMIC_SIZE
@ RGN_FLAG_HIDDEN
@ RGN_FLAG_POLL_FAILED
@ RGN_FLAG_TOO_SMALL
@ SNODE_BACKDRAW
@ SPACE_TEXT
@ SPACE_CLIP
@ SPACE_ACTION
@ SPACE_CONSOLE
@ SPACE_OUTLINER
@ SPACE_STATUSBAR
@ SPACE_TOPBAR
@ SPACE_NODE
@ SPACE_USERPREF
@ SPACE_FILE
@ SPACE_PROPERTIES
@ SPACE_NLA
@ SPACE_SEQ
@ SPACE_EMPTY
@ SPACE_SCRIPT
@ SPACE_IMAGE
@ SPACE_GRAPH
@ SPACE_VIEW3D
@ SPACE_INFO
@ SEQ_DRAW_BACKDROP
#define SPACE_TYPE_ANY
#define UI_SCALE_FAC
bool ED_node_is_compositor(const SpaceNode *snode)
Definition node_edit.cc:523
float ED_region_blend_alpha(ARegion *region)
void ED_screen_ensure_updated(bContext *C, wmWindowManager *wm, wmWindow *win)
#define ED_screen_areas_iter(win, screen, area_name)
Definition ED_screen.hh:281
void ED_region_tag_redraw_no_rebuild(ARegion *region)
Definition area.cc:653
void ED_region_tag_redraw_partial(ARegion *region, const rcti *rct, bool rebuild)
Definition area.cc:681
void ED_screen_draw_edges(wmWindow *win)
void ED_region_do_layout(bContext *C, ARegion *region)
Definition area.cc:476
void ED_area_update_region_sizes(wmWindowManager *wm, wmWindow *win, ScrArea *area)
Definition area.cc:1959
void ED_region_tag_redraw_editor_overlays(ARegion *region)
Definition area.cc:669
void ED_region_do_draw(bContext *C, ARegion *region)
Definition area.cc:499
bool ED_view3d_calc_render_border(const Scene *scene, Depsgraph *depsgraph, View3D *v3d, ARegion *region, rcti *r_rect)
static AppView * view
GHOST C-API function and type declarations.
GHOST_TWindowState GHOST_GetWindowState(GHOST_WindowHandle windowhandle)
GHOST_TSuccess GHOST_GetPixelAtCursor(float r_color[3])
void GHOST_GetCursorGrabState(GHOST_WindowHandle windowhandle, GHOST_TGrabCursorMode *r_mode, GHOST_TAxisFlag *r_axis_flag, int r_bounds[4], bool *r_use_software_cursor)
GHOST_TSuccess GHOST_GetCursorBitmap(GHOST_WindowHandle windowhandle, GHOST_CursorBitmapRef *bitmap)
bool GHOST_GetCursorVisibility(GHOST_WindowHandle windowhandle)
GHOST_TSuccess GHOST_ActivateWindowDrawingContext(GHOST_WindowHandle windowhandle)
GHOST_TWindowState
@ GHOST_kWindowStateMinimized
GHOST_TAxisFlag
@ GHOST_kAxisX
@ GHOST_kAxisY
@ GHOST_kSuccess
Definition GHOST_Types.h:87
GHOST_TGrabCursorMode
@ GHOST_kGrabWrap
@ GHOST_kGrabHide
void GPU_batch_set_shader(blender::gpu::Batch *batch, GPUShader *shader)
void GPU_batch_draw(blender::gpu::Batch *batch)
blender::gpu::Batch * GPU_batch_preset_quad()
bool GPU_hdr_support()
void GPU_render_end()
void GPU_context_main_lock()
void GPU_context_begin_frame(GPUContext *ctx)
void GPU_render_begin()
void GPU_render_step()
void GPU_context_main_unlock()
void GPU_context_end_frame(GPUContext *ctx)
void GPU_context_active_set(GPUContext *)
void GPU_debug_group_end()
Definition gpu_debug.cc:33
void GPU_debug_group_begin(const char *name)
Definition gpu_debug.cc:22
void GPU_offscreen_draw_to_screen(GPUOffScreen *offscreen, int x, int y)
GPUOffScreen * GPU_offscreen_create(int width, int height, bool with_depth_buffer, eGPUTextureFormat format, eGPUTextureUsage usage, char err_out[256])
int GPU_offscreen_width(const GPUOffScreen *offscreen)
void GPU_offscreen_bind(GPUOffScreen *offscreen, bool save)
void GPU_frontbuffer_read_color(int x, int y, int width, int height, int channels, eGPUDataFormat data_format, void *r_data)
int GPU_offscreen_height(const GPUOffScreen *offscreen)
@ GPU_BACKBUFFER_LEFT
@ GPU_BACKBUFFER_RIGHT
GPUTexture * GPU_offscreen_color_texture(const GPUOffScreen *offscreen)
void GPU_clear_color(float red, float green, float blue, float alpha)
void GPU_offscreen_read_color_region(GPUOffScreen *offscreen, eGPUDataFormat data_format, int x, int y, int w, int h, void *r_data)
void GPU_offscreen_free(GPUOffScreen *offscreen)
void GPU_backbuffer_bind(eGPUBackBuffer back_buffer_type)
eGPUTextureFormat GPU_offscreen_format(const GPUOffScreen *offscreen)
void GPU_offscreen_read_color(GPUOffScreen *offscreen, eGPUDataFormat data_format, void *r_data)
void GPU_offscreen_unbind(GPUOffScreen *offscreen, bool restore)
void immEnd()
void immUnbindProgram()
void immUniformColor4f(float r, float g, float b, float a)
void immBindBuiltinProgram(eGPUBuiltinShader shader_id)
void immBindTexture(const char *name, GPUTexture *tex)
void immVertex3f(uint attr_id, float x, float y, float z)
GPUVertFormat * immVertexFormat()
void immAttr2f(uint attr_id, float x, float y)
void immBegin(GPUPrimType, uint vertex_len)
void immRecti(uint pos, int x1, int y1, int x2, int y2)
void GPU_matrix_push()
#define GPU_matrix_mul(x)
void GPU_matrix_pop()
@ GPU_PRIM_TRI_FAN
int GPU_shader_get_sampler_binding(GPUShader *shader, const char *name)
int GPU_shader_get_uniform(GPUShader *shader, const char *name)
void GPU_shader_uniform_float_ex(GPUShader *shader, int location, int length, int array_size, const float *value)
void GPU_shader_bind(GPUShader *shader)
@ GPU_UNIFORM_COLOR
int GPU_shader_get_builtin_uniform(GPUShader *shader, int builtin)
GPUShader * GPU_shader_get_builtin_shader(eGPUBuiltinShader shader)
@ GPU_SHADER_3D_UNIFORM_COLOR
@ GPU_SHADER_2D_IMAGE_RECT_COLOR
@ GPU_SHADER_3D_IMAGE
@ GPU_BLEND_NONE
Definition GPU_state.hh:85
@ GPU_BLEND_ALPHA
Definition GPU_state.hh:87
@ GPU_BLEND_ALPHA_PREMULT
Definition GPU_state.hh:88
void GPU_blend(eGPUBlend blend)
Definition gpu_state.cc:42
void GPU_scissor_test(bool enable)
Definition gpu_state.cc:183
void GPU_scissor(int x, int y, int width, int height)
Definition gpu_state.cc:188
void GPU_bgl_end()
Definition gpu_state.cc:349
void GPU_texture_bind(GPUTexture *texture, int unit)
GPUTexture * GPU_texture_create_2d(const char *name, int width, int height, int mip_len, eGPUTextureFormat format, eGPUTextureUsage usage, const float *data)
void GPU_texture_free(GPUTexture *texture)
void GPU_texture_unbind(GPUTexture *texture)
@ GPU_DATA_UBYTE
@ GPU_DATA_FLOAT
eGPUTextureUsage
@ GPU_TEXTURE_USAGE_SHADER_READ
@ GPU_TEXTURE_USAGE_GENERAL
void GPU_texture_mipmap_mode(GPUTexture *texture, bool use_mipmap, bool use_filter)
void GPU_texture_filter_mode(GPUTexture *texture, bool use_filter)
eGPUTextureFormat
void GPU_texture_update(GPUTexture *texture, eGPUDataFormat data_format, const void *data)
@ GPU_FETCH_FLOAT
@ GPU_FETCH_INT_TO_FLOAT
uint GPU_vertformat_attr_add(GPUVertFormat *, const char *name, GPUVertCompType, uint comp_len, GPUVertFetchMode)
@ GPU_COMP_F32
@ GPU_COMP_I32
void GPU_viewport_bind(GPUViewport *viewport, int view, const rcti *rect)
GPUTexture * GPU_viewport_color_texture(GPUViewport *viewport, int view)
void GPU_viewport_draw_to_screen(GPUViewport *viewport, int view, const rcti *rect)
GPUViewport * GPU_viewport_create()
GPUViewport * GPU_viewport_stereo_create()
bool GPU_viewport_do_update(GPUViewport *viewport)
void GPU_viewport_free(GPUViewport *viewport)
void GPU_viewport_stereo_composite(GPUViewport *viewport, Stereo3dFormat *stereo_format)
void GPU_viewport_unbind(GPUViewport *viewport)
#define GLA_PIXEL_OFS
Read Guarded memory(de)allocation.
@ RE_USE_STEREO_VIEWPORT
Definition RE_engine.h:53
@ RE_ENGINE_DO_DRAW
Definition RE_engine.h:65
void UI_SetTheme(int spacetype, int regionid)
@ WM_CAPABILITY_CURSOR_WARP
Definition WM_api.hh:169
@ WM_CAPABILITY_GPU_FRONT_BUFFER_READ
Definition WM_api.hh:180
@ WM_GIZMOGROUPTYPE_VR_REDRAWS
#define WM_TOOLSYSTEM_SPACE_MASK
struct GPUContext GPUContext
struct GPUShader GPUShader
static btDbvtVolume bounds(btDbvtNode **leaves, int count)
Definition btDbvt.cpp:299
unsigned int U
Definition btGjkEpa3.h:78
const Depsgraph * depsgraph
draw_view in_light_buf[] float
draw_view push_constant(Type::INT, "radiance_src") .push_constant(Type capture_info_buf storage_buf(1, Qualifier::READ, "ObjectBounds", "bounds_buf[]") .push_constant(Type draw_view int
RAYTRACE_GROUP_SIZE additional_info("eevee_shared", "eevee_gbuffer_data", "eevee_global_ubo", "eevee_sampling_data", "eevee_utility_texture", "eevee_hiz_data", "draw_view") .specialization_constant(Type RAYTRACE_GROUP_SIZE in_sh_0_tx in_sh_2_tx screen_normal_tx GPU_RGBA8
blender::gpu::Batch * quad
RenderEngine * RE_view_engine_get(const ViewRender *view_render)
void *(* MEM_mallocN)(size_t len, const char *str)
Definition mallocn.cc:44
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
void *(* MEM_callocN)(size_t len, const char *str)
Definition mallocn.cc:42
static ulong state[N]
#define min(a, b)
Definition sort.c:32
unsigned char uint8_t
Definition stdint.h:78
signed char int8_t
Definition stdint.h:75
struct ImageUser iuser
struct ListBase bg_images
const uint8_t * data
Definition GHOST_Types.h:70
GHOST_TAxisFlag wrap_axis
Definition wm_draw.cc:179
GHOST_TGrabCursorMode mode
Definition wm_draw.cc:178
int bounds[4]
Definition wm_draw.cc:180
void * first
struct ViewRender * view_render
RenderEngineType * type
Definition RE_engine.h:134
struct ImageUser iuser
char multiview_eye
struct Object * camera
void(* draw)(const wmWindow *win, void *customdata)
Definition wm_draw.cc:603
WindowDrawCB * prev
Definition wm_draw.cc:601
WindowDrawCB * next
Definition wm_draw.cc:601
void * customdata
Definition wm_draw.cc:604
float xmax
float xmin
float ymax
float ymin
int ymin
int ymax
int xmin
int xmax
GPUOffScreen * offscreen
Definition wm_draw.hh:20
GPUViewport * viewport
Definition wm_draw.hh:21
int xy[2]
Definition WM_types.hh:726
WindowManagerRuntimeHandle * runtime
struct wmWindow * windrawable
struct wmEvent * eventstate
struct Stereo3dFormat * stereo3d_format
float max
void wm_drags_draw(bContext *C, wmWindow *win)
static void wm_draw_callbacks(wmWindow *win)
Definition wm_draw.cc:631
void WM_draw_region_viewport_unbind(ARegion *region)
Definition wm_draw.cc:1657
static void wm_draw_offscreen_texture_parameters(GPUOffScreen *offscreen)
Definition wm_draw.cc:664
uint8_t * WM_window_pixels_read_from_frontbuffer(const wmWindowManager *wm, const wmWindow *win, int r_size[2])
Definition wm_draw.cc:1271
static void wm_draw_region_unbind(ARegion *region)
Definition wm_draw.cc:765
static void wm_draw_region_bind(ARegion *region, int view)
Definition wm_draw.cc:744
int8_t enabled
Definition wm_draw.cc:168
static bool wm_software_cursor_needed_for_window(const wmWindow *win, GrabState *grab_state)
Definition wm_draw.cc:191
static const char * wm_area_name(ScrArea *area)
Definition wm_draw.cc:561
uint8_t * WM_window_pixels_read(bContext *C, wmWindow *win, int r_size[2])
Definition wm_draw.cc:1411
static bool wm_region_use_viewport_by_type(short space_type, short region_type)
Definition wm_draw.cc:549
static void wm_draw_surface(bContext *C, wmSurface *surface)
Definition wm_draw.cc:1248
void WM_window_pixels_read_sample_from_frontbuffer(const wmWindowManager *wm, const wmWindow *win, const int pos[2], float r_col[3])
Definition wm_draw.cc:1317
static void wm_draw_window_offscreen(bContext *C, wmWindow *win, bool stereo)
Definition wm_draw.cc:925
void WM_draw_region_viewport_ensure(Scene *scene, ARegion *region, short space_type)
Definition wm_draw.cc:1646
void WM_redraw_windows(bContext *C)
Definition wm_draw.cc:1621
int xy[2]
Definition wm_draw.cc:170
static void wm_draw_region_buffer_free(ARegion *region)
Definition wm_draw.cc:649
static void wm_draw_region_buffer_create(Scene *scene, ARegion *region, bool stereo, bool use_viewport)
Definition wm_draw.cc:683
GPUViewport * WM_draw_region_get_viewport(ARegion *region)
Definition wm_draw.cc:905
void * WM_draw_cb_activate(wmWindow *win, void(*draw)(const wmWindow *win, void *customdata), void *customdata)
Definition wm_draw.cc:607
static void wm_paintcursor_draw(bContext *C, ScrArea *area, ARegion *region)
Definition wm_draw.cc:99
void wm_draw_region_blend(ARegion *region, int view, bool blend)
Definition wm_draw.cc:821
static void wm_draw_update_clear_window(bContext *C, wmWindow *win)
Definition wm_draw.cc:1518
static bool wm_software_cursor_needed()
Definition wm_draw.cc:183
GPUTexture * wm_draw_region_texture(ARegion *region, int view)
Definition wm_draw.cc:808
static eGPUTextureFormat get_hdr_framebuffer_format(const Scene *scene)
Definition wm_draw.cc:673
bool WM_region_use_viewport(ScrArea *area, ARegion *region)
Definition wm_draw.cc:556
#define SPACE_NAME(space)
static void wm_region_test_render_do_draw(const Scene *scene, Depsgraph *depsgraph, ScrArea *area, ARegion *region)
Definition wm_draw.cc:503
static bool wm_draw_region_stereo_set(Main *bmain, ScrArea *area, ARegion *region, eStereoViews sview)
Definition wm_draw.cc:396
bool WM_window_pixels_read_sample_from_offscreen(bContext *C, wmWindow *win, const int pos[2], float r_col[3])
Definition wm_draw.cc:1380
void WM_draw_cb_exit(wmWindow *win, void *handle)
Definition wm_draw.cc:620
void wm_draw_region_clear(wmWindow *win, ARegion *)
Definition wm_draw.cc:1597
static void wm_region_test_gizmo_do_draw(bContext *C, ScrArea *area, ARegion *region, bool tag_redraw)
Definition wm_draw.cc:465
void WM_paint_cursor_tag_redraw(wmWindow *win, ARegion *)
Definition wm_draw.cc:1533
static void wm_software_cursor_draw(wmWindow *win, const GrabState *grab_state)
Definition wm_draw.cc:343
static struct @1377 g_software_cursor
static bool wm_software_cursor_motion_test(const wmWindow *win)
Definition wm_draw.cc:210
static void wm_software_cursor_motion_clear_with_window(const wmWindow *win)
Definition wm_draw.cc:232
void WM_draw_region_viewport_bind(ARegion *region)
Definition wm_draw.cc:1652
GPUViewport * WM_draw_region_get_bound_viewport(ARegion *region)
Definition wm_draw.cc:915
static void wm_software_cursor_draw_crosshair(const int event_xy[2])
Definition wm_draw.cc:300
int winid
Definition wm_draw.cc:169
void wm_draw_region_test(bContext *C, ScrArea *area, ARegion *region)
Definition wm_draw.cc:1608
static void wm_draw_region_blit(ARegion *region, int view)
Definition wm_draw.cc:782
uint8_t * WM_window_pixels_read_from_offscreen(bContext *C, wmWindow *win, int r_size[2])
Definition wm_draw.cc:1341
void WM_draw_region_free(ARegion *region)
Definition wm_draw.cc:1603
static void wm_software_cursor_motion_update(const wmWindow *win)
Definition wm_draw.cc:217
static void wm_region_draw_overlay(bContext *C, const ScrArea *area, ARegion *region)
Definition wm_draw.cc:380
static void wm_draw_window(bContext *C, wmWindow *win)
Definition wm_draw.cc:1165
static void wm_software_cursor_draw_bitmap(const int event_xy[2], const GHOST_CursorBitmapRef *bitmap)
Definition wm_draw.cc:239
static bool wm_window_grab_warp_region_is_set(const wmWindow *win)
Definition wm_draw.cc:74
bool WM_desktop_cursor_sample_read(float r_col[3])
Definition wm_draw.cc:1428
void wm_draw_update(bContext *C)
Definition wm_draw.cc:1541
static bool wm_draw_update_test_window(Main *bmain, bContext *C, wmWindow *win)
Definition wm_draw.cc:1440
static void wm_draw_window_onscreen(bContext *C, wmWindow *win, int view)
Definition wm_draw.cc:1051
static void wm_software_cursor_motion_clear()
Definition wm_draw.cc:225
bool WM_window_pixels_read_sample(bContext *C, wmWindow *win, const int pos[2], float r_col[3])
Definition wm_draw.cc:1419
void WM_report(eReportType type, const char *message)
void wm_gesture_draw(wmWindow *win)
bool WM_gizmo_group_type_poll(const bContext *C, const wmGizmoGroupType *gzgt)
const ListBase * WM_gizmomap_group_list(wmGizmoMap *gzmap)
void wm_stereo3d_draw_sidebyside(wmWindow *win, int view)
Definition wm_stereo.cc:44
bool WM_stereo3d_enabled(wmWindow *win, bool skip_stereo3d_check)
Definition wm_stereo.cc:141
void wm_stereo3d_draw_topbottom(wmWindow *win, int view)
Definition wm_stereo.cc:93
void wmViewport(const rcti *winrct)
void wmWindowViewport(const wmWindow *win)
void wmWindowViewport_ex(const wmWindow *win, float offset)
void wm_surface_make_drawable(wmSurface *surface)
Definition wm_surface.cc:78
void wm_surface_clear_drawable()
Definition wm_surface.cc:49
void wm_surfaces_iter(bContext *C, void(*cb)(bContext *C, wmSurface *))
Definition wm_surface.cc:29
void WM_toolsystem_update_from_context(bContext *C, WorkSpace *workspace, const Scene *scene, ViewLayer *view_layer, ScrArea *area)
blender::int2 WM_window_native_pixel_size(const wmWindow *win)
void wm_window_swap_buffers(wmWindow *win)
Push rendered buffer to the screen.
bool wm_cursor_position_get(wmWindow *win, int *r_x, int *r_y)
int WM_window_native_pixel_y(const wmWindow *win)
void wm_window_clear_drawable(wmWindowManager *wm)
void wm_window_make_drawable(wmWindowManager *wm, wmWindow *win)
eWM_CapabilitiesFlag WM_capabilities_flag()
ViewLayer * WM_window_get_active_view_layer(const wmWindow *win)
Scene * WM_window_get_active_scene(const wmWindow *win)
bScreen * WM_window_get_active_screen(const wmWindow *win)