1 /*************************************************************************/
2 /* editor_preview_plugins.cpp */
3 /*************************************************************************/
4 /* This file is part of: */
5 /* GODOT ENGINE */
6 /* https://godotengine.org */
7 /*************************************************************************/
8 /* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
9 /* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
10 /* */
11 /* Permission is hereby granted, free of charge, to any person obtaining */
12 /* a copy of this software and associated documentation files (the */
13 /* "Software"), to deal in the Software without restriction, including */
14 /* without limitation the rights to use, copy, modify, merge, publish, */
15 /* distribute, sublicense, and/or sell copies of the Software, and to */
16 /* permit persons to whom the Software is furnished to do so, subject to */
17 /* the following conditions: */
18 /* */
19 /* The above copyright notice and this permission notice shall be */
20 /* included in all copies or substantial portions of the Software. */
21 /* */
22 /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
23 /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
24 /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
25 /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
26 /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
27 /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
28 /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
29 /*************************************************************************/
30
31 #include "editor_preview_plugins.h"
32
33 #include "core/io/file_access_memory.h"
34 #include "core/io/resource_loader.h"
35 #include "core/os/os.h"
36 #include "editor/editor_node.h"
37 #include "editor/editor_scale.h"
38 #include "editor/editor_settings.h"
39 #include "scene/resources/bit_map.h"
40 #include "scene/resources/dynamic_font.h"
41 #include "scene/resources/material.h"
42 #include "scene/resources/mesh.h"
43 #include "servers/audio/audio_stream.h"
44
post_process_preview(Ref<Image> p_image)45 void post_process_preview(Ref<Image> p_image) {
46
47 if (p_image->get_format() != Image::FORMAT_RGBA8)
48 p_image->convert(Image::FORMAT_RGBA8);
49
50 p_image->lock();
51
52 const int w = p_image->get_width();
53 const int h = p_image->get_height();
54
55 const int r = MIN(w, h) / 32;
56 const int r2 = r * r;
57 Color transparent = Color(0, 0, 0, 0);
58
59 for (int i = 0; i < r; i++) {
60 for (int j = 0; j < r; j++) {
61 int dx = i - r;
62 int dy = j - r;
63 if (dx * dx + dy * dy > r2) {
64 p_image->set_pixel(i, j, transparent);
65 p_image->set_pixel(w - 1 - i, j, transparent);
66 p_image->set_pixel(w - 1 - i, h - 1 - j, transparent);
67 p_image->set_pixel(i, h - 1 - j, transparent);
68 } else {
69 break;
70 }
71 }
72 }
73
74 p_image->unlock();
75 }
76
handles(const String & p_type) const77 bool EditorTexturePreviewPlugin::handles(const String &p_type) const {
78
79 return ClassDB::is_parent_class(p_type, "Texture");
80 }
81
generate_small_preview_automatically() const82 bool EditorTexturePreviewPlugin::generate_small_preview_automatically() const {
83 return true;
84 }
85
generate(const RES & p_from,const Size2 & p_size) const86 Ref<Texture> EditorTexturePreviewPlugin::generate(const RES &p_from, const Size2 &p_size) const {
87
88 Ref<Image> img;
89 Ref<AtlasTexture> atex = p_from;
90 Ref<LargeTexture> ltex = p_from;
91 if (atex.is_valid()) {
92 Ref<Texture> tex = atex->get_atlas();
93 if (!tex.is_valid()) {
94 return Ref<Texture>();
95 }
96
97 Ref<Image> atlas = tex->get_data();
98 if (!atlas.is_valid()) {
99 return Ref<Texture>();
100 }
101
102 img = atlas->get_rect(atex->get_region());
103 } else if (ltex.is_valid()) {
104 img = ltex->to_image();
105 } else {
106 Ref<Texture> tex = p_from;
107 if (tex.is_valid()) {
108 img = tex->get_data();
109 if (img.is_valid()) {
110 img = img->duplicate();
111 }
112 }
113 }
114
115 if (img.is_null() || img->empty())
116 return Ref<Texture>();
117
118 img->clear_mipmaps();
119
120 if (img->is_compressed()) {
121 if (img->decompress() != OK)
122 return Ref<Texture>();
123 } else if (img->get_format() != Image::FORMAT_RGB8 && img->get_format() != Image::FORMAT_RGBA8) {
124 img->convert(Image::FORMAT_RGBA8);
125 }
126
127 Vector2 new_size = img->get_size();
128 if (new_size.x > p_size.x) {
129 new_size = Vector2(p_size.x, new_size.y * p_size.x / new_size.x);
130 }
131 if (new_size.y > p_size.y) {
132 new_size = Vector2(new_size.x * p_size.y / new_size.y, p_size.y);
133 }
134 Vector2i new_size_i(MAX(1, (int)new_size.x), MAX(1, (int)new_size.y));
135 img->resize(new_size_i.x, new_size_i.y, Image::INTERPOLATE_CUBIC);
136
137 post_process_preview(img);
138
139 Ref<ImageTexture> ptex = Ref<ImageTexture>(memnew(ImageTexture));
140
141 ptex->create_from_image(img, 0);
142 return ptex;
143 }
144
EditorTexturePreviewPlugin()145 EditorTexturePreviewPlugin::EditorTexturePreviewPlugin() {
146 }
147
148 ////////////////////////////////////////////////////////////////////////////
149
handles(const String & p_type) const150 bool EditorImagePreviewPlugin::handles(const String &p_type) const {
151
152 return p_type == "Image";
153 }
154
generate(const RES & p_from,const Size2 & p_size) const155 Ref<Texture> EditorImagePreviewPlugin::generate(const RES &p_from, const Size2 &p_size) const {
156
157 Ref<Image> img = p_from;
158
159 if (img.is_null() || img->empty())
160 return Ref<Image>();
161
162 img = img->duplicate();
163 img->clear_mipmaps();
164
165 if (img->is_compressed()) {
166 if (img->decompress() != OK)
167 return Ref<Image>();
168 } else if (img->get_format() != Image::FORMAT_RGB8 && img->get_format() != Image::FORMAT_RGBA8) {
169 img->convert(Image::FORMAT_RGBA8);
170 }
171
172 Vector2 new_size = img->get_size();
173 if (new_size.x > p_size.x) {
174 new_size = Vector2(p_size.x, new_size.y * p_size.x / new_size.x);
175 }
176 if (new_size.y > p_size.y) {
177 new_size = Vector2(new_size.x * p_size.y / new_size.y, p_size.y);
178 }
179 img->resize(new_size.x, new_size.y, Image::INTERPOLATE_CUBIC);
180
181 post_process_preview(img);
182
183 Ref<ImageTexture> ptex;
184 ptex.instance();
185
186 ptex->create_from_image(img, 0);
187 return ptex;
188 }
189
EditorImagePreviewPlugin()190 EditorImagePreviewPlugin::EditorImagePreviewPlugin() {
191 }
192
generate_small_preview_automatically() const193 bool EditorImagePreviewPlugin::generate_small_preview_automatically() const {
194 return true;
195 }
196 ////////////////////////////////////////////////////////////////////////////
197 /////////////////////////////////////////////////
handles(const String & p_type) const198 bool EditorBitmapPreviewPlugin::handles(const String &p_type) const {
199
200 return ClassDB::is_parent_class(p_type, "BitMap");
201 }
202
generate(const RES & p_from,const Size2 & p_size) const203 Ref<Texture> EditorBitmapPreviewPlugin::generate(const RES &p_from, const Size2 &p_size) const {
204
205 Ref<BitMap> bm = p_from;
206
207 if (bm->get_size() == Size2()) {
208 return Ref<Texture>();
209 }
210
211 PoolVector<uint8_t> data;
212
213 data.resize(bm->get_size().width * bm->get_size().height);
214
215 {
216 PoolVector<uint8_t>::Write w = data.write();
217
218 for (int i = 0; i < bm->get_size().width; i++) {
219 for (int j = 0; j < bm->get_size().height; j++) {
220 if (bm->get_bit(Point2i(i, j))) {
221 w[j * bm->get_size().width + i] = 255;
222 } else {
223 w[j * bm->get_size().width + i] = 0;
224 }
225 }
226 }
227 }
228
229 Ref<Image> img;
230 img.instance();
231 img->create(bm->get_size().width, bm->get_size().height, 0, Image::FORMAT_L8, data);
232
233 if (img->is_compressed()) {
234 if (img->decompress() != OK)
235 return Ref<Texture>();
236 } else if (img->get_format() != Image::FORMAT_RGB8 && img->get_format() != Image::FORMAT_RGBA8) {
237 img->convert(Image::FORMAT_RGBA8);
238 }
239
240 Vector2 new_size = img->get_size();
241 if (new_size.x > p_size.x) {
242 new_size = Vector2(p_size.x, new_size.y * p_size.x / new_size.x);
243 }
244 if (new_size.y > p_size.y) {
245 new_size = Vector2(new_size.x * p_size.y / new_size.y, p_size.y);
246 }
247 img->resize(new_size.x, new_size.y, Image::INTERPOLATE_CUBIC);
248
249 post_process_preview(img);
250
251 Ref<ImageTexture> ptex = Ref<ImageTexture>(memnew(ImageTexture));
252
253 ptex->create_from_image(img, 0);
254 return ptex;
255 }
256
generate_small_preview_automatically() const257 bool EditorBitmapPreviewPlugin::generate_small_preview_automatically() const {
258 return true;
259 }
260
EditorBitmapPreviewPlugin()261 EditorBitmapPreviewPlugin::EditorBitmapPreviewPlugin() {
262 }
263
264 ///////////////////////////////////////////////////////////////////////////
265
handles(const String & p_type) const266 bool EditorPackedScenePreviewPlugin::handles(const String &p_type) const {
267
268 return ClassDB::is_parent_class(p_type, "PackedScene");
269 }
generate(const RES & p_from,const Size2 & p_size) const270 Ref<Texture> EditorPackedScenePreviewPlugin::generate(const RES &p_from, const Size2 &p_size) const {
271
272 return generate_from_path(p_from->get_path(), p_size);
273 }
274
generate_from_path(const String & p_path,const Size2 & p_size) const275 Ref<Texture> EditorPackedScenePreviewPlugin::generate_from_path(const String &p_path, const Size2 &p_size) const {
276
277 String temp_path = EditorSettings::get_singleton()->get_cache_dir();
278 String cache_base = ProjectSettings::get_singleton()->globalize_path(p_path).md5_text();
279 cache_base = temp_path.plus_file("resthumb-" + cache_base);
280
281 //does not have it, try to load a cached thumbnail
282
283 String path = cache_base + ".png";
284
285 if (!FileAccess::exists(path))
286 return Ref<Texture>();
287
288 Ref<Image> img;
289 img.instance();
290 Error err = img->load(path);
291 if (err == OK) {
292
293 Ref<ImageTexture> ptex = Ref<ImageTexture>(memnew(ImageTexture));
294
295 post_process_preview(img);
296 ptex->create_from_image(img, 0);
297 return ptex;
298
299 } else {
300 return Ref<Texture>();
301 }
302 }
303
EditorPackedScenePreviewPlugin()304 EditorPackedScenePreviewPlugin::EditorPackedScenePreviewPlugin() {
305 }
306
307 //////////////////////////////////////////////////////////////////
308
_preview_done(const Variant & p_udata)309 void EditorMaterialPreviewPlugin::_preview_done(const Variant &p_udata) {
310
311 preview_done = true;
312 }
313
_bind_methods()314 void EditorMaterialPreviewPlugin::_bind_methods() {
315
316 ClassDB::bind_method("_preview_done", &EditorMaterialPreviewPlugin::_preview_done);
317 }
318
handles(const String & p_type) const319 bool EditorMaterialPreviewPlugin::handles(const String &p_type) const {
320
321 return ClassDB::is_parent_class(p_type, "Material"); //any material
322 }
323
generate_small_preview_automatically() const324 bool EditorMaterialPreviewPlugin::generate_small_preview_automatically() const {
325 return true;
326 }
327
generate(const RES & p_from,const Size2 & p_size) const328 Ref<Texture> EditorMaterialPreviewPlugin::generate(const RES &p_from, const Size2 &p_size) const {
329
330 Ref<Material> material = p_from;
331 ERR_FAIL_COND_V(material.is_null(), Ref<Texture>());
332
333 if (material->get_shader_mode() == Shader::MODE_SPATIAL) {
334
335 VS::get_singleton()->mesh_surface_set_material(sphere, 0, material->get_rid());
336
337 VS::get_singleton()->viewport_set_update_mode(viewport, VS::VIEWPORT_UPDATE_ONCE); //once used for capture
338
339 preview_done = false;
340 VS::get_singleton()->request_frame_drawn_callback(const_cast<EditorMaterialPreviewPlugin *>(this), "_preview_done", Variant());
341
342 while (!preview_done) {
343 OS::get_singleton()->delay_usec(10);
344 }
345
346 Ref<Image> img = VS::get_singleton()->texture_get_data(viewport_texture);
347 VS::get_singleton()->mesh_surface_set_material(sphere, 0, RID());
348
349 ERR_FAIL_COND_V(!img.is_valid(), Ref<ImageTexture>());
350
351 img->convert(Image::FORMAT_RGBA8);
352 int thumbnail_size = MAX(p_size.x, p_size.y);
353 img->resize(thumbnail_size, thumbnail_size, Image::INTERPOLATE_CUBIC);
354 post_process_preview(img);
355 Ref<ImageTexture> ptex = Ref<ImageTexture>(memnew(ImageTexture));
356 ptex->create_from_image(img, 0);
357 return ptex;
358 }
359
360 return Ref<Texture>();
361 }
362
EditorMaterialPreviewPlugin()363 EditorMaterialPreviewPlugin::EditorMaterialPreviewPlugin() {
364
365 scenario = VS::get_singleton()->scenario_create();
366
367 viewport = VS::get_singleton()->viewport_create();
368 VS::get_singleton()->viewport_set_update_mode(viewport, VS::VIEWPORT_UPDATE_DISABLED);
369 VS::get_singleton()->viewport_set_scenario(viewport, scenario);
370 VS::get_singleton()->viewport_set_size(viewport, 128, 128);
371 VS::get_singleton()->viewport_set_transparent_background(viewport, true);
372 VS::get_singleton()->viewport_set_active(viewport, true);
373 VS::get_singleton()->viewport_set_vflip(viewport, true);
374 viewport_texture = VS::get_singleton()->viewport_get_texture(viewport);
375
376 camera = VS::get_singleton()->camera_create();
377 VS::get_singleton()->viewport_attach_camera(viewport, camera);
378 VS::get_singleton()->camera_set_transform(camera, Transform(Basis(), Vector3(0, 0, 3)));
379 VS::get_singleton()->camera_set_perspective(camera, 45, 0.1, 10);
380
381 light = VS::get_singleton()->directional_light_create();
382 light_instance = VS::get_singleton()->instance_create2(light, scenario);
383 VS::get_singleton()->instance_set_transform(light_instance, Transform().looking_at(Vector3(-1, -1, -1), Vector3(0, 1, 0)));
384
385 light2 = VS::get_singleton()->directional_light_create();
386 VS::get_singleton()->light_set_color(light2, Color(0.7, 0.7, 0.7));
387 //VS::get_singleton()->light_set_color(light2, Color(0.7, 0.7, 0.7));
388
389 light_instance2 = VS::get_singleton()->instance_create2(light2, scenario);
390
391 VS::get_singleton()->instance_set_transform(light_instance2, Transform().looking_at(Vector3(0, 1, 0), Vector3(0, 0, 1)));
392
393 sphere = VS::get_singleton()->mesh_create();
394 sphere_instance = VS::get_singleton()->instance_create2(sphere, scenario);
395
396 int lats = 32;
397 int lons = 32;
398 float radius = 1.0;
399
400 PoolVector<Vector3> vertices;
401 PoolVector<Vector3> normals;
402 PoolVector<Vector2> uvs;
403 PoolVector<float> tangents;
404 Basis tt = Basis(Vector3(0, 1, 0), Math_PI * 0.5);
405
406 for (int i = 1; i <= lats; i++) {
407 double lat0 = Math_PI * (-0.5 + (double)(i - 1) / lats);
408 double z0 = Math::sin(lat0);
409 double zr0 = Math::cos(lat0);
410
411 double lat1 = Math_PI * (-0.5 + (double)i / lats);
412 double z1 = Math::sin(lat1);
413 double zr1 = Math::cos(lat1);
414
415 for (int j = lons; j >= 1; j--) {
416
417 double lng0 = 2 * Math_PI * (double)(j - 1) / lons;
418 double x0 = Math::cos(lng0);
419 double y0 = Math::sin(lng0);
420
421 double lng1 = 2 * Math_PI * (double)(j) / lons;
422 double x1 = Math::cos(lng1);
423 double y1 = Math::sin(lng1);
424
425 Vector3 v[4] = {
426 Vector3(x1 * zr0, z0, y1 * zr0),
427 Vector3(x1 * zr1, z1, y1 * zr1),
428 Vector3(x0 * zr1, z1, y0 * zr1),
429 Vector3(x0 * zr0, z0, y0 * zr0)
430 };
431
432 #define ADD_POINT(m_idx) \
433 normals.push_back(v[m_idx]); \
434 vertices.push_back(v[m_idx] * radius); \
435 { \
436 Vector2 uv(Math::atan2(v[m_idx].x, v[m_idx].z), Math::atan2(-v[m_idx].y, v[m_idx].z)); \
437 uv /= Math_PI; \
438 uv *= 4.0; \
439 uv = uv * 0.5 + Vector2(0.5, 0.5); \
440 uvs.push_back(uv); \
441 } \
442 { \
443 Vector3 t = tt.xform(v[m_idx]); \
444 tangents.push_back(t.x); \
445 tangents.push_back(t.y); \
446 tangents.push_back(t.z); \
447 tangents.push_back(1.0); \
448 }
449
450 ADD_POINT(0);
451 ADD_POINT(1);
452 ADD_POINT(2);
453
454 ADD_POINT(2);
455 ADD_POINT(3);
456 ADD_POINT(0);
457 }
458 }
459
460 Array arr;
461 arr.resize(VS::ARRAY_MAX);
462 arr[VS::ARRAY_VERTEX] = vertices;
463 arr[VS::ARRAY_NORMAL] = normals;
464 arr[VS::ARRAY_TANGENT] = tangents;
465 arr[VS::ARRAY_TEX_UV] = uvs;
466 VS::get_singleton()->mesh_add_surface_from_arrays(sphere, VS::PRIMITIVE_TRIANGLES, arr);
467 }
468
~EditorMaterialPreviewPlugin()469 EditorMaterialPreviewPlugin::~EditorMaterialPreviewPlugin() {
470
471 VS::get_singleton()->free(sphere);
472 VS::get_singleton()->free(sphere_instance);
473 VS::get_singleton()->free(viewport);
474 VS::get_singleton()->free(light);
475 VS::get_singleton()->free(light_instance);
476 VS::get_singleton()->free(light2);
477 VS::get_singleton()->free(light_instance2);
478 VS::get_singleton()->free(camera);
479 VS::get_singleton()->free(scenario);
480 }
481
482 ///////////////////////////////////////////////////////////////////////////
483
_is_text_char(CharType c)484 static bool _is_text_char(CharType c) {
485
486 return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_';
487 }
488
handles(const String & p_type) const489 bool EditorScriptPreviewPlugin::handles(const String &p_type) const {
490
491 return ClassDB::is_parent_class(p_type, "Script");
492 }
493
generate(const RES & p_from,const Size2 & p_size) const494 Ref<Texture> EditorScriptPreviewPlugin::generate(const RES &p_from, const Size2 &p_size) const {
495
496 Ref<Script> scr = p_from;
497 if (scr.is_null())
498 return Ref<Texture>();
499
500 String code = scr->get_source_code().strip_edges();
501 if (code == "")
502 return Ref<Texture>();
503
504 List<String> kwors;
505 scr->get_language()->get_reserved_words(&kwors);
506
507 Set<String> keywords;
508
509 for (List<String>::Element *E = kwors.front(); E; E = E->next()) {
510
511 keywords.insert(E->get());
512 }
513
514 int line = 0;
515 int col = 0;
516 Ref<Image> img;
517 img.instance();
518 int thumbnail_size = MAX(p_size.x, p_size.y);
519 img->create(thumbnail_size, thumbnail_size, 0, Image::FORMAT_RGBA8);
520
521 Color bg_color = EditorSettings::get_singleton()->get("text_editor/highlighting/background_color");
522 Color keyword_color = EditorSettings::get_singleton()->get("text_editor/highlighting/keyword_color");
523 Color text_color = EditorSettings::get_singleton()->get("text_editor/highlighting/text_color");
524 Color symbol_color = EditorSettings::get_singleton()->get("text_editor/highlighting/symbol_color");
525
526 img->lock();
527
528 if (bg_color.a == 0)
529 bg_color = Color(0, 0, 0, 0);
530 bg_color.a = MAX(bg_color.a, 0.2); // some background
531
532 for (int i = 0; i < thumbnail_size; i++) {
533 for (int j = 0; j < thumbnail_size; j++) {
534 img->set_pixel(i, j, bg_color);
535 }
536 }
537
538 const int x0 = thumbnail_size / 8;
539 const int y0 = thumbnail_size / 8;
540 const int available_height = thumbnail_size - 2 * y0;
541 col = x0;
542
543 bool prev_is_text = false;
544 bool in_keyword = false;
545 for (int i = 0; i < code.length(); i++) {
546
547 CharType c = code[i];
548 if (c > 32) {
549 if (col < thumbnail_size) {
550 Color color = text_color;
551
552 if (c != '_' && ((c >= '!' && c <= '/') || (c >= ':' && c <= '@') || (c >= '[' && c <= '`') || (c >= '{' && c <= '~') || c == '\t')) {
553 //make symbol a little visible
554 color = symbol_color;
555 in_keyword = false;
556 } else if (!prev_is_text && _is_text_char(c)) {
557 int pos = i;
558
559 while (_is_text_char(code[pos])) {
560 pos++;
561 }
562 String word = code.substr(i, pos - i);
563 if (keywords.has(word))
564 in_keyword = true;
565
566 } else if (!_is_text_char(c)) {
567 in_keyword = false;
568 }
569
570 if (in_keyword)
571 color = keyword_color;
572
573 Color ul = color;
574 ul.a *= 0.5;
575 img->set_pixel(col, y0 + line * 2, bg_color.blend(ul));
576 img->set_pixel(col, y0 + line * 2 + 1, color);
577
578 prev_is_text = _is_text_char(c);
579 }
580 } else {
581
582 prev_is_text = false;
583 in_keyword = false;
584
585 if (c == '\n') {
586 col = x0;
587 line++;
588 if (line >= available_height / 2)
589 break;
590 } else if (c == '\t') {
591 col += 3;
592 }
593 }
594 col++;
595 }
596
597 img->unlock();
598
599 post_process_preview(img);
600
601 Ref<ImageTexture> ptex = Ref<ImageTexture>(memnew(ImageTexture));
602
603 ptex->create_from_image(img, 0);
604 return ptex;
605 }
606
EditorScriptPreviewPlugin()607 EditorScriptPreviewPlugin::EditorScriptPreviewPlugin() {
608 }
609 ///////////////////////////////////////////////////////////////////
610
handles(const String & p_type) const611 bool EditorAudioStreamPreviewPlugin::handles(const String &p_type) const {
612
613 return ClassDB::is_parent_class(p_type, "AudioStream");
614 }
615
generate(const RES & p_from,const Size2 & p_size) const616 Ref<Texture> EditorAudioStreamPreviewPlugin::generate(const RES &p_from, const Size2 &p_size) const {
617
618 Ref<AudioStream> stream = p_from;
619 ERR_FAIL_COND_V(stream.is_null(), Ref<Texture>());
620
621 PoolVector<uint8_t> img;
622
623 int w = p_size.x;
624 int h = p_size.y;
625 img.resize(w * h * 3);
626
627 PoolVector<uint8_t>::Write imgdata = img.write();
628 uint8_t *imgw = imgdata.ptr();
629
630 Ref<AudioStreamPlayback> playback = stream->instance_playback();
631 ERR_FAIL_COND_V(playback.is_null(), Ref<Texture>());
632
633 float len_s = stream->get_length();
634 if (len_s == 0) {
635 len_s = 60; //one minute audio if no length specified
636 }
637 int frame_length = AudioServer::get_singleton()->get_mix_rate() * len_s;
638
639 Vector<AudioFrame> frames;
640 frames.resize(frame_length);
641
642 playback->start();
643 playback->mix(frames.ptrw(), 1, frames.size());
644 playback->stop();
645
646 for (int i = 0; i < w; i++) {
647
648 float max = -1000;
649 float min = 1000;
650 int from = uint64_t(i) * frame_length / w;
651 int to = (uint64_t(i) + 1) * frame_length / w;
652 to = MIN(to, frame_length);
653 from = MIN(from, frame_length - 1);
654 if (to == from) {
655 to = from + 1;
656 }
657
658 for (int j = from; j < to; j++) {
659
660 max = MAX(max, frames[j].l);
661 max = MAX(max, frames[j].r);
662
663 min = MIN(min, frames[j].l);
664 min = MIN(min, frames[j].r);
665 }
666
667 int pfrom = CLAMP((min * 0.5 + 0.5) * h / 2, 0, h / 2) + h / 4;
668 int pto = CLAMP((max * 0.5 + 0.5) * h / 2, 0, h / 2) + h / 4;
669
670 for (int j = 0; j < h; j++) {
671 uint8_t *p = &imgw[(j * w + i) * 3];
672 if (j < pfrom || j > pto) {
673 p[0] = 100;
674 p[1] = 100;
675 p[2] = 100;
676 } else {
677 p[0] = 180;
678 p[1] = 180;
679 p[2] = 180;
680 }
681 }
682 }
683
684 imgdata.release();
685 //post_process_preview(img);
686
687 Ref<ImageTexture> ptex = Ref<ImageTexture>(memnew(ImageTexture));
688 Ref<Image> image;
689 image.instance();
690 image->create(w, h, false, Image::FORMAT_RGB8, img);
691 ptex->create_from_image(image, 0);
692 return ptex;
693 }
694
EditorAudioStreamPreviewPlugin()695 EditorAudioStreamPreviewPlugin::EditorAudioStreamPreviewPlugin() {
696 }
697
698 ///////////////////////////////////////////////////////////////////////////
699
_preview_done(const Variant & p_udata)700 void EditorMeshPreviewPlugin::_preview_done(const Variant &p_udata) {
701
702 preview_done = true;
703 }
704
_bind_methods()705 void EditorMeshPreviewPlugin::_bind_methods() {
706
707 ClassDB::bind_method("_preview_done", &EditorMeshPreviewPlugin::_preview_done);
708 }
handles(const String & p_type) const709 bool EditorMeshPreviewPlugin::handles(const String &p_type) const {
710
711 return ClassDB::is_parent_class(p_type, "Mesh"); //any Mesh
712 }
713
generate(const RES & p_from,const Size2 & p_size) const714 Ref<Texture> EditorMeshPreviewPlugin::generate(const RES &p_from, const Size2 &p_size) const {
715
716 Ref<Mesh> mesh = p_from;
717 ERR_FAIL_COND_V(mesh.is_null(), Ref<Texture>());
718
719 VS::get_singleton()->instance_set_base(mesh_instance, mesh->get_rid());
720
721 AABB aabb = mesh->get_aabb();
722 Vector3 ofs = aabb.position + aabb.size * 0.5;
723 aabb.position -= ofs;
724 Transform xform;
725 xform.basis = Basis().rotated(Vector3(0, 1, 0), -Math_PI * 0.125);
726 xform.basis = Basis().rotated(Vector3(1, 0, 0), Math_PI * 0.125) * xform.basis;
727 AABB rot_aabb = xform.xform(aabb);
728 float m = MAX(rot_aabb.size.x, rot_aabb.size.y) * 0.5;
729 if (m == 0)
730 return Ref<Texture>();
731 m = 1.0 / m;
732 m *= 0.5;
733 xform.basis.scale(Vector3(m, m, m));
734 xform.origin = -xform.basis.xform(ofs); //-ofs*m;
735 xform.origin.z -= rot_aabb.size.z * 2;
736 VS::get_singleton()->instance_set_transform(mesh_instance, xform);
737
738 VS::get_singleton()->viewport_set_update_mode(viewport, VS::VIEWPORT_UPDATE_ONCE); //once used for capture
739
740 preview_done = false;
741 VS::get_singleton()->request_frame_drawn_callback(const_cast<EditorMeshPreviewPlugin *>(this), "_preview_done", Variant());
742
743 while (!preview_done) {
744 OS::get_singleton()->delay_usec(10);
745 }
746
747 Ref<Image> img = VS::get_singleton()->texture_get_data(viewport_texture);
748 ERR_FAIL_COND_V(img.is_null(), Ref<ImageTexture>());
749
750 VS::get_singleton()->instance_set_base(mesh_instance, RID());
751
752 img->convert(Image::FORMAT_RGBA8);
753
754 Vector2 new_size = img->get_size();
755 if (new_size.x > p_size.x) {
756 new_size = Vector2(p_size.x, new_size.y * p_size.x / new_size.x);
757 }
758 if (new_size.y > p_size.y) {
759 new_size = Vector2(new_size.x * p_size.y / new_size.y, p_size.y);
760 }
761 img->resize(new_size.x, new_size.y, Image::INTERPOLATE_CUBIC);
762
763 post_process_preview(img);
764
765 Ref<ImageTexture> ptex = Ref<ImageTexture>(memnew(ImageTexture));
766 ptex->create_from_image(img, 0);
767 return ptex;
768 }
769
EditorMeshPreviewPlugin()770 EditorMeshPreviewPlugin::EditorMeshPreviewPlugin() {
771
772 scenario = VS::get_singleton()->scenario_create();
773
774 viewport = VS::get_singleton()->viewport_create();
775 VS::get_singleton()->viewport_set_update_mode(viewport, VS::VIEWPORT_UPDATE_DISABLED);
776 VS::get_singleton()->viewport_set_vflip(viewport, true);
777 VS::get_singleton()->viewport_set_scenario(viewport, scenario);
778 VS::get_singleton()->viewport_set_size(viewport, 128, 128);
779 VS::get_singleton()->viewport_set_transparent_background(viewport, true);
780 VS::get_singleton()->viewport_set_active(viewport, true);
781 viewport_texture = VS::get_singleton()->viewport_get_texture(viewport);
782
783 camera = VS::get_singleton()->camera_create();
784 VS::get_singleton()->viewport_attach_camera(viewport, camera);
785 VS::get_singleton()->camera_set_transform(camera, Transform(Basis(), Vector3(0, 0, 3)));
786 //VS::get_singleton()->camera_set_perspective(camera,45,0.1,10);
787 VS::get_singleton()->camera_set_orthogonal(camera, 1.0, 0.01, 1000.0);
788
789 light = VS::get_singleton()->directional_light_create();
790 light_instance = VS::get_singleton()->instance_create2(light, scenario);
791 VS::get_singleton()->instance_set_transform(light_instance, Transform().looking_at(Vector3(-1, -1, -1), Vector3(0, 1, 0)));
792
793 light2 = VS::get_singleton()->directional_light_create();
794 VS::get_singleton()->light_set_color(light2, Color(0.7, 0.7, 0.7));
795 //VS::get_singleton()->light_set_color(light2, VS::LIGHT_COLOR_SPECULAR, Color(0.0, 0.0, 0.0));
796 light_instance2 = VS::get_singleton()->instance_create2(light2, scenario);
797
798 VS::get_singleton()->instance_set_transform(light_instance2, Transform().looking_at(Vector3(0, 1, 0), Vector3(0, 0, 1)));
799
800 //sphere = VS::get_singleton()->mesh_create();
801 mesh_instance = VS::get_singleton()->instance_create();
802 VS::get_singleton()->instance_set_scenario(mesh_instance, scenario);
803 }
804
~EditorMeshPreviewPlugin()805 EditorMeshPreviewPlugin::~EditorMeshPreviewPlugin() {
806
807 //VS::get_singleton()->free(sphere);
808 VS::get_singleton()->free(mesh_instance);
809 VS::get_singleton()->free(viewport);
810 VS::get_singleton()->free(light);
811 VS::get_singleton()->free(light_instance);
812 VS::get_singleton()->free(light2);
813 VS::get_singleton()->free(light_instance2);
814 VS::get_singleton()->free(camera);
815 VS::get_singleton()->free(scenario);
816 }
817
818 ///////////////////////////////////////////////////////////////////////////
819
_preview_done(const Variant & p_udata)820 void EditorFontPreviewPlugin::_preview_done(const Variant &p_udata) {
821
822 preview_done = true;
823 }
824
_bind_methods()825 void EditorFontPreviewPlugin::_bind_methods() {
826
827 ClassDB::bind_method("_preview_done", &EditorFontPreviewPlugin::_preview_done);
828 }
829
handles(const String & p_type) const830 bool EditorFontPreviewPlugin::handles(const String &p_type) const {
831
832 return ClassDB::is_parent_class(p_type, "DynamicFontData") || ClassDB::is_parent_class(p_type, "DynamicFont");
833 }
834
generate_from_path(const String & p_path,const Size2 & p_size) const835 Ref<Texture> EditorFontPreviewPlugin::generate_from_path(const String &p_path, const Size2 &p_size) const {
836
837 RES res = ResourceLoader::load(p_path);
838 Ref<DynamicFont> sampled_font;
839 if (res->is_class("DynamicFont")) {
840 sampled_font = res->duplicate();
841 if (sampled_font->get_outline_color() == Color(1, 1, 1, 1)) {
842 sampled_font->set_outline_color(Color(0, 0, 0, 1));
843 }
844 } else if (res->is_class("DynamicFontData")) {
845 sampled_font.instance();
846 sampled_font->set_font_data(res);
847 }
848 sampled_font->set_size(50);
849
850 String sampled_text = "Abg";
851 Vector2 size = sampled_font->get_string_size(sampled_text);
852
853 Vector2 pos;
854
855 pos.x = 64 - size.x / 2;
856 pos.y = 80;
857
858 Ref<Font> font = sampled_font;
859
860 font->draw(canvas_item, pos, sampled_text);
861
862 preview_done = false;
863 VS::get_singleton()->viewport_set_update_mode(viewport, VS::VIEWPORT_UPDATE_ONCE); //once used for capture
864 VS::get_singleton()->request_frame_drawn_callback(const_cast<EditorFontPreviewPlugin *>(this), "_preview_done", Variant());
865
866 while (!preview_done) {
867 OS::get_singleton()->delay_usec(10);
868 }
869
870 VS::get_singleton()->canvas_item_clear(canvas_item);
871
872 Ref<Image> img = VS::get_singleton()->texture_get_data(viewport_texture);
873 ERR_FAIL_COND_V(img.is_null(), Ref<ImageTexture>());
874
875 img->convert(Image::FORMAT_RGBA8);
876
877 Vector2 new_size = img->get_size();
878 if (new_size.x > p_size.x) {
879 new_size = Vector2(p_size.x, new_size.y * p_size.x / new_size.x);
880 }
881 if (new_size.y > p_size.y) {
882 new_size = Vector2(new_size.x * p_size.y / new_size.y, p_size.y);
883 }
884 img->resize(new_size.x, new_size.y, Image::INTERPOLATE_CUBIC);
885
886 post_process_preview(img);
887
888 Ref<ImageTexture> ptex = Ref<ImageTexture>(memnew(ImageTexture));
889 ptex->create_from_image(img, 0);
890
891 return ptex;
892 }
893
generate(const RES & p_from,const Size2 & p_size) const894 Ref<Texture> EditorFontPreviewPlugin::generate(const RES &p_from, const Size2 &p_size) const {
895
896 String path = p_from->get_path();
897 if (!FileAccess::exists(path)) {
898 return Ref<Texture>();
899 }
900 return generate_from_path(path, p_size);
901 }
902
EditorFontPreviewPlugin()903 EditorFontPreviewPlugin::EditorFontPreviewPlugin() {
904
905 viewport = VS::get_singleton()->viewport_create();
906 VS::get_singleton()->viewport_set_update_mode(viewport, VS::VIEWPORT_UPDATE_DISABLED);
907 VS::get_singleton()->viewport_set_vflip(viewport, true);
908 VS::get_singleton()->viewport_set_size(viewport, 128, 128);
909 VS::get_singleton()->viewport_set_active(viewport, true);
910 viewport_texture = VS::get_singleton()->viewport_get_texture(viewport);
911
912 canvas = VS::get_singleton()->canvas_create();
913 canvas_item = VS::get_singleton()->canvas_item_create();
914
915 VS::get_singleton()->viewport_attach_canvas(viewport, canvas);
916 VS::get_singleton()->canvas_item_set_parent(canvas_item, canvas);
917 }
918
~EditorFontPreviewPlugin()919 EditorFontPreviewPlugin::~EditorFontPreviewPlugin() {
920
921 VS::get_singleton()->free(canvas_item);
922 VS::get_singleton()->free(canvas);
923 VS::get_singleton()->free(viewport);
924 }
925