Blender V4.3
wm_splash_screen.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
17#include <algorithm>
18#include <cstring>
19
20#include "DNA_ID.h"
21#include "DNA_scene_types.h"
22#include "DNA_screen_types.h"
23#include "DNA_userdef_types.h"
25
26#include "BLF_api.hh"
27
28#include "BLI_blenlib.h"
29#include "BLI_utildefines.h"
30
31#include "BKE_appdir.hh"
32#include "BKE_blender_version.h"
33#include "BKE_context.hh"
34
35#include "BLT_translation.hh"
36
37#include "IMB_imbuf.hh"
38#include "IMB_imbuf_types.hh"
39
40#include "ED_datafiles.h"
41#include "ED_screen.hh"
42
43#include "RNA_access.hh"
44
45#include "UI_interface.hh"
46#include "UI_interface_icons.hh"
47#include "UI_resources.hh"
48
49#include "WM_api.hh"
50#include "WM_types.hh"
51
52#include "wm.hh"
53
54/* -------------------------------------------------------------------- */
58static void wm_block_splash_close(bContext *C, void *arg_block, void * /*arg*/)
59{
60 wmWindow *win = CTX_wm_window(C);
61 UI_popup_block_close(C, win, static_cast<uiBlock *>(arg_block));
62}
63
64static void wm_block_splash_add_label(uiBlock *block, const char *label, int x, int y)
65{
66 if (!(label && label[0])) {
67 return;
68 }
69
71
72 uiBut *but = uiDefBut(
73 block, UI_BTYPE_LABEL, 0, label, 0, y, x, UI_UNIT_Y, nullptr, 0, 0, nullptr);
76
77 /* Regardless of theme, this text should always be bright white. */
78 uchar color[4] = {255, 255, 255, 255};
79 UI_but_color_set(but, color);
80
82}
83
84#ifndef WITH_HEADLESS
86{
87 uchar *rct = ibuf->byte_buffer.data;
88 if (!rct) {
89 return;
90 }
91
92 bTheme *btheme = UI_GetTheme();
93 const float roundness = btheme->tui.wcol_menu_back.roundness * UI_SCALE_FAC;
94 const int size = roundness * 20;
95
97 /* Y-axis initial offset. */
98 rct += 4 * (ibuf->y - size) * ibuf->x;
99
100 for (int y = 0; y < size; y++) {
101 for (int x = 0; x < size; x++, rct += 4) {
102 const float pixel = 1.0 / size;
103 const float u = pixel * x;
104 const float v = pixel * y;
105 const float distance = sqrt(u * u + v * v);
106
107 /* Pointer offset to the alpha value of pixel. */
108 /* NOTE: the left corner is flipped in the X-axis. */
109 const int offset_l = 4 * (size - x - x - 1) + 3;
110 const int offset_r = 4 * (ibuf->x - size) + 3;
111
112 if (distance > 1.0) {
113 rct[offset_l] = 0;
114 rct[offset_r] = 0;
115 }
116 else {
117 /* Create a single pixel wide transition for anti-aliasing.
118 * Invert the distance and map its range [0, 1] to [0, pixel]. */
119 const float fac = (1.0 - distance) * size;
120
121 if (fac > 1.0) {
122 continue;
123 }
124
125 const uchar alpha = unit_float_to_uchar_clamp(fac);
126 rct[offset_l] = alpha;
127 rct[offset_r] = alpha;
128 }
129 }
130
131 /* X-axis offset to the next row. */
132 rct += 4 * (ibuf->x - size);
133 }
134 }
135}
136#endif /* !WITH_HEADLESS */
137
138static ImBuf *wm_block_splash_image(int width, int *r_height)
139{
140 ImBuf *ibuf = nullptr;
141 int height = 0;
142#ifndef WITH_HEADLESS
143 if (U.app_template[0] != '\0') {
144 char splash_filepath[FILE_MAX];
145 char template_directory[FILE_MAX];
147 U.app_template, template_directory, sizeof(template_directory)))
148 {
149 BLI_path_join(splash_filepath, sizeof(splash_filepath), template_directory, "splash.png");
150 ibuf = IMB_loadiffname(splash_filepath, IB_rect, nullptr);
151 }
152 }
153
154 if (ibuf == nullptr) {
155 const uchar *splash_data = (const uchar *)datatoc_splash_png;
156 size_t splash_data_size = datatoc_splash_png_size;
158 splash_data, splash_data_size, IB_rect, nullptr, "<splash screen>");
159 }
160
161 if (ibuf) {
162 ibuf->planes = 32; /* The image might not have an alpha channel. */
163 height = (width * ibuf->y) / ibuf->x;
164 if (width != ibuf->x || height != ibuf->y) {
165 IMB_scale(ibuf, width, height, IMBScaleFilter::Box, false);
166 }
167
170 }
171
172#else
173 UNUSED_VARS(width);
174#endif
175 *r_height = height;
176 return ibuf;
177}
178
182static void wm_block_splash_close_on_fileselect(bContext *C, void *arg1, void * /*arg2*/)
183{
184 wmWindow *win = CTX_wm_window(C);
185 if (!win) {
186 return;
187 }
188
189 /* Check for the event as this will run before the new window/area has been created. */
190 bool has_fileselect = false;
191 LISTBASE_FOREACH (const wmEvent *, event, &win->event_queue) {
192 if (event->type == EVT_FILESELECT) {
193 has_fileselect = true;
194 break;
195 }
196 }
197
198 if (has_fileselect) {
199 wm_block_splash_close(C, arg1, nullptr);
200 }
201}
202
203#if defined(__APPLE__)
204/* Check if Blender is running under Rosetta for the purpose of displaying a splash screen warning.
205 * From Apple's WWDC 2020 Session - Explore the new system architecture of Apple Silicon Macs.
206 * Time code: 14:31 - https://developer.apple.com/videos/play/wwdc2020/10686/ */
207
208# include <sys/sysctl.h>
209
210static int is_using_macos_rosetta()
211{
212 int ret = 0;
213 size_t size = sizeof(ret);
214
215 if (sysctlbyname("sysctl.proc_translated", &ret, &size, nullptr, 0) != -1) {
216 return ret;
217 }
218 /* If "sysctl.proc_translated" is not present then must be native. */
219 if (errno == ENOENT) {
220 return 0;
221 }
222 return -1;
223}
224#endif /* __APPLE__ */
225
226static uiBlock *wm_block_splash_create(bContext *C, ARegion *region, void * /*arg*/)
227{
228 const uiStyle *style = UI_style_get_dpi();
229
230 uiBlock *block = UI_block_begin(C, region, "splash", UI_EMBOSS);
231
232 /* Note on #UI_BLOCK_NO_WIN_CLIP, the window size is not always synchronized
233 * with the OS when the splash shows, window clipping in this case gives
234 * ugly results and clipping the splash isn't useful anyway, just disable it #32938. */
237
238 int splash_width = style->widget.points * 45 * UI_SCALE_FAC;
239 CLAMP_MAX(splash_width, CTX_wm_window(C)->sizex * 0.7f);
240 int splash_height;
241
242 /* Would be nice to support caching this, so it only has to be re-read (and likely resized) on
243 * first draw or if the image changed. */
244 ImBuf *ibuf = wm_block_splash_image(splash_width, &splash_height);
245 /* This should never happen, if it does - don't crash. */
246 if (LIKELY(ibuf)) {
247 uiBut *but = uiDefButImage(
248 block, ibuf, 0, 0.5f * U.widget_unit, splash_width, splash_height, nullptr);
249
250 UI_but_func_set(but, wm_block_splash_close, block, nullptr);
251
254 splash_width - 8.0 * UI_SCALE_FAC,
255 splash_height - 13.0 * UI_SCALE_FAC);
256 }
257
258 const int layout_margin_x = UI_SCALE_FAC * 26;
259 uiLayout *layout = UI_block_layout(block,
262 layout_margin_x,
263 0,
264 splash_width - (layout_margin_x * 2),
265 UI_SCALE_FAC * 110,
266 0,
267 style);
268
269 MenuType *mt;
270 char userpref[FILE_MAX];
271 const std::optional<std::string> cfgdir = BKE_appdir_folder_id(BLENDER_USER_CONFIG, nullptr);
272
273 if (cfgdir.has_value()) {
274 BLI_path_join(userpref, sizeof(userpref), cfgdir->c_str(), BLENDER_USERPREF_FILE);
275 }
276 else {
277 userpref[0] = '\0';
278 }
279
280 /* Draw setup screen if no preferences have been saved yet. */
281 if (!(userpref[0] && BLI_exists(userpref))) {
282 mt = WM_menutype_find("WM_MT_splash_quick_setup", true);
283
284 /* The #UI_BLOCK_QUICK_SETUP flag prevents the button text from being left-aligned,
285 * as it is for all menus due to the #UI_BLOCK_LOOP flag, see in #ui_def_but. */
287 }
288 else {
289 mt = WM_menutype_find("WM_MT_splash", true);
290 }
291
293
294 if (mt) {
295 UI_menutype_draw(C, mt, layout);
296 }
297
298/* Displays a warning if blender is being emulated via Rosetta (macOS) or XTA (Windows) */
299#if defined(__APPLE__) || defined(_M_X64)
300# if defined(__APPLE__)
301 if (is_using_macos_rosetta() > 0) {
302# elif defined(_M_X64)
303 if (strncmp(BLI_getenv("PROCESSOR_IDENTIFIER"), "ARM", 3) == 0) {
304# endif
306
307 uiLayout *split = uiLayoutSplit(layout, 0.725, true);
308 uiLayout *row1 = uiLayoutRow(split, true);
309 uiLayout *row2 = uiLayoutRow(split, true);
310
311 uiItemL(row1, RPT_("Intel binary detected. Expect reduced performance."), ICON_ERROR);
312
313 PointerRNA op_ptr;
314 uiItemFullO(row2,
315 "WM_OT_url_open",
317 ICON_URL,
318 nullptr,
321 &op_ptr);
322# if defined(__APPLE__)
324 &op_ptr,
325 "url",
326 "https://docs.blender.org/manual/en/latest/getting_started/installing/macos.html");
327# elif defined(_M_X64)
329 &op_ptr,
330 "url",
331 "https://docs.blender.org/manual/en/latest/getting_started/installing/windows.html");
332# endif
333
334 uiItemS(layout);
335 }
336#endif
337
339
340 return block;
341}
342
343static int wm_splash_invoke(bContext *C, wmOperator * /*op*/, const wmEvent * /*event*/)
344{
345 UI_popup_block_invoke(C, wm_block_splash_create, nullptr, nullptr);
346
347 return OPERATOR_FINISHED;
348}
349
351{
352 ot->name = "Splash Screen";
353 ot->idname = "WM_OT_splash";
354 ot->description = "Open the splash screen with release info";
355
358}
359
362/* -------------------------------------------------------------------- */
366static uiBlock *wm_block_about_create(bContext *C, ARegion *region, void * /*arg*/)
367{
368 constexpr bool show_color = false;
369 const uiStyle *style = UI_style_get_dpi();
370 const int dialog_width = style->widget.points * 42 * UI_SCALE_FAC;
371
372 uiBlock *block = UI_block_begin(C, region, "about", UI_EMBOSS);
373
376
377 uiLayout *layout = UI_block_layout(
378 block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, 0, 0, dialog_width, 0, 0, style);
379
380/* Blender logo. */
381#ifndef WITH_HEADLESS
382
383 float size = 0.2f * dialog_width;
384
385 ImBuf *ibuf = UI_svg_icon_bitmap(ICON_BLENDER_LOGO_LARGE, size, show_color);
386
387 if (ibuf) {
388 bTheme *btheme = UI_GetTheme();
389 const uchar *color = btheme->tui.wcol_menu_back.text_sel;
390
391 /* The top margin. */
392 uiLayout *row = uiLayoutRow(layout, false);
393 uiItemS_ex(row, 0.2f);
394
395 /* The logo image. */
396 row = uiLayoutRow(layout, false);
398 uiDefButImage(block, ibuf, 0, U.widget_unit, ibuf->x, ibuf->y, show_color ? nullptr : color);
399
400 /* Padding below the logo. */
401 row = uiLayoutRow(layout, false);
402 uiItemS_ex(row, 2.7f);
403 }
404#endif /* !WITH_HEADLESS */
405
406 uiLayout *col = uiLayoutColumn(layout, true);
407
408 uiItemL_ex(col, IFACE_("Blender"), ICON_NONE, true, false);
409
410 MenuType *mt = WM_menutype_find("WM_MT_splash_about", true);
411 if (mt) {
412 UI_menutype_draw(C, mt, col);
413 }
414
416
417 return block;
418}
419
420static int wm_splash_about_invoke(bContext *C, wmOperator * /*op*/, const wmEvent * /*event*/)
421{
422 UI_popup_block_invoke(C, wm_block_about_create, nullptr, nullptr);
423
424 return OPERATOR_FINISHED;
425}
426
428{
429 ot->name = "About Blender";
430 ot->idname = "WM_OT_splash_about";
431 ot->description = "Open a window with information about Blender";
432
435}
436
bool BKE_appdir_app_template_id_search(const char *app_template, char *path, size_t path_maxncpy) ATTR_NONNULL(1)
Definition appdir.cc:1071
#define BLENDER_USERPREF_FILE
@ BLENDER_USER_CONFIG
std::optional< std::string > BKE_appdir_folder_id(int folder_id, const char *subfolder) ATTR_WARN_UNUSED_RESULT
Definition appdir.cc:704
const char * BKE_blender_version_string(void)
Definition blender.cc:139
wmWindow * CTX_wm_window(const bContext *C)
sqrt(x)+1/max(0
int BLI_exists(const char *path) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition storage.cc:350
#define LISTBASE_FOREACH(type, var, list)
#define FILE_MAX
#define BLI_path_join(...)
const char * BLI_getenv(const char *env) ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT
unsigned char uchar
#define CLAMP_MAX(a, c)
#define UNUSED_VARS(...)
#define LIKELY(x)
#define RPT_(msgid)
#define CTX_IFACE_(context, msgid)
#define BLT_I18NCONTEXT_OPERATOR_DEFAULT
#define IFACE_(msgid)
ID and Library types, which are fundamental for SDNA.
#define UI_SCALE_FAC
int datatoc_splash_png_size
const char datatoc_splash_png[]
void IMB_premultiply_alpha(ImBuf *ibuf)
Definition filter.cc:579
ImBuf * IMB_loadiffname(const char *filepath, int flags, char colorspace[IM_MAX_SPACE])
Definition readimage.cc:146
bool IMB_scale(ImBuf *ibuf, unsigned int newx, unsigned int newy, IMBScaleFilter filter, bool threaded=true)
Definition scaling.cc:779
Contains defines and structs used throughout the imbuf module.
@ IB_rect
Group Output data from inside of a node group A color picker Mix two input colors RGB to Convert a color s luminance to a grayscale value Generate a normal vector and a dot product Brightness Control the brightness and contrast of the input color Vector Map input vector components with curves Camera Retrieve information about the camera and how it relates to the current shading point s position Clamp a value between a minimum and a maximum Vector Perform vector math operation Invert Invert a color
void UI_but_func_set(uiBut *but, std::function< void(bContext &)> func)
#define UI_UNIT_Y
@ UI_EMBOSS_NONE
@ UI_EMBOSS
void UI_block_theme_style_set(uiBlock *block, char theme_style)
@ UI_LAYOUT_ALIGN_LEFT
@ UI_BLOCK_LOOP
@ UI_BLOCK_KEEP_OPEN
@ UI_BLOCK_QUICK_SETUP
@ UI_BLOCK_NO_WIN_CLIP
void UI_but_color_set(uiBut *but, const uchar color[4])
uiBut * uiDefBut(uiBlock *block, int type, int retval, blender::StringRef str, int x, int y, short width, short height, void *poin, float min, float max, const char *tip)
void uiItemL(uiLayout *layout, const char *name, int icon)
void uiItemFullO(uiLayout *layout, const char *opname, const char *name, int icon, IDProperty *properties, wmOperatorCallContext context, eUI_Item_Flag flag, PointerRNA *r_opptr)
void UI_popup_block_invoke(bContext *C, uiBlockCreateFunc func, void *arg, uiFreeArgFunc arg_free)
uiLayout * uiLayoutRow(uiLayout *layout, bool align)
uiLayout * UI_block_layout(uiBlock *block, int dir, int type, int x, int y, int size, int em, int padding, const uiStyle *style)
const uiStyle * UI_style_get_dpi()
void UI_but_drawflag_enable(uiBut *but, int flag)
void uiLayoutSetAlignment(uiLayout *layout, char alignment)
uiBlock * UI_block_begin(const bContext *C, ARegion *region, std::string name, eUIEmbossType emboss)
void uiItemS(uiLayout *layout)
void UI_popup_block_close(bContext *C, wmWindow *win, uiBlock *block)
void uiItemS_ex(uiLayout *layout, float factor, LayoutSeparatorType type=LayoutSeparatorType::Auto)
#define UI_ITEM_NONE
void UI_block_emboss_set(uiBlock *block, eUIEmbossType emboss)
void UI_menutype_draw(bContext *C, MenuType *mt, uiLayout *layout)
void UI_block_func_set(uiBlock *block, uiButHandleFunc func, void *arg1, void *arg2)
void UI_but_drawflag_disable(uiBut *but, int flag)
@ UI_LAYOUT_VERTICAL
@ UI_LAYOUT_PANEL
@ UI_BLOCK_THEME_STYLE_POPUP
uiBut * uiDefButImage(uiBlock *block, void *imbuf, int x, int y, short width, short height, const uchar color[4])
void UI_block_bounds_set_centered(uiBlock *block, int addval)
Definition interface.cc:616
uiLayout * uiLayoutColumn(uiLayout *layout, bool align)
uiLayout * uiLayoutSplit(uiLayout *layout, float percentage, bool align)
void UI_block_flag_enable(uiBlock *block, int flag)
@ UI_BTYPE_LABEL
uiBut * uiItemL_ex(uiLayout *layout, const char *name, int icon, bool highlight, bool redalert)
@ UI_BUT_TEXT_RIGHT
@ UI_BUT_TEXT_LEFT
ImBuf * UI_svg_icon_bitmap(uint icon_id, float size, bool multicolor=false)
bTheme * UI_GetTheme()
@ WM_OP_INVOKE_DEFAULT
Definition WM_types.hh:218
ATTR_WARN_UNUSED_RESULT const BMVert * v
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
unsigned int U
Definition btGjkEpa3.h:78
const char * label
uint col
struct ImBuf * IMB_ibImageFromMemory(const unsigned char *, size_t, int, char[IM_MAX_SPACE], const char *)
#define unit_float_to_uchar_clamp(val)
float distance(float a, float b)
return ret
void RNA_string_set(PointerRNA *ptr, const char *name, const char *value)
ImBufByteBuffer byte_buffer
unsigned char planes
uiWidgetColors wcol_menu_back
uiFontStyle widget
unsigned char text_sel[4]
const char * name
Definition WM_types.hh:990
bool(* poll)(bContext *C) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1042
const char * idname
Definition WM_types.hh:992
int(* invoke)(bContext *C, wmOperator *op, const wmEvent *event) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1022
const char * description
Definition WM_types.hh:996
@ EVT_FILESELECT
wmOperatorType * ot
Definition wm_files.cc:4125
MenuType * WM_menutype_find(const char *idname, bool quiet)
bool WM_operator_winactive(bContext *C)
void WM_OT_splash_about(wmOperatorType *ot)
static ImBuf * wm_block_splash_image(int width, int *r_height)
static void wm_block_splash_add_label(uiBlock *block, const char *label, int x, int y)
static void wm_block_splash_close(bContext *C, void *arg_block, void *)
static uiBlock * wm_block_about_create(bContext *C, ARegion *region, void *)
static void wm_block_splash_image_roundcorners_add(ImBuf *ibuf)
static void wm_block_splash_close_on_fileselect(bContext *C, void *arg1, void *)
static uiBlock * wm_block_splash_create(bContext *C, ARegion *region, void *)
static int wm_splash_about_invoke(bContext *C, wmOperator *, const wmEvent *)
static int wm_splash_invoke(bContext *C, wmOperator *, const wmEvent *)
void WM_OT_splash(wmOperatorType *ot)