From b7cc2bb1e281b360fdbf4b845cfa61e3a5998ddb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Verschelde?= Date: Tue, 12 Feb 2019 13:30:56 +0100 Subject: Core: Ensure classes match their header filename Also drop some unused files. Renamed: - `core/dvector.h` -> `pool_vector.h` - `core/io/resource_import.h` -> `resource_importer.h` - `core/sort.h` -> `sort_array.h` - `core/string_db.h` -> `string_name.h` Dropped: - `core/allocators.h` - `core/os/shell.h` - `core/variant_construct_string.cpp` --- core/allocators.h | 195 ------- core/core_string_names.h | 2 +- core/dvector.cpp | 71 --- core/dvector.h | 643 ---------------------- core/global_constants.h | 2 +- core/hashfuncs.h | 2 +- core/image.h | 2 +- core/io/file_access_buffered.h | 2 +- core/io/file_access_buffered_fa.h | 2 +- core/io/resource_import.cpp | 373 ------------- core/io/resource_import.h | 113 ---- core/io/resource_importer.cpp | 373 +++++++++++++ core/io/resource_importer.h | 113 ++++ core/io/resource_loader.cpp | 2 +- core/list.h | 2 +- core/math/bsp_tree.h | 2 +- core/math/geometry.h | 2 +- core/math/triangle_mesh.cpp | 2 +- core/node_path.h | 2 +- core/os/shell.cpp | 46 -- core/os/shell.h | 52 -- core/pool_vector.cpp | 71 +++ core/pool_vector.h | 643 ++++++++++++++++++++++ core/register_core_types.cpp | 2 +- core/sort.h | 330 ----------- core/sort_array.h | 330 +++++++++++ core/string_db.cpp | 426 -------------- core/string_db.h | 172 ------ core/string_name.cpp | 426 ++++++++++++++ core/string_name.h | 172 ++++++ core/variant.h | 2 +- core/variant_construct_string.cpp | 438 --------------- core/vector.h | 2 +- drivers/gles2/rasterizer_storage_gles2.h | 2 +- drivers/windows/shell_windows.cpp | 67 --- drivers/windows/shell_windows.h | 52 -- editor/editor_file_system.cpp | 2 +- editor/import/editor_import_plugin.h | 2 +- editor/import/resource_importer_bitmask.h | 2 +- editor/import/resource_importer_csv_translation.h | 2 +- editor/import/resource_importer_image.h | 2 +- editor/import/resource_importer_layered_texture.h | 2 +- editor/import/resource_importer_scene.h | 2 +- editor/import/resource_importer_texture.h | 2 +- editor/import/resource_importer_wav.h | 2 +- editor/import_dock.h | 2 +- editor/plugins/spatial_editor_plugin.cpp | 2 +- modules/csg/csg.cpp | 2 +- modules/csg/csg.h | 2 +- modules/gdnative/gdnative/array.cpp | 2 +- modules/gdnative/gdnative/pool_arrays.cpp | 2 +- modules/gdnative/gdnative/string.cpp | 2 +- modules/gdnative/gdnative/string_name.cpp | 2 +- modules/gdscript/gdscript_function.h | 2 +- modules/gdscript/gdscript_tokenizer.h | 2 +- modules/mono/glue/base_object_glue.cpp | 2 +- modules/stb_vorbis/resource_importer_ogg_vorbis.h | 2 +- scene/scene_string_names.h | 2 +- servers/physics/shape_sw.cpp | 2 +- servers/physics_2d/shape_2d_sw.cpp | 2 +- servers/visual/shader_language.h | 2 +- servers/visual/visual_server_raster.cpp | 2 +- servers/visual/visual_server_raster.h | 1 - servers/visual/visual_server_scene.h | 2 - 64 files changed, 2170 insertions(+), 3023 deletions(-) delete mode 100644 core/allocators.h delete mode 100644 core/dvector.cpp delete mode 100644 core/dvector.h delete mode 100644 core/io/resource_import.cpp delete mode 100644 core/io/resource_import.h create mode 100644 core/io/resource_importer.cpp create mode 100644 core/io/resource_importer.h delete mode 100644 core/os/shell.cpp delete mode 100644 core/os/shell.h create mode 100644 core/pool_vector.cpp create mode 100644 core/pool_vector.h delete mode 100644 core/sort.h create mode 100644 core/sort_array.h delete mode 100644 core/string_db.cpp delete mode 100644 core/string_db.h create mode 100644 core/string_name.cpp create mode 100644 core/string_name.h delete mode 100644 core/variant_construct_string.cpp delete mode 100644 drivers/windows/shell_windows.cpp delete mode 100644 drivers/windows/shell_windows.h diff --git a/core/allocators.h b/core/allocators.h deleted file mode 100644 index 8d4af7a9fb..0000000000 --- a/core/allocators.h +++ /dev/null @@ -1,195 +0,0 @@ -/*************************************************************************/ -/* allocators.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#ifndef ALLOCATORS_H -#define ALLOCATORS_H - -#include "core/os/memory.h" - -template -class BalloonAllocator { - - enum { - - USED_FLAG = (1 << 30), - USED_MASK = USED_FLAG - 1 - }; - - struct Balloon { - - Balloon *next; - Balloon *prev; - uint32_t hand; - }; - - struct Hand { - - int used; - int allocated; - Balloon *first; - Balloon *last; - }; - - Hand hands[MAX_HANDS]; - -public: - void *alloc(size_t p_size) { - - size_t max = (1 << MAX_HANDS); - ERR_FAIL_COND_V(p_size > max, NULL); - - unsigned int hand = 0; - - while (p_size > (size_t)(1 << hand)) - ++hand; - - Hand &h = hands[hand]; - - if (h.used == h.allocated) { - - for (int i = 0; i < PREALLOC_COUNT; i++) { - - Balloon *b = (Balloon *)memalloc(sizeof(Balloon) + (1 << hand)); - b->hand = hand; - if (h.last) { - - b->prev = h.last; - h.last->next = b; - h.last = b; - } else { - - b->prev = NULL; - h.last = b; - h.first = b; - } - } - - h.last->next = NULL; - h.allocated += PREALLOC_COUNT; - } - - Balloon *pick = h.last; - - ERR_FAIL_COND_V((pick->hand & USED_FLAG), NULL); - - // remove last - h.last = h.last->prev; - h.last->next = NULL; - - pick->next = h.first; - h.first->prev = pick; - pick->prev = NULL; - h.first = pick; - h.used++; - pick->hand |= USED_FLAG; - - return (void *)(pick + 1); - } - - void free(void *p_ptr) { - - Balloon *b = (Balloon *)p_ptr; - b -= 1; - - ERR_FAIL_COND(!(b->hand & USED_FLAG)); - - b->hand = b->hand & USED_MASK; // not used - int hand = b->hand; - - Hand &h = hands[hand]; - - if (b == h.first) - h.first = b->next; - - if (b->prev) - b->prev->next = b->next; - if (b->next) - b->next->prev = b->prev; - - if (h.last != b) { - h.last->next = b; - b->prev = h.last; - b->next = NULL; - h.last = b; - } - - h.used--; - - if (h.used <= (h.allocated - (PREALLOC_COUNT * 2))) { // this is done to ensure no alloc/free is done constantly - - for (int i = 0; i < PREALLOC_COUNT; i++) { - ERR_CONTINUE(h.last->hand & USED_FLAG); - - Balloon *new_last = h.last->prev; - if (new_last) - new_last->next = NULL; - memfree(h.last); - h.last = new_last; - } - h.allocated -= PREALLOC_COUNT; - } - } - - BalloonAllocator() { - - for (int i = 0; i < MAX_HANDS; i++) { - - hands[i].allocated = 0; - hands[i].used = 0; - hands[i].first = NULL; - hands[i].last = NULL; - } - } - - void clear() { - - for (int i = 0; i < MAX_HANDS; i++) { - - while (hands[i].first) { - - Balloon *b = hands[i].first; - hands[i].first = b->next; - memfree(b); - } - - hands[i].allocated = 0; - hands[i].used = 0; - hands[i].first = NULL; - hands[i].last = NULL; - } - } - - ~BalloonAllocator() { - - clear(); - } -}; - -#endif // ALLOCATORS_H diff --git a/core/core_string_names.h b/core/core_string_names.h index 1a837cdc2e..6fea40e1b2 100644 --- a/core/core_string_names.h +++ b/core/core_string_names.h @@ -31,7 +31,7 @@ #ifndef CORE_STRING_NAMES_H #define CORE_STRING_NAMES_H -#include "core/string_db.h" +#include "core/string_name.h" class CoreStringNames { diff --git a/core/dvector.cpp b/core/dvector.cpp deleted file mode 100644 index 592c3c053d..0000000000 --- a/core/dvector.cpp +++ /dev/null @@ -1,71 +0,0 @@ -/*************************************************************************/ -/* dvector.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#include "dvector.h" - -Mutex *dvector_lock = NULL; - -PoolAllocator *MemoryPool::memory_pool = NULL; -uint8_t *MemoryPool::pool_memory = NULL; -size_t *MemoryPool::pool_size = NULL; - -MemoryPool::Alloc *MemoryPool::allocs = NULL; -MemoryPool::Alloc *MemoryPool::free_list = NULL; -uint32_t MemoryPool::alloc_count = 0; -uint32_t MemoryPool::allocs_used = 0; -Mutex *MemoryPool::alloc_mutex = NULL; - -size_t MemoryPool::total_memory = 0; -size_t MemoryPool::max_memory = 0; - -void MemoryPool::setup(uint32_t p_max_allocs) { - - allocs = memnew_arr(Alloc, p_max_allocs); - alloc_count = p_max_allocs; - allocs_used = 0; - - for (uint32_t i = 0; i < alloc_count - 1; i++) { - - allocs[i].free_list = &allocs[i + 1]; - } - - free_list = &allocs[0]; - - alloc_mutex = Mutex::create(); -} - -void MemoryPool::cleanup() { - - memdelete_arr(allocs); - memdelete(alloc_mutex); - - ERR_EXPLAINC("There are still MemoryPool allocs in use at exit!"); - ERR_FAIL_COND(allocs_used > 0); -} diff --git a/core/dvector.h b/core/dvector.h deleted file mode 100644 index fc962b4940..0000000000 --- a/core/dvector.h +++ /dev/null @@ -1,643 +0,0 @@ -/*************************************************************************/ -/* dvector.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#ifndef DVECTOR_H -#define DVECTOR_H - -#include "core/os/copymem.h" -#include "core/os/memory.h" -#include "core/os/rw_lock.h" -#include "core/pool_allocator.h" -#include "core/safe_refcount.h" -#include "core/ustring.h" - -struct MemoryPool { - - //avoid accessing these directly, must be public for template access - - static PoolAllocator *memory_pool; - static uint8_t *pool_memory; - static size_t *pool_size; - - struct Alloc { - - SafeRefCount refcount; - uint32_t lock; - void *mem; - PoolAllocator::ID pool_id; - size_t size; - - Alloc *free_list; - - Alloc() : - lock(0), - mem(NULL), - pool_id(POOL_ALLOCATOR_INVALID_ID), - size(0), - free_list(NULL) { - } - }; - - static Alloc *allocs; - static Alloc *free_list; - static uint32_t alloc_count; - static uint32_t allocs_used; - static Mutex *alloc_mutex; - static size_t total_memory; - static size_t max_memory; - - static void setup(uint32_t p_max_allocs = (1 << 16)); - static void cleanup(); -}; - -/** - @author Juan Linietsky -*/ - -template -class PoolVector { - - MemoryPool::Alloc *alloc; - - void _copy_on_write() { - - if (!alloc) - return; - - // ERR_FAIL_COND(alloc->lock>0); should not be illegal to lock this for copy on write, as it's a copy on write after all - - // Refcount should not be zero, otherwise it's a misuse of COW - if (alloc->refcount.get() == 1) - return; //nothing to do - - //must allocate something - - MemoryPool::alloc_mutex->lock(); - if (MemoryPool::allocs_used == MemoryPool::alloc_count) { - MemoryPool::alloc_mutex->unlock(); - ERR_EXPLAINC("All memory pool allocations are in use, can't COW."); - ERR_FAIL(); - } - - MemoryPool::Alloc *old_alloc = alloc; - - //take one from the free list - alloc = MemoryPool::free_list; - MemoryPool::free_list = alloc->free_list; - //increment the used counter - MemoryPool::allocs_used++; - - //copy the alloc data - alloc->size = old_alloc->size; - alloc->refcount.init(); - alloc->pool_id = POOL_ALLOCATOR_INVALID_ID; - alloc->lock = 0; - -#ifdef DEBUG_ENABLED - MemoryPool::total_memory += alloc->size; - if (MemoryPool::total_memory > MemoryPool::max_memory) { - MemoryPool::max_memory = MemoryPool::total_memory; - } -#endif - - MemoryPool::alloc_mutex->unlock(); - - if (MemoryPool::memory_pool) { - - } else { - alloc->mem = memalloc(alloc->size); - } - - { - Write w; - w._ref(alloc); - Read r; - r._ref(old_alloc); - - int cur_elements = alloc->size / sizeof(T); - T *dst = (T *)w.ptr(); - const T *src = (const T *)r.ptr(); - for (int i = 0; i < cur_elements; i++) { - memnew_placement(&dst[i], T(src[i])); - } - } - - if (old_alloc->refcount.unref()) { - //this should never happen but.. - -#ifdef DEBUG_ENABLED - MemoryPool::alloc_mutex->lock(); - MemoryPool::total_memory -= old_alloc->size; - MemoryPool::alloc_mutex->unlock(); -#endif - - { - Write w; - w._ref(old_alloc); - - int cur_elements = old_alloc->size / sizeof(T); - T *elems = (T *)w.ptr(); - for (int i = 0; i < cur_elements; i++) { - elems[i].~T(); - } - } - - if (MemoryPool::memory_pool) { - //resize memory pool - //if none, create - //if some resize - } else { - - memfree(old_alloc->mem); - old_alloc->mem = NULL; - old_alloc->size = 0; - - MemoryPool::alloc_mutex->lock(); - old_alloc->free_list = MemoryPool::free_list; - MemoryPool::free_list = old_alloc; - MemoryPool::allocs_used--; - MemoryPool::alloc_mutex->unlock(); - } - } - } - - void _reference(const PoolVector &p_dvector) { - - if (alloc == p_dvector.alloc) - return; - - _unreference(); - - if (!p_dvector.alloc) { - return; - } - - if (p_dvector.alloc->refcount.ref()) { - alloc = p_dvector.alloc; - } - } - - void _unreference() { - - if (!alloc) - return; - - if (!alloc->refcount.unref()) { - alloc = NULL; - return; - } - - //must be disposed! - - { - int cur_elements = alloc->size / sizeof(T); - - // Don't use write() here because it could otherwise provoke COW, - // which is not desirable here because we are destroying the last reference anyways - Write w; - // Reference to still prevent other threads from touching the alloc - w._ref(alloc); - - for (int i = 0; i < cur_elements; i++) { - - w[i].~T(); - } - } - -#ifdef DEBUG_ENABLED - MemoryPool::alloc_mutex->lock(); - MemoryPool::total_memory -= alloc->size; - MemoryPool::alloc_mutex->unlock(); -#endif - - if (MemoryPool::memory_pool) { - //resize memory pool - //if none, create - //if some resize - } else { - - memfree(alloc->mem); - alloc->mem = NULL; - alloc->size = 0; - - MemoryPool::alloc_mutex->lock(); - alloc->free_list = MemoryPool::free_list; - MemoryPool::free_list = alloc; - MemoryPool::allocs_used--; - MemoryPool::alloc_mutex->unlock(); - } - - alloc = NULL; - } - -public: - class Access { - friend class PoolVector; - - protected: - MemoryPool::Alloc *alloc; - T *mem; - - _FORCE_INLINE_ void _ref(MemoryPool::Alloc *p_alloc) { - alloc = p_alloc; - if (alloc) { - if (atomic_increment(&alloc->lock) == 1) { - if (MemoryPool::memory_pool) { - //lock it and get mem - } - } - - mem = (T *)alloc->mem; - } - } - - _FORCE_INLINE_ void _unref() { - - if (alloc) { - if (atomic_decrement(&alloc->lock) == 0) { - if (MemoryPool::memory_pool) { - //put mem back - } - } - - mem = NULL; - alloc = NULL; - } - } - - Access() { - alloc = NULL; - mem = NULL; - } - - public: - virtual ~Access() { - _unref(); - } - }; - - class Read : public Access { - public: - _FORCE_INLINE_ const T &operator[](int p_index) const { return this->mem[p_index]; } - _FORCE_INLINE_ const T *ptr() const { return this->mem; } - - void operator=(const Read &p_read) { - if (this->alloc == p_read.alloc) - return; - this->_unref(); - this->_ref(p_read.alloc); - } - - Read(const Read &p_read) { - this->_ref(p_read.alloc); - } - - Read() {} - }; - - class Write : public Access { - public: - _FORCE_INLINE_ T &operator[](int p_index) const { return this->mem[p_index]; } - _FORCE_INLINE_ T *ptr() const { return this->mem; } - - void operator=(const Write &p_read) { - if (this->alloc == p_read.alloc) - return; - this->_unref(); - this->_ref(p_read.alloc); - } - - Write(const Write &p_read) { - this->_ref(p_read.alloc); - } - - Write() {} - }; - - Read read() const { - - Read r; - if (alloc) { - r._ref(alloc); - } - return r; - } - Write write() { - - Write w; - if (alloc) { - _copy_on_write(); //make sure there is only one being acessed - w._ref(alloc); - } - return w; - } - - template - void fill_with(const MC &p_mc) { - - int c = p_mc.size(); - resize(c); - Write w = write(); - int idx = 0; - for (const typename MC::Element *E = p_mc.front(); E; E = E->next()) { - - w[idx++] = E->get(); - } - } - - void remove(int p_index) { - - int s = size(); - ERR_FAIL_INDEX(p_index, s); - Write w = write(); - for (int i = p_index; i < s - 1; i++) { - - w[i] = w[i + 1]; - }; - w = Write(); - resize(s - 1); - } - - inline int size() const; - T get(int p_index) const; - void set(int p_index, const T &p_val); - void push_back(const T &p_val); - void append(const T &p_val) { push_back(p_val); } - void append_array(const PoolVector &p_arr) { - int ds = p_arr.size(); - if (ds == 0) - return; - int bs = size(); - resize(bs + ds); - Write w = write(); - Read r = p_arr.read(); - for (int i = 0; i < ds; i++) - w[bs + i] = r[i]; - } - - PoolVector subarray(int p_from, int p_to) { - - if (p_from < 0) { - p_from = size() + p_from; - } - if (p_to < 0) { - p_to = size() + p_to; - } - - CRASH_BAD_INDEX(p_from, size()); - CRASH_BAD_INDEX(p_to, size()); - - PoolVector slice; - int span = 1 + p_to - p_from; - slice.resize(span); - Read r = read(); - Write w = slice.write(); - for (int i = 0; i < span; ++i) { - w[i] = r[p_from + i]; - } - - return slice; - } - - Error insert(int p_pos, const T &p_val) { - - int s = size(); - ERR_FAIL_INDEX_V(p_pos, s + 1, ERR_INVALID_PARAMETER); - resize(s + 1); - { - Write w = write(); - for (int i = s; i > p_pos; i--) - w[i] = w[i - 1]; - w[p_pos] = p_val; - } - - return OK; - } - - String join(String delimiter) { - String rs = ""; - int s = size(); - Read r = read(); - for (int i = 0; i < s; i++) { - rs += r[i] + delimiter; - } - rs.erase(rs.length() - delimiter.length(), delimiter.length()); - return rs; - } - - bool is_locked() const { return alloc && alloc->lock > 0; } - - inline const T operator[](int p_index) const; - - Error resize(int p_size); - - void invert(); - - void operator=(const PoolVector &p_dvector) { _reference(p_dvector); } - PoolVector() { alloc = NULL; } - PoolVector(const PoolVector &p_dvector) { - alloc = NULL; - _reference(p_dvector); - } - ~PoolVector() { _unreference(); } -}; - -template -int PoolVector::size() const { - - return alloc ? alloc->size / sizeof(T) : 0; -} - -template -T PoolVector::get(int p_index) const { - - return operator[](p_index); -} - -template -void PoolVector::set(int p_index, const T &p_val) { - - if (p_index < 0 || p_index >= size()) { - ERR_FAIL_COND(p_index < 0 || p_index >= size()); - } - - Write w = write(); - w[p_index] = p_val; -} - -template -void PoolVector::push_back(const T &p_val) { - - resize(size() + 1); - set(size() - 1, p_val); -} - -template -const T PoolVector::operator[](int p_index) const { - - CRASH_BAD_INDEX(p_index, size()); - - Read r = read(); - return r[p_index]; -} - -template -Error PoolVector::resize(int p_size) { - - if (alloc == NULL) { - - if (p_size == 0) - return OK; //nothing to do here - - //must allocate something - MemoryPool::alloc_mutex->lock(); - if (MemoryPool::allocs_used == MemoryPool::alloc_count) { - MemoryPool::alloc_mutex->unlock(); - ERR_EXPLAINC("All memory pool allocations are in use."); - ERR_FAIL_V(ERR_OUT_OF_MEMORY); - } - - //take one from the free list - alloc = MemoryPool::free_list; - MemoryPool::free_list = alloc->free_list; - //increment the used counter - MemoryPool::allocs_used++; - - //cleanup the alloc - alloc->size = 0; - alloc->refcount.init(); - alloc->pool_id = POOL_ALLOCATOR_INVALID_ID; - MemoryPool::alloc_mutex->unlock(); - - } else { - - ERR_FAIL_COND_V(alloc->lock > 0, ERR_LOCKED); //can't resize if locked! - } - - size_t new_size = sizeof(T) * p_size; - - if (alloc->size == new_size) - return OK; //nothing to do - - if (p_size == 0) { - _unreference(); - return OK; - } - - _copy_on_write(); // make it unique - -#ifdef DEBUG_ENABLED - MemoryPool::alloc_mutex->lock(); - MemoryPool::total_memory -= alloc->size; - MemoryPool::total_memory += new_size; - if (MemoryPool::total_memory > MemoryPool::max_memory) { - MemoryPool::max_memory = MemoryPool::total_memory; - } - MemoryPool::alloc_mutex->unlock(); -#endif - - int cur_elements = alloc->size / sizeof(T); - - if (p_size > cur_elements) { - - if (MemoryPool::memory_pool) { - //resize memory pool - //if none, create - //if some resize - } else { - - if (alloc->size == 0) { - alloc->mem = memalloc(new_size); - } else { - alloc->mem = memrealloc(alloc->mem, new_size); - } - } - - alloc->size = new_size; - - Write w = write(); - - for (int i = cur_elements; i < p_size; i++) { - - memnew_placement(&w[i], T); - } - - } else { - - { - Write w = write(); - for (int i = p_size; i < cur_elements; i++) { - - w[i].~T(); - } - } - - if (MemoryPool::memory_pool) { - //resize memory pool - //if none, create - //if some resize - } else { - - if (new_size == 0) { - memfree(alloc->mem); - alloc->mem = NULL; - alloc->size = 0; - - MemoryPool::alloc_mutex->lock(); - alloc->free_list = MemoryPool::free_list; - MemoryPool::free_list = alloc; - MemoryPool::allocs_used--; - MemoryPool::alloc_mutex->unlock(); - - } else { - alloc->mem = memrealloc(alloc->mem, new_size); - alloc->size = new_size; - } - } - } - - return OK; -} - -template -void PoolVector::invert() { - T temp; - Write w = write(); - int s = size(); - int half_s = s / 2; - - for (int i = 0; i < half_s; i++) { - temp = w[i]; - w[i] = w[s - i - 1]; - w[s - i - 1] = temp; - } -} - -#endif diff --git a/core/global_constants.h b/core/global_constants.h index 47c1a4dafc..c798a3b9bc 100644 --- a/core/global_constants.h +++ b/core/global_constants.h @@ -31,7 +31,7 @@ #ifndef GLOBAL_CONSTANTS_H #define GLOBAL_CONSTANTS_H -#include "core/string_db.h" +#include "core/string_name.h" class GlobalConstants { public: diff --git a/core/hashfuncs.h b/core/hashfuncs.h index 811ce6264e..07d78dcbde 100644 --- a/core/hashfuncs.h +++ b/core/hashfuncs.h @@ -34,7 +34,7 @@ #include "core/math/math_defs.h" #include "core/math/math_funcs.h" #include "core/node_path.h" -#include "core/string_db.h" +#include "core/string_name.h" #include "core/typedefs.h" #include "core/ustring.h" diff --git a/core/image.h b/core/image.h index b23f8cac46..872b84d565 100644 --- a/core/image.h +++ b/core/image.h @@ -32,8 +32,8 @@ #define IMAGE_H #include "core/color.h" -#include "core/dvector.h" #include "core/math/rect2.h" +#include "core/pool_vector.h" #include "core/resource.h" /** diff --git a/core/io/file_access_buffered.h b/core/io/file_access_buffered.h index 756045a674..4065d77c58 100644 --- a/core/io/file_access_buffered.h +++ b/core/io/file_access_buffered.h @@ -31,8 +31,8 @@ #ifndef FILE_ACCESS_BUFFERED_H #define FILE_ACCESS_BUFFERED_H -#include "core/dvector.h" #include "core/os/file_access.h" +#include "core/pool_vector.h" #include "core/ustring.h" class FileAccessBuffered : public FileAccess { diff --git a/core/io/file_access_buffered_fa.h b/core/io/file_access_buffered_fa.h index 5180f2344f..be960fbc25 100644 --- a/core/io/file_access_buffered_fa.h +++ b/core/io/file_access_buffered_fa.h @@ -54,7 +54,7 @@ class FileAccessBufferedFA : public FileAccessBuffered { cache.offset = p_offset; cache.buffer.resize(p_size); - // on dvector + // on PoolVector //PoolVector::Write write = cache.buffer.write(); //f.get_buffer(write.ptrw(), p_size); diff --git a/core/io/resource_import.cpp b/core/io/resource_import.cpp deleted file mode 100644 index 63dc0b6a26..0000000000 --- a/core/io/resource_import.cpp +++ /dev/null @@ -1,373 +0,0 @@ -/*************************************************************************/ -/* resource_import.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#include "resource_import.h" - -#include "core/os/os.h" -#include "core/variant_parser.h" - -Error ResourceFormatImporter::_get_path_and_type(const String &p_path, PathAndType &r_path_and_type, bool *r_valid) const { - - Error err; - FileAccess *f = FileAccess::open(p_path + ".import", FileAccess::READ, &err); - - if (!f) { - if (r_valid) { - *r_valid = false; - } - return err; - } - - VariantParser::StreamFile stream; - stream.f = f; - - String assign; - Variant value; - VariantParser::Tag next_tag; - - if (r_valid) { - *r_valid = true; - } - - int lines = 0; - String error_text; - bool path_found = false; //first match must have priority - while (true) { - - assign = Variant(); - next_tag.fields.clear(); - next_tag.name = String(); - - err = VariantParser::parse_tag_assign_eof(&stream, lines, error_text, next_tag, assign, value, NULL, true); - if (err == ERR_FILE_EOF) { - memdelete(f); - return OK; - } else if (err != OK) { - ERR_PRINTS("ResourceFormatImporter::load - " + p_path + ".import:" + itos(lines) + " error: " + error_text); - memdelete(f); - return err; - } - - if (assign != String()) { - if (!path_found && assign.begins_with("path.") && r_path_and_type.path == String()) { - String feature = assign.get_slicec('.', 1); - if (OS::get_singleton()->has_feature(feature)) { - r_path_and_type.path = value; - path_found = true; //first match must have priority - } - - } else if (!path_found && assign == "path") { - r_path_and_type.path = value; - path_found = true; //first match must have priority - } else if (assign == "type") { - r_path_and_type.type = value; - } else if (assign == "importer") { - r_path_and_type.importer = value; - } else if (assign == "valid") { - if (r_valid) { - *r_valid = value; - } - } - - } else if (next_tag.name != "remap") { - break; - } - } - - memdelete(f); - - if (r_path_and_type.path == String() || r_path_and_type.type == String()) { - return ERR_FILE_CORRUPT; - } - return OK; -} - -RES ResourceFormatImporter::load(const String &p_path, const String &p_original_path, Error *r_error) { - - PathAndType pat; - Error err = _get_path_and_type(p_path, pat); - - if (err != OK) { - - if (r_error) - *r_error = err; - - return RES(); - } - - RES res = ResourceLoader::_load(pat.path, p_path, pat.type, false, r_error); - -#ifdef TOOLS_ENABLED - if (res.is_valid()) { - res->set_import_last_modified_time(res->get_last_modified_time()); //pass this, if used - res->set_import_path(pat.path); - } -#endif - - return res; -} - -void ResourceFormatImporter::get_recognized_extensions(List *p_extensions) const { - - Set found; - - for (int i = 0; i < importers.size(); i++) { - List local_exts; - importers[i]->get_recognized_extensions(&local_exts); - for (List::Element *F = local_exts.front(); F; F = F->next()) { - if (!found.has(F->get())) { - p_extensions->push_back(F->get()); - found.insert(F->get()); - } - } - } -} - -void ResourceFormatImporter::get_recognized_extensions_for_type(const String &p_type, List *p_extensions) const { - - if (p_type == "") { - return get_recognized_extensions(p_extensions); - } - - Set found; - - for (int i = 0; i < importers.size(); i++) { - String res_type = importers[i]->get_resource_type(); - if (res_type == String()) - continue; - - if (!ClassDB::is_parent_class(res_type, p_type)) - continue; - - List local_exts; - importers[i]->get_recognized_extensions(&local_exts); - for (List::Element *F = local_exts.front(); F; F = F->next()) { - if (!found.has(F->get())) { - p_extensions->push_back(F->get()); - found.insert(F->get()); - } - } - } -} - -bool ResourceFormatImporter::recognize_path(const String &p_path, const String &p_for_type) const { - - return FileAccess::exists(p_path + ".import"); -} - -bool ResourceFormatImporter::can_be_imported(const String &p_path) const { - - return ResourceFormatLoader::recognize_path(p_path); -} - -int ResourceFormatImporter::get_import_order(const String &p_path) const { - - Ref importer; - - if (FileAccess::exists(p_path + ".import")) { - - PathAndType pat; - Error err = _get_path_and_type(p_path, pat); - - if (err == OK) { - importer = get_importer_by_name(pat.importer); - } - } else { - - importer = get_importer_by_extension(p_path.get_extension().to_lower()); - } - - if (importer.is_valid()) - return importer->get_import_order(); - - return 0; -} - -bool ResourceFormatImporter::handles_type(const String &p_type) const { - - for (int i = 0; i < importers.size(); i++) { - - String res_type = importers[i]->get_resource_type(); - if (res_type == String()) - continue; - if (ClassDB::is_parent_class(res_type, p_type)) - return true; - } - - return true; -} - -String ResourceFormatImporter::get_internal_resource_path(const String &p_path) const { - - PathAndType pat; - Error err = _get_path_and_type(p_path, pat); - - if (err != OK) { - - return String(); - } - - return pat.path; -} - -void ResourceFormatImporter::get_internal_resource_path_list(const String &p_path, List *r_paths) { - - Error err; - FileAccess *f = FileAccess::open(p_path + ".import", FileAccess::READ, &err); - - if (!f) - return; - - VariantParser::StreamFile stream; - stream.f = f; - - String assign; - Variant value; - VariantParser::Tag next_tag; - - int lines = 0; - String error_text; - while (true) { - - assign = Variant(); - next_tag.fields.clear(); - next_tag.name = String(); - - err = VariantParser::parse_tag_assign_eof(&stream, lines, error_text, next_tag, assign, value, NULL, true); - if (err == ERR_FILE_EOF) { - memdelete(f); - return; - } else if (err != OK) { - ERR_PRINTS("ResourceFormatImporter::get_internal_resource_path_list - " + p_path + ".import:" + itos(lines) + " error: " + error_text); - memdelete(f); - return; - } - - if (assign != String()) { - if (assign.begins_with("path.")) { - r_paths->push_back(value); - } else if (assign == "path") { - r_paths->push_back(value); - } - } else if (next_tag.name != "remap") { - break; - } - } - memdelete(f); -} - -bool ResourceFormatImporter::is_import_valid(const String &p_path) const { - - bool valid = true; - PathAndType pat; - _get_path_and_type(p_path, pat, &valid); - return valid; -} - -String ResourceFormatImporter::get_resource_type(const String &p_path) const { - - PathAndType pat; - Error err = _get_path_and_type(p_path, pat); - - if (err != OK) { - - return ""; - } - - return pat.type; -} - -void ResourceFormatImporter::get_dependencies(const String &p_path, List *p_dependencies, bool p_add_types) { - - PathAndType pat; - Error err = _get_path_and_type(p_path, pat); - - if (err != OK) { - - return; - } - - return ResourceLoader::get_dependencies(pat.path, p_dependencies, p_add_types); -} - -Ref ResourceFormatImporter::get_importer_by_name(const String &p_name) const { - - for (int i = 0; i < importers.size(); i++) { - if (importers[i]->get_importer_name() == p_name) { - return importers[i]; - } - } - - return Ref(); -} - -void ResourceFormatImporter::get_importers_for_extension(const String &p_extension, List > *r_importers) { - - for (int i = 0; i < importers.size(); i++) { - List local_exts; - importers[i]->get_recognized_extensions(&local_exts); - for (List::Element *F = local_exts.front(); F; F = F->next()) { - if (p_extension.to_lower() == F->get()) { - r_importers->push_back(importers[i]); - } - } - } -} - -Ref ResourceFormatImporter::get_importer_by_extension(const String &p_extension) const { - - Ref importer; - float priority = 0; - - for (int i = 0; i < importers.size(); i++) { - - List local_exts; - importers[i]->get_recognized_extensions(&local_exts); - for (List::Element *F = local_exts.front(); F; F = F->next()) { - if (p_extension.to_lower() == F->get() && importers[i]->get_priority() > priority) { - importer = importers[i]; - priority = importers[i]->get_priority(); - } - } - } - - return importer; -} - -String ResourceFormatImporter::get_import_base_path(const String &p_for_file) const { - - return "res://.import/" + p_for_file.get_file() + "-" + p_for_file.md5_text(); -} - -ResourceFormatImporter *ResourceFormatImporter::singleton = NULL; - -ResourceFormatImporter::ResourceFormatImporter() { - singleton = this; -} diff --git a/core/io/resource_import.h b/core/io/resource_import.h deleted file mode 100644 index 96dd7983e6..0000000000 --- a/core/io/resource_import.h +++ /dev/null @@ -1,113 +0,0 @@ -/*************************************************************************/ -/* resource_import.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#ifndef RESOURCE_IMPORT_H -#define RESOURCE_IMPORT_H - -#include "core/io/resource_loader.h" - -class ResourceImporter; - -class ResourceFormatImporter : public ResourceFormatLoader { - - GDCLASS(ResourceFormatImporter, ResourceFormatLoader) - - struct PathAndType { - String path; - String type; - String importer; - }; - - Error _get_path_and_type(const String &p_path, PathAndType &r_path_and_type, bool *r_valid = NULL) const; - - static ResourceFormatImporter *singleton; - - Vector > importers; - -public: - static ResourceFormatImporter *get_singleton() { return singleton; } - virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = NULL); - virtual void get_recognized_extensions(List *p_extensions) const; - virtual void get_recognized_extensions_for_type(const String &p_type, List *p_extensions) const; - virtual bool recognize_path(const String &p_path, const String &p_for_type = String()) const; - virtual bool handles_type(const String &p_type) const; - virtual String get_resource_type(const String &p_path) const; - virtual bool is_import_valid(const String &p_path) const; - virtual void get_dependencies(const String &p_path, List *p_dependencies, bool p_add_types = false); - - virtual bool can_be_imported(const String &p_path) const; - virtual int get_import_order(const String &p_path) const; - - String get_internal_resource_path(const String &p_path) const; - void get_internal_resource_path_list(const String &p_path, List *r_paths); - - void add_importer(const Ref &p_importer) { importers.push_back(p_importer); } - void remove_importer(const Ref &p_importer) { importers.erase(p_importer); } - Ref get_importer_by_name(const String &p_name) const; - Ref get_importer_by_extension(const String &p_extension) const; - void get_importers_for_extension(const String &p_extension, List > *r_importers); - - String get_import_base_path(const String &p_for_file) const; - ResourceFormatImporter(); -}; - -class ResourceImporter : public Reference { - - GDCLASS(ResourceImporter, Reference) -public: - virtual String get_importer_name() const = 0; - virtual String get_visible_name() const = 0; - virtual void get_recognized_extensions(List *p_extensions) const = 0; - virtual String get_save_extension() const = 0; - virtual String get_resource_type() const = 0; - virtual float get_priority() const { return 1.0; } - virtual int get_import_order() const { return 0; } - - struct ImportOption { - PropertyInfo option; - Variant default_value; - - ImportOption(const PropertyInfo &p_info, const Variant &p_default) : - option(p_info), - default_value(p_default) { - } - ImportOption() {} - }; - - virtual int get_preset_count() const { return 0; } - virtual String get_preset_name(int p_idx) const { return String(); } - - virtual void get_import_options(List *r_options, int p_preset = 0) const = 0; - virtual bool get_option_visibility(const String &p_option, const Map &p_options) const = 0; - - virtual Error import(const String &p_source_file, const String &p_save_path, const Map &p_options, List *r_platform_variants, List *r_gen_files = NULL) = 0; -}; - -#endif // RESOURCE_IMPORT_H diff --git a/core/io/resource_importer.cpp b/core/io/resource_importer.cpp new file mode 100644 index 0000000000..9327e000f5 --- /dev/null +++ b/core/io/resource_importer.cpp @@ -0,0 +1,373 @@ +/*************************************************************************/ +/* resource_importer.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "resource_importer.h" + +#include "core/os/os.h" +#include "core/variant_parser.h" + +Error ResourceFormatImporter::_get_path_and_type(const String &p_path, PathAndType &r_path_and_type, bool *r_valid) const { + + Error err; + FileAccess *f = FileAccess::open(p_path + ".import", FileAccess::READ, &err); + + if (!f) { + if (r_valid) { + *r_valid = false; + } + return err; + } + + VariantParser::StreamFile stream; + stream.f = f; + + String assign; + Variant value; + VariantParser::Tag next_tag; + + if (r_valid) { + *r_valid = true; + } + + int lines = 0; + String error_text; + bool path_found = false; //first match must have priority + while (true) { + + assign = Variant(); + next_tag.fields.clear(); + next_tag.name = String(); + + err = VariantParser::parse_tag_assign_eof(&stream, lines, error_text, next_tag, assign, value, NULL, true); + if (err == ERR_FILE_EOF) { + memdelete(f); + return OK; + } else if (err != OK) { + ERR_PRINTS("ResourceFormatImporter::load - " + p_path + ".import:" + itos(lines) + " error: " + error_text); + memdelete(f); + return err; + } + + if (assign != String()) { + if (!path_found && assign.begins_with("path.") && r_path_and_type.path == String()) { + String feature = assign.get_slicec('.', 1); + if (OS::get_singleton()->has_feature(feature)) { + r_path_and_type.path = value; + path_found = true; //first match must have priority + } + + } else if (!path_found && assign == "path") { + r_path_and_type.path = value; + path_found = true; //first match must have priority + } else if (assign == "type") { + r_path_and_type.type = value; + } else if (assign == "importer") { + r_path_and_type.importer = value; + } else if (assign == "valid") { + if (r_valid) { + *r_valid = value; + } + } + + } else if (next_tag.name != "remap") { + break; + } + } + + memdelete(f); + + if (r_path_and_type.path == String() || r_path_and_type.type == String()) { + return ERR_FILE_CORRUPT; + } + return OK; +} + +RES ResourceFormatImporter::load(const String &p_path, const String &p_original_path, Error *r_error) { + + PathAndType pat; + Error err = _get_path_and_type(p_path, pat); + + if (err != OK) { + + if (r_error) + *r_error = err; + + return RES(); + } + + RES res = ResourceLoader::_load(pat.path, p_path, pat.type, false, r_error); + +#ifdef TOOLS_ENABLED + if (res.is_valid()) { + res->set_import_last_modified_time(res->get_last_modified_time()); //pass this, if used + res->set_import_path(pat.path); + } +#endif + + return res; +} + +void ResourceFormatImporter::get_recognized_extensions(List *p_extensions) const { + + Set found; + + for (int i = 0; i < importers.size(); i++) { + List local_exts; + importers[i]->get_recognized_extensions(&local_exts); + for (List::Element *F = local_exts.front(); F; F = F->next()) { + if (!found.has(F->get())) { + p_extensions->push_back(F->get()); + found.insert(F->get()); + } + } + } +} + +void ResourceFormatImporter::get_recognized_extensions_for_type(const String &p_type, List *p_extensions) const { + + if (p_type == "") { + return get_recognized_extensions(p_extensions); + } + + Set found; + + for (int i = 0; i < importers.size(); i++) { + String res_type = importers[i]->get_resource_type(); + if (res_type == String()) + continue; + + if (!ClassDB::is_parent_class(res_type, p_type)) + continue; + + List local_exts; + importers[i]->get_recognized_extensions(&local_exts); + for (List::Element *F = local_exts.front(); F; F = F->next()) { + if (!found.has(F->get())) { + p_extensions->push_back(F->get()); + found.insert(F->get()); + } + } + } +} + +bool ResourceFormatImporter::recognize_path(const String &p_path, const String &p_for_type) const { + + return FileAccess::exists(p_path + ".import"); +} + +bool ResourceFormatImporter::can_be_imported(const String &p_path) const { + + return ResourceFormatLoader::recognize_path(p_path); +} + +int ResourceFormatImporter::get_import_order(const String &p_path) const { + + Ref importer; + + if (FileAccess::exists(p_path + ".import")) { + + PathAndType pat; + Error err = _get_path_and_type(p_path, pat); + + if (err == OK) { + importer = get_importer_by_name(pat.importer); + } + } else { + + importer = get_importer_by_extension(p_path.get_extension().to_lower()); + } + + if (importer.is_valid()) + return importer->get_import_order(); + + return 0; +} + +bool ResourceFormatImporter::handles_type(const String &p_type) const { + + for (int i = 0; i < importers.size(); i++) { + + String res_type = importers[i]->get_resource_type(); + if (res_type == String()) + continue; + if (ClassDB::is_parent_class(res_type, p_type)) + return true; + } + + return true; +} + +String ResourceFormatImporter::get_internal_resource_path(const String &p_path) const { + + PathAndType pat; + Error err = _get_path_and_type(p_path, pat); + + if (err != OK) { + + return String(); + } + + return pat.path; +} + +void ResourceFormatImporter::get_internal_resource_path_list(const String &p_path, List *r_paths) { + + Error err; + FileAccess *f = FileAccess::open(p_path + ".import", FileAccess::READ, &err); + + if (!f) + return; + + VariantParser::StreamFile stream; + stream.f = f; + + String assign; + Variant value; + VariantParser::Tag next_tag; + + int lines = 0; + String error_text; + while (true) { + + assign = Variant(); + next_tag.fields.clear(); + next_tag.name = String(); + + err = VariantParser::parse_tag_assign_eof(&stream, lines, error_text, next_tag, assign, value, NULL, true); + if (err == ERR_FILE_EOF) { + memdelete(f); + return; + } else if (err != OK) { + ERR_PRINTS("ResourceFormatImporter::get_internal_resource_path_list - " + p_path + ".import:" + itos(lines) + " error: " + error_text); + memdelete(f); + return; + } + + if (assign != String()) { + if (assign.begins_with("path.")) { + r_paths->push_back(value); + } else if (assign == "path") { + r_paths->push_back(value); + } + } else if (next_tag.name != "remap") { + break; + } + } + memdelete(f); +} + +bool ResourceFormatImporter::is_import_valid(const String &p_path) const { + + bool valid = true; + PathAndType pat; + _get_path_and_type(p_path, pat, &valid); + return valid; +} + +String ResourceFormatImporter::get_resource_type(const String &p_path) const { + + PathAndType pat; + Error err = _get_path_and_type(p_path, pat); + + if (err != OK) { + + return ""; + } + + return pat.type; +} + +void ResourceFormatImporter::get_dependencies(const String &p_path, List *p_dependencies, bool p_add_types) { + + PathAndType pat; + Error err = _get_path_and_type(p_path, pat); + + if (err != OK) { + + return; + } + + return ResourceLoader::get_dependencies(pat.path, p_dependencies, p_add_types); +} + +Ref ResourceFormatImporter::get_importer_by_name(const String &p_name) const { + + for (int i = 0; i < importers.size(); i++) { + if (importers[i]->get_importer_name() == p_name) { + return importers[i]; + } + } + + return Ref(); +} + +void ResourceFormatImporter::get_importers_for_extension(const String &p_extension, List > *r_importers) { + + for (int i = 0; i < importers.size(); i++) { + List local_exts; + importers[i]->get_recognized_extensions(&local_exts); + for (List::Element *F = local_exts.front(); F; F = F->next()) { + if (p_extension.to_lower() == F->get()) { + r_importers->push_back(importers[i]); + } + } + } +} + +Ref ResourceFormatImporter::get_importer_by_extension(const String &p_extension) const { + + Ref importer; + float priority = 0; + + for (int i = 0; i < importers.size(); i++) { + + List local_exts; + importers[i]->get_recognized_extensions(&local_exts); + for (List::Element *F = local_exts.front(); F; F = F->next()) { + if (p_extension.to_lower() == F->get() && importers[i]->get_priority() > priority) { + importer = importers[i]; + priority = importers[i]->get_priority(); + } + } + } + + return importer; +} + +String ResourceFormatImporter::get_import_base_path(const String &p_for_file) const { + + return "res://.import/" + p_for_file.get_file() + "-" + p_for_file.md5_text(); +} + +ResourceFormatImporter *ResourceFormatImporter::singleton = NULL; + +ResourceFormatImporter::ResourceFormatImporter() { + singleton = this; +} diff --git a/core/io/resource_importer.h b/core/io/resource_importer.h new file mode 100644 index 0000000000..32c39a8085 --- /dev/null +++ b/core/io/resource_importer.h @@ -0,0 +1,113 @@ +/*************************************************************************/ +/* resource_importer.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef RESOURCE_IMPORTER_H +#define RESOURCE_IMPORTER_H + +#include "core/io/resource_loader.h" + +class ResourceImporter; + +class ResourceFormatImporter : public ResourceFormatLoader { + + GDCLASS(ResourceFormatImporter, ResourceFormatLoader) + + struct PathAndType { + String path; + String type; + String importer; + }; + + Error _get_path_and_type(const String &p_path, PathAndType &r_path_and_type, bool *r_valid = NULL) const; + + static ResourceFormatImporter *singleton; + + Vector > importers; + +public: + static ResourceFormatImporter *get_singleton() { return singleton; } + virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = NULL); + virtual void get_recognized_extensions(List *p_extensions) const; + virtual void get_recognized_extensions_for_type(const String &p_type, List *p_extensions) const; + virtual bool recognize_path(const String &p_path, const String &p_for_type = String()) const; + virtual bool handles_type(const String &p_type) const; + virtual String get_resource_type(const String &p_path) const; + virtual bool is_import_valid(const String &p_path) const; + virtual void get_dependencies(const String &p_path, List *p_dependencies, bool p_add_types = false); + + virtual bool can_be_imported(const String &p_path) const; + virtual int get_import_order(const String &p_path) const; + + String get_internal_resource_path(const String &p_path) const; + void get_internal_resource_path_list(const String &p_path, List *r_paths); + + void add_importer(const Ref &p_importer) { importers.push_back(p_importer); } + void remove_importer(const Ref &p_importer) { importers.erase(p_importer); } + Ref get_importer_by_name(const String &p_name) const; + Ref get_importer_by_extension(const String &p_extension) const; + void get_importers_for_extension(const String &p_extension, List > *r_importers); + + String get_import_base_path(const String &p_for_file) const; + ResourceFormatImporter(); +}; + +class ResourceImporter : public Reference { + + GDCLASS(ResourceImporter, Reference) +public: + virtual String get_importer_name() const = 0; + virtual String get_visible_name() const = 0; + virtual void get_recognized_extensions(List *p_extensions) const = 0; + virtual String get_save_extension() const = 0; + virtual String get_resource_type() const = 0; + virtual float get_priority() const { return 1.0; } + virtual int get_import_order() const { return 0; } + + struct ImportOption { + PropertyInfo option; + Variant default_value; + + ImportOption(const PropertyInfo &p_info, const Variant &p_default) : + option(p_info), + default_value(p_default) { + } + ImportOption() {} + }; + + virtual int get_preset_count() const { return 0; } + virtual String get_preset_name(int p_idx) const { return String(); } + + virtual void get_import_options(List *r_options, int p_preset = 0) const = 0; + virtual bool get_option_visibility(const String &p_option, const Map &p_options) const = 0; + + virtual Error import(const String &p_source_file, const String &p_save_path, const Map &p_options, List *r_platform_variants, List *r_gen_files = NULL) = 0; +}; + +#endif // RESOURCE_IMPORTER_H diff --git a/core/io/resource_loader.cpp b/core/io/resource_loader.cpp index 02e4d8dc7a..4aa002e9a2 100644 --- a/core/io/resource_loader.cpp +++ b/core/io/resource_loader.cpp @@ -30,7 +30,7 @@ #include "resource_loader.h" -#include "core/io/resource_import.h" +#include "core/io/resource_importer.h" #include "core/os/file_access.h" #include "core/os/os.h" #include "core/path_remap.h" diff --git a/core/list.h b/core/list.h index dd4ea3bd89..c26aad6463 100644 --- a/core/list.h +++ b/core/list.h @@ -32,7 +32,7 @@ #define GLOBALS_LIST_H #include "core/os/memory.h" -#include "core/sort.h" +#include "core/sort_array.h" /** * Generic Templatized Linked List Implementation. diff --git a/core/math/bsp_tree.h b/core/math/bsp_tree.h index 0af532a2d5..a7a3697990 100644 --- a/core/math/bsp_tree.h +++ b/core/math/bsp_tree.h @@ -31,11 +31,11 @@ #ifndef BSP_TREE_H #define BSP_TREE_H -#include "core/dvector.h" #include "core/math/aabb.h" #include "core/math/face3.h" #include "core/math/plane.h" #include "core/method_ptrcall.h" +#include "core/pool_vector.h" #include "core/variant.h" #include "core/vector.h" /** diff --git a/core/math/geometry.h b/core/math/geometry.h index 29493516b8..f927a63ed5 100644 --- a/core/math/geometry.h +++ b/core/math/geometry.h @@ -31,12 +31,12 @@ #ifndef GEOMETRY_H #define GEOMETRY_H -#include "core/dvector.h" #include "core/math/face3.h" #include "core/math/rect2.h" #include "core/math/triangulate.h" #include "core/math/vector3.h" #include "core/object.h" +#include "core/pool_vector.h" #include "core/print_string.h" #include "core/vector.h" diff --git a/core/math/triangle_mesh.cpp b/core/math/triangle_mesh.cpp index cdf3d16b72..83784a1fa7 100644 --- a/core/math/triangle_mesh.cpp +++ b/core/math/triangle_mesh.cpp @@ -30,7 +30,7 @@ #include "triangle_mesh.h" -#include "core/sort.h" +#include "core/sort_array.h" int TriangleMesh::_create_bvh(BVH *p_bvh, BVH **p_bb, int p_from, int p_size, int p_depth, int &max_depth, int &max_alloc) { diff --git a/core/node_path.h b/core/node_path.h index 17b1435723..24725123d6 100644 --- a/core/node_path.h +++ b/core/node_path.h @@ -31,7 +31,7 @@ #ifndef NODE_PATH_H #define NODE_PATH_H -#include "core/string_db.h" +#include "core/string_name.h" #include "core/ustring.h" /** diff --git a/core/os/shell.cpp b/core/os/shell.cpp deleted file mode 100644 index a859241cb6..0000000000 --- a/core/os/shell.cpp +++ /dev/null @@ -1,46 +0,0 @@ -/*************************************************************************/ -/* shell.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#include "shell.h" - -Shell *Shell::singleton = NULL; - -Shell *Shell::get_singleton() { - - return singleton; -} - -Shell::~Shell() { -} - -Shell::Shell() { - - singleton = this; -} diff --git a/core/os/shell.h b/core/os/shell.h deleted file mode 100644 index c1bd995b5b..0000000000 --- a/core/os/shell.h +++ /dev/null @@ -1,52 +0,0 @@ -/*************************************************************************/ -/* shell.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#ifndef SHELL_H -#define SHELL_H - -#include "core/typedefs.h" -#include "core/ustring.h" - -/** - @author Juan Linietsky -*/ -class Shell { - - static Shell *singleton; - -public: - static Shell *get_singleton(); - virtual void execute(String p_path) = 0; - - Shell(); - virtual ~Shell(); -}; - -#endif diff --git a/core/pool_vector.cpp b/core/pool_vector.cpp new file mode 100644 index 0000000000..b9d2316315 --- /dev/null +++ b/core/pool_vector.cpp @@ -0,0 +1,71 @@ +/*************************************************************************/ +/* pool_vector.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "pool_vector.h" + +Mutex *pool_vector_lock = NULL; + +PoolAllocator *MemoryPool::memory_pool = NULL; +uint8_t *MemoryPool::pool_memory = NULL; +size_t *MemoryPool::pool_size = NULL; + +MemoryPool::Alloc *MemoryPool::allocs = NULL; +MemoryPool::Alloc *MemoryPool::free_list = NULL; +uint32_t MemoryPool::alloc_count = 0; +uint32_t MemoryPool::allocs_used = 0; +Mutex *MemoryPool::alloc_mutex = NULL; + +size_t MemoryPool::total_memory = 0; +size_t MemoryPool::max_memory = 0; + +void MemoryPool::setup(uint32_t p_max_allocs) { + + allocs = memnew_arr(Alloc, p_max_allocs); + alloc_count = p_max_allocs; + allocs_used = 0; + + for (uint32_t i = 0; i < alloc_count - 1; i++) { + + allocs[i].free_list = &allocs[i + 1]; + } + + free_list = &allocs[0]; + + alloc_mutex = Mutex::create(); +} + +void MemoryPool::cleanup() { + + memdelete_arr(allocs); + memdelete(alloc_mutex); + + ERR_EXPLAINC("There are still MemoryPool allocs in use at exit!"); + ERR_FAIL_COND(allocs_used > 0); +} diff --git a/core/pool_vector.h b/core/pool_vector.h new file mode 100644 index 0000000000..102a620f17 --- /dev/null +++ b/core/pool_vector.h @@ -0,0 +1,643 @@ +/*************************************************************************/ +/* pool_vector.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef POOL_VECTOR_H +#define POOL_VECTOR_H + +#include "core/os/copymem.h" +#include "core/os/memory.h" +#include "core/os/rw_lock.h" +#include "core/pool_allocator.h" +#include "core/safe_refcount.h" +#include "core/ustring.h" + +struct MemoryPool { + + //avoid accessing these directly, must be public for template access + + static PoolAllocator *memory_pool; + static uint8_t *pool_memory; + static size_t *pool_size; + + struct Alloc { + + SafeRefCount refcount; + uint32_t lock; + void *mem; + PoolAllocator::ID pool_id; + size_t size; + + Alloc *free_list; + + Alloc() : + lock(0), + mem(NULL), + pool_id(POOL_ALLOCATOR_INVALID_ID), + size(0), + free_list(NULL) { + } + }; + + static Alloc *allocs; + static Alloc *free_list; + static uint32_t alloc_count; + static uint32_t allocs_used; + static Mutex *alloc_mutex; + static size_t total_memory; + static size_t max_memory; + + static void setup(uint32_t p_max_allocs = (1 << 16)); + static void cleanup(); +}; + +/** + @author Juan Linietsky +*/ + +template +class PoolVector { + + MemoryPool::Alloc *alloc; + + void _copy_on_write() { + + if (!alloc) + return; + + // ERR_FAIL_COND(alloc->lock>0); should not be illegal to lock this for copy on write, as it's a copy on write after all + + // Refcount should not be zero, otherwise it's a misuse of COW + if (alloc->refcount.get() == 1) + return; //nothing to do + + //must allocate something + + MemoryPool::alloc_mutex->lock(); + if (MemoryPool::allocs_used == MemoryPool::alloc_count) { + MemoryPool::alloc_mutex->unlock(); + ERR_EXPLAINC("All memory pool allocations are in use, can't COW."); + ERR_FAIL(); + } + + MemoryPool::Alloc *old_alloc = alloc; + + //take one from the free list + alloc = MemoryPool::free_list; + MemoryPool::free_list = alloc->free_list; + //increment the used counter + MemoryPool::allocs_used++; + + //copy the alloc data + alloc->size = old_alloc->size; + alloc->refcount.init(); + alloc->pool_id = POOL_ALLOCATOR_INVALID_ID; + alloc->lock = 0; + +#ifdef DEBUG_ENABLED + MemoryPool::total_memory += alloc->size; + if (MemoryPool::total_memory > MemoryPool::max_memory) { + MemoryPool::max_memory = MemoryPool::total_memory; + } +#endif + + MemoryPool::alloc_mutex->unlock(); + + if (MemoryPool::memory_pool) { + + } else { + alloc->mem = memalloc(alloc->size); + } + + { + Write w; + w._ref(alloc); + Read r; + r._ref(old_alloc); + + int cur_elements = alloc->size / sizeof(T); + T *dst = (T *)w.ptr(); + const T *src = (const T *)r.ptr(); + for (int i = 0; i < cur_elements; i++) { + memnew_placement(&dst[i], T(src[i])); + } + } + + if (old_alloc->refcount.unref()) { + //this should never happen but.. + +#ifdef DEBUG_ENABLED + MemoryPool::alloc_mutex->lock(); + MemoryPool::total_memory -= old_alloc->size; + MemoryPool::alloc_mutex->unlock(); +#endif + + { + Write w; + w._ref(old_alloc); + + int cur_elements = old_alloc->size / sizeof(T); + T *elems = (T *)w.ptr(); + for (int i = 0; i < cur_elements; i++) { + elems[i].~T(); + } + } + + if (MemoryPool::memory_pool) { + //resize memory pool + //if none, create + //if some resize + } else { + + memfree(old_alloc->mem); + old_alloc->mem = NULL; + old_alloc->size = 0; + + MemoryPool::alloc_mutex->lock(); + old_alloc->free_list = MemoryPool::free_list; + MemoryPool::free_list = old_alloc; + MemoryPool::allocs_used--; + MemoryPool::alloc_mutex->unlock(); + } + } + } + + void _reference(const PoolVector &p_pool_vector) { + + if (alloc == p_pool_vector.alloc) + return; + + _unreference(); + + if (!p_pool_vector.alloc) { + return; + } + + if (p_pool_vector.alloc->refcount.ref()) { + alloc = p_pool_vector.alloc; + } + } + + void _unreference() { + + if (!alloc) + return; + + if (!alloc->refcount.unref()) { + alloc = NULL; + return; + } + + //must be disposed! + + { + int cur_elements = alloc->size / sizeof(T); + + // Don't use write() here because it could otherwise provoke COW, + // which is not desirable here because we are destroying the last reference anyways + Write w; + // Reference to still prevent other threads from touching the alloc + w._ref(alloc); + + for (int i = 0; i < cur_elements; i++) { + + w[i].~T(); + } + } + +#ifdef DEBUG_ENABLED + MemoryPool::alloc_mutex->lock(); + MemoryPool::total_memory -= alloc->size; + MemoryPool::alloc_mutex->unlock(); +#endif + + if (MemoryPool::memory_pool) { + //resize memory pool + //if none, create + //if some resize + } else { + + memfree(alloc->mem); + alloc->mem = NULL; + alloc->size = 0; + + MemoryPool::alloc_mutex->lock(); + alloc->free_list = MemoryPool::free_list; + MemoryPool::free_list = alloc; + MemoryPool::allocs_used--; + MemoryPool::alloc_mutex->unlock(); + } + + alloc = NULL; + } + +public: + class Access { + friend class PoolVector; + + protected: + MemoryPool::Alloc *alloc; + T *mem; + + _FORCE_INLINE_ void _ref(MemoryPool::Alloc *p_alloc) { + alloc = p_alloc; + if (alloc) { + if (atomic_increment(&alloc->lock) == 1) { + if (MemoryPool::memory_pool) { + //lock it and get mem + } + } + + mem = (T *)alloc->mem; + } + } + + _FORCE_INLINE_ void _unref() { + + if (alloc) { + if (atomic_decrement(&alloc->lock) == 0) { + if (MemoryPool::memory_pool) { + //put mem back + } + } + + mem = NULL; + alloc = NULL; + } + } + + Access() { + alloc = NULL; + mem = NULL; + } + + public: + virtual ~Access() { + _unref(); + } + }; + + class Read : public Access { + public: + _FORCE_INLINE_ const T &operator[](int p_index) const { return this->mem[p_index]; } + _FORCE_INLINE_ const T *ptr() const { return this->mem; } + + void operator=(const Read &p_read) { + if (this->alloc == p_read.alloc) + return; + this->_unref(); + this->_ref(p_read.alloc); + } + + Read(const Read &p_read) { + this->_ref(p_read.alloc); + } + + Read() {} + }; + + class Write : public Access { + public: + _FORCE_INLINE_ T &operator[](int p_index) const { return this->mem[p_index]; } + _FORCE_INLINE_ T *ptr() const { return this->mem; } + + void operator=(const Write &p_read) { + if (this->alloc == p_read.alloc) + return; + this->_unref(); + this->_ref(p_read.alloc); + } + + Write(const Write &p_read) { + this->_ref(p_read.alloc); + } + + Write() {} + }; + + Read read() const { + + Read r; + if (alloc) { + r._ref(alloc); + } + return r; + } + Write write() { + + Write w; + if (alloc) { + _copy_on_write(); //make sure there is only one being acessed + w._ref(alloc); + } + return w; + } + + template + void fill_with(const MC &p_mc) { + + int c = p_mc.size(); + resize(c); + Write w = write(); + int idx = 0; + for (const typename MC::Element *E = p_mc.front(); E; E = E->next()) { + + w[idx++] = E->get(); + } + } + + void remove(int p_index) { + + int s = size(); + ERR_FAIL_INDEX(p_index, s); + Write w = write(); + for (int i = p_index; i < s - 1; i++) { + + w[i] = w[i + 1]; + }; + w = Write(); + resize(s - 1); + } + + inline int size() const; + T get(int p_index) const; + void set(int p_index, const T &p_val); + void push_back(const T &p_val); + void append(const T &p_val) { push_back(p_val); } + void append_array(const PoolVector &p_arr) { + int ds = p_arr.size(); + if (ds == 0) + return; + int bs = size(); + resize(bs + ds); + Write w = write(); + Read r = p_arr.read(); + for (int i = 0; i < ds; i++) + w[bs + i] = r[i]; + } + + PoolVector subarray(int p_from, int p_to) { + + if (p_from < 0) { + p_from = size() + p_from; + } + if (p_to < 0) { + p_to = size() + p_to; + } + + CRASH_BAD_INDEX(p_from, size()); + CRASH_BAD_INDEX(p_to, size()); + + PoolVector slice; + int span = 1 + p_to - p_from; + slice.resize(span); + Read r = read(); + Write w = slice.write(); + for (int i = 0; i < span; ++i) { + w[i] = r[p_from + i]; + } + + return slice; + } + + Error insert(int p_pos, const T &p_val) { + + int s = size(); + ERR_FAIL_INDEX_V(p_pos, s + 1, ERR_INVALID_PARAMETER); + resize(s + 1); + { + Write w = write(); + for (int i = s; i > p_pos; i--) + w[i] = w[i - 1]; + w[p_pos] = p_val; + } + + return OK; + } + + String join(String delimiter) { + String rs = ""; + int s = size(); + Read r = read(); + for (int i = 0; i < s; i++) { + rs += r[i] + delimiter; + } + rs.erase(rs.length() - delimiter.length(), delimiter.length()); + return rs; + } + + bool is_locked() const { return alloc && alloc->lock > 0; } + + inline const T operator[](int p_index) const; + + Error resize(int p_size); + + void invert(); + + void operator=(const PoolVector &p_pool_vector) { _reference(p_pool_vector); } + PoolVector() { alloc = NULL; } + PoolVector(const PoolVector &p_pool_vector) { + alloc = NULL; + _reference(p_pool_vector); + } + ~PoolVector() { _unreference(); } +}; + +template +int PoolVector::size() const { + + return alloc ? alloc->size / sizeof(T) : 0; +} + +template +T PoolVector::get(int p_index) const { + + return operator[](p_index); +} + +template +void PoolVector::set(int p_index, const T &p_val) { + + if (p_index < 0 || p_index >= size()) { + ERR_FAIL_COND(p_index < 0 || p_index >= size()); + } + + Write w = write(); + w[p_index] = p_val; +} + +template +void PoolVector::push_back(const T &p_val) { + + resize(size() + 1); + set(size() - 1, p_val); +} + +template +const T PoolVector::operator[](int p_index) const { + + CRASH_BAD_INDEX(p_index, size()); + + Read r = read(); + return r[p_index]; +} + +template +Error PoolVector::resize(int p_size) { + + if (alloc == NULL) { + + if (p_size == 0) + return OK; //nothing to do here + + //must allocate something + MemoryPool::alloc_mutex->lock(); + if (MemoryPool::allocs_used == MemoryPool::alloc_count) { + MemoryPool::alloc_mutex->unlock(); + ERR_EXPLAINC("All memory pool allocations are in use."); + ERR_FAIL_V(ERR_OUT_OF_MEMORY); + } + + //take one from the free list + alloc = MemoryPool::free_list; + MemoryPool::free_list = alloc->free_list; + //increment the used counter + MemoryPool::allocs_used++; + + //cleanup the alloc + alloc->size = 0; + alloc->refcount.init(); + alloc->pool_id = POOL_ALLOCATOR_INVALID_ID; + MemoryPool::alloc_mutex->unlock(); + + } else { + + ERR_FAIL_COND_V(alloc->lock > 0, ERR_LOCKED); //can't resize if locked! + } + + size_t new_size = sizeof(T) * p_size; + + if (alloc->size == new_size) + return OK; //nothing to do + + if (p_size == 0) { + _unreference(); + return OK; + } + + _copy_on_write(); // make it unique + +#ifdef DEBUG_ENABLED + MemoryPool::alloc_mutex->lock(); + MemoryPool::total_memory -= alloc->size; + MemoryPool::total_memory += new_size; + if (MemoryPool::total_memory > MemoryPool::max_memory) { + MemoryPool::max_memory = MemoryPool::total_memory; + } + MemoryPool::alloc_mutex->unlock(); +#endif + + int cur_elements = alloc->size / sizeof(T); + + if (p_size > cur_elements) { + + if (MemoryPool::memory_pool) { + //resize memory pool + //if none, create + //if some resize + } else { + + if (alloc->size == 0) { + alloc->mem = memalloc(new_size); + } else { + alloc->mem = memrealloc(alloc->mem, new_size); + } + } + + alloc->size = new_size; + + Write w = write(); + + for (int i = cur_elements; i < p_size; i++) { + + memnew_placement(&w[i], T); + } + + } else { + + { + Write w = write(); + for (int i = p_size; i < cur_elements; i++) { + + w[i].~T(); + } + } + + if (MemoryPool::memory_pool) { + //resize memory pool + //if none, create + //if some resize + } else { + + if (new_size == 0) { + memfree(alloc->mem); + alloc->mem = NULL; + alloc->size = 0; + + MemoryPool::alloc_mutex->lock(); + alloc->free_list = MemoryPool::free_list; + MemoryPool::free_list = alloc; + MemoryPool::allocs_used--; + MemoryPool::alloc_mutex->unlock(); + + } else { + alloc->mem = memrealloc(alloc->mem, new_size); + alloc->size = new_size; + } + } + } + + return OK; +} + +template +void PoolVector::invert() { + T temp; + Write w = write(); + int s = size(); + int half_s = s / 2; + + for (int i = 0; i < half_s; i++) { + temp = w[i]; + w[i] = w[s - i - 1]; + w[s - i - 1] = temp; + } +} + +#endif // POOL_VECTOR_H diff --git a/core/register_core_types.cpp b/core/register_core_types.cpp index 60c2778603..97c96b4018 100644 --- a/core/register_core_types.cpp +++ b/core/register_core_types.cpp @@ -47,7 +47,7 @@ #include "core/io/packet_peer_udp.h" #include "core/io/pck_packer.h" #include "core/io/resource_format_binary.h" -#include "core/io/resource_import.h" +#include "core/io/resource_importer.h" #include "core/io/stream_peer_ssl.h" #include "core/io/tcp_server.h" #include "core/io/translation_loader_po.h" diff --git a/core/sort.h b/core/sort.h deleted file mode 100644 index 4da7c323c7..0000000000 --- a/core/sort.h +++ /dev/null @@ -1,330 +0,0 @@ -/*************************************************************************/ -/* sort.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#ifndef SORT_H -#define SORT_H - -#include "core/typedefs.h" - -#define ERR_BAD_COMPARE(cond) \ - if (unlikely(cond)) { \ - ERR_PRINT("bad comparison function; sorting will be broken"); \ - break; \ - } - -template -struct _DefaultComparator { - - _FORCE_INLINE_ bool operator()(const T &a, const T &b) const { return (a < b); } -}; - -#ifdef DEBUG_ENABLED -#define SORT_ARRAY_VALIDATE_ENABLED true -#else -#define SORT_ARRAY_VALIDATE_ENABLED false -#endif - -template , bool Validate = SORT_ARRAY_VALIDATE_ENABLED> -class SortArray { - - enum { - - INTROSORT_THRESHOLD = 16 - }; - -public: - Comparator compare; - - inline const T &median_of_3(const T &a, const T &b, const T &c) const { - - if (compare(a, b)) - if (compare(b, c)) - return b; - else if (compare(a, c)) - return c; - else - return a; - else if (compare(a, c)) - return a; - else if (compare(b, c)) - return c; - else - return b; - } - - inline int bitlog(int n) const { - int k; - for (k = 0; n != 1; n >>= 1) - ++k; - return k; - } - - /* Heap / Heapsort functions */ - - inline void push_heap(int p_first, int p_hole_idx, int p_top_index, T p_value, T *p_array) const { - - int parent = (p_hole_idx - 1) / 2; - while (p_hole_idx > p_top_index && compare(p_array[p_first + parent], p_value)) { - - p_array[p_first + p_hole_idx] = p_array[p_first + parent]; - p_hole_idx = parent; - parent = (p_hole_idx - 1) / 2; - } - p_array[p_first + p_hole_idx] = p_value; - } - - inline void pop_heap(int p_first, int p_last, int p_result, T p_value, T *p_array) const { - - p_array[p_result] = p_array[p_first]; - adjust_heap(p_first, 0, p_last - p_first, p_value, p_array); - } - inline void pop_heap(int p_first, int p_last, T *p_array) const { - - pop_heap(p_first, p_last - 1, p_last - 1, p_array[p_last - 1], p_array); - } - - inline void adjust_heap(int p_first, int p_hole_idx, int p_len, T p_value, T *p_array) const { - - int top_index = p_hole_idx; - int second_child = 2 * p_hole_idx + 2; - - while (second_child < p_len) { - - if (compare(p_array[p_first + second_child], p_array[p_first + (second_child - 1)])) - second_child--; - - p_array[p_first + p_hole_idx] = p_array[p_first + second_child]; - p_hole_idx = second_child; - second_child = 2 * (second_child + 1); - } - - if (second_child == p_len) { - p_array[p_first + p_hole_idx] = p_array[p_first + (second_child - 1)]; - p_hole_idx = second_child - 1; - } - push_heap(p_first, p_hole_idx, top_index, p_value, p_array); - } - - inline void sort_heap(int p_first, int p_last, T *p_array) const { - - while (p_last - p_first > 1) { - - pop_heap(p_first, p_last--, p_array); - } - } - - inline void make_heap(int p_first, int p_last, T *p_array) const { - if (p_last - p_first < 2) - return; - int len = p_last - p_first; - int parent = (len - 2) / 2; - - while (true) { - adjust_heap(p_first, parent, len, p_array[p_first + parent], p_array); - if (parent == 0) - return; - parent--; - } - } - - inline void partial_sort(int p_first, int p_last, int p_middle, T *p_array) const { - - make_heap(p_first, p_middle, p_array); - for (int i = p_middle; i < p_last; i++) - if (compare(p_array[i], p_array[p_first])) - pop_heap(p_first, p_middle, i, p_array[i], p_array); - sort_heap(p_first, p_middle, p_array); - } - - inline void partial_select(int p_first, int p_last, int p_middle, T *p_array) const { - - make_heap(p_first, p_middle, p_array); - for (int i = p_middle; i < p_last; i++) - if (compare(p_array[i], p_array[p_first])) - pop_heap(p_first, p_middle, i, p_array[i], p_array); - } - - inline int partitioner(int p_first, int p_last, T p_pivot, T *p_array) const { - - const int unmodified_first = p_first; - const int unmodified_last = p_last; - - while (true) { - while (compare(p_array[p_first], p_pivot)) { - if (Validate) { - ERR_BAD_COMPARE(p_first == unmodified_last - 1) - } - p_first++; - } - p_last--; - while (compare(p_pivot, p_array[p_last])) { - if (Validate) { - ERR_BAD_COMPARE(p_last == unmodified_first) - } - p_last--; - } - - if (!(p_first < p_last)) - return p_first; - - SWAP(p_array[p_first], p_array[p_last]); - p_first++; - } - } - - inline void introsort(int p_first, int p_last, T *p_array, int p_max_depth) const { - - while (p_last - p_first > INTROSORT_THRESHOLD) { - - if (p_max_depth == 0) { - partial_sort(p_first, p_last, p_last, p_array); - return; - } - - p_max_depth--; - - int cut = partitioner( - p_first, - p_last, - median_of_3( - p_array[p_first], - p_array[p_first + (p_last - p_first) / 2], - p_array[p_last - 1]), - p_array); - - introsort(cut, p_last, p_array, p_max_depth); - p_last = cut; - } - } - - inline void introselect(int p_first, int p_nth, int p_last, T *p_array, int p_max_depth) const { - - while (p_last - p_first > 3) { - - if (p_max_depth == 0) { - partial_select(p_first, p_nth + 1, p_last, p_array); - SWAP(p_first, p_nth); - return; - } - - p_max_depth--; - - int cut = partitioner( - p_first, - p_last, - median_of_3( - p_array[p_first], - p_array[p_first + (p_last - p_first) / 2], - p_array[p_last - 1]), - p_array); - - if (cut <= p_nth) - p_first = cut; - else - p_last = cut; - } - - insertion_sort(p_first, p_last, p_array); - } - - inline void unguarded_linear_insert(int p_last, T p_value, T *p_array) const { - - int next = p_last - 1; - while (compare(p_value, p_array[next])) { - if (Validate) { - ERR_BAD_COMPARE(next == 0) - } - p_array[p_last] = p_array[next]; - p_last = next; - next--; - } - p_array[p_last] = p_value; - } - - inline void linear_insert(int p_first, int p_last, T *p_array) const { - - T val = p_array[p_last]; - if (compare(val, p_array[p_first])) { - - for (int i = p_last; i > p_first; i--) - p_array[i] = p_array[i - 1]; - - p_array[p_first] = val; - } else - unguarded_linear_insert(p_last, val, p_array); - } - - inline void insertion_sort(int p_first, int p_last, T *p_array) const { - - if (p_first == p_last) - return; - for (int i = p_first + 1; i != p_last; i++) - linear_insert(p_first, i, p_array); - } - - inline void unguarded_insertion_sort(int p_first, int p_last, T *p_array) const { - - for (int i = p_first; i != p_last; i++) - unguarded_linear_insert(i, p_array[i], p_array); - } - - inline void final_insertion_sort(int p_first, int p_last, T *p_array) const { - - if (p_last - p_first > INTROSORT_THRESHOLD) { - insertion_sort(p_first, p_first + INTROSORT_THRESHOLD, p_array); - unguarded_insertion_sort(p_first + INTROSORT_THRESHOLD, p_last, p_array); - } else { - - insertion_sort(p_first, p_last, p_array); - } - } - - inline void sort_range(int p_first, int p_last, T *p_array) const { - - if (p_first != p_last) { - introsort(p_first, p_last, p_array, bitlog(p_last - p_first) * 2); - final_insertion_sort(p_first, p_last, p_array); - } - } - - inline void sort(T *p_array, int p_len) const { - - sort_range(0, p_len, p_array); - } - - inline void nth_element(int p_first, int p_last, int p_nth, T *p_array) const { - - if (p_first == p_last || p_nth == p_last) - return; - introselect(p_first, p_nth, p_last, p_array, bitlog(p_last - p_first) * 2); - } -}; - -#endif diff --git a/core/sort_array.h b/core/sort_array.h new file mode 100644 index 0000000000..0f258aec3e --- /dev/null +++ b/core/sort_array.h @@ -0,0 +1,330 @@ +/*************************************************************************/ +/* sort_array.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef SORT_ARRAY_H +#define SORT_ARRAY_H + +#include "core/typedefs.h" + +#define ERR_BAD_COMPARE(cond) \ + if (unlikely(cond)) { \ + ERR_PRINT("bad comparison function; sorting will be broken"); \ + break; \ + } + +template +struct _DefaultComparator { + + _FORCE_INLINE_ bool operator()(const T &a, const T &b) const { return (a < b); } +}; + +#ifdef DEBUG_ENABLED +#define SORT_ARRAY_VALIDATE_ENABLED true +#else +#define SORT_ARRAY_VALIDATE_ENABLED false +#endif + +template , bool Validate = SORT_ARRAY_VALIDATE_ENABLED> +class SortArray { + + enum { + + INTROSORT_THRESHOLD = 16 + }; + +public: + Comparator compare; + + inline const T &median_of_3(const T &a, const T &b, const T &c) const { + + if (compare(a, b)) + if (compare(b, c)) + return b; + else if (compare(a, c)) + return c; + else + return a; + else if (compare(a, c)) + return a; + else if (compare(b, c)) + return c; + else + return b; + } + + inline int bitlog(int n) const { + int k; + for (k = 0; n != 1; n >>= 1) + ++k; + return k; + } + + /* Heap / Heapsort functions */ + + inline void push_heap(int p_first, int p_hole_idx, int p_top_index, T p_value, T *p_array) const { + + int parent = (p_hole_idx - 1) / 2; + while (p_hole_idx > p_top_index && compare(p_array[p_first + parent], p_value)) { + + p_array[p_first + p_hole_idx] = p_array[p_first + parent]; + p_hole_idx = parent; + parent = (p_hole_idx - 1) / 2; + } + p_array[p_first + p_hole_idx] = p_value; + } + + inline void pop_heap(int p_first, int p_last, int p_result, T p_value, T *p_array) const { + + p_array[p_result] = p_array[p_first]; + adjust_heap(p_first, 0, p_last - p_first, p_value, p_array); + } + inline void pop_heap(int p_first, int p_last, T *p_array) const { + + pop_heap(p_first, p_last - 1, p_last - 1, p_array[p_last - 1], p_array); + } + + inline void adjust_heap(int p_first, int p_hole_idx, int p_len, T p_value, T *p_array) const { + + int top_index = p_hole_idx; + int second_child = 2 * p_hole_idx + 2; + + while (second_child < p_len) { + + if (compare(p_array[p_first + second_child], p_array[p_first + (second_child - 1)])) + second_child--; + + p_array[p_first + p_hole_idx] = p_array[p_first + second_child]; + p_hole_idx = second_child; + second_child = 2 * (second_child + 1); + } + + if (second_child == p_len) { + p_array[p_first + p_hole_idx] = p_array[p_first + (second_child - 1)]; + p_hole_idx = second_child - 1; + } + push_heap(p_first, p_hole_idx, top_index, p_value, p_array); + } + + inline void sort_heap(int p_first, int p_last, T *p_array) const { + + while (p_last - p_first > 1) { + + pop_heap(p_first, p_last--, p_array); + } + } + + inline void make_heap(int p_first, int p_last, T *p_array) const { + if (p_last - p_first < 2) + return; + int len = p_last - p_first; + int parent = (len - 2) / 2; + + while (true) { + adjust_heap(p_first, parent, len, p_array[p_first + parent], p_array); + if (parent == 0) + return; + parent--; + } + } + + inline void partial_sort(int p_first, int p_last, int p_middle, T *p_array) const { + + make_heap(p_first, p_middle, p_array); + for (int i = p_middle; i < p_last; i++) + if (compare(p_array[i], p_array[p_first])) + pop_heap(p_first, p_middle, i, p_array[i], p_array); + sort_heap(p_first, p_middle, p_array); + } + + inline void partial_select(int p_first, int p_last, int p_middle, T *p_array) const { + + make_heap(p_first, p_middle, p_array); + for (int i = p_middle; i < p_last; i++) + if (compare(p_array[i], p_array[p_first])) + pop_heap(p_first, p_middle, i, p_array[i], p_array); + } + + inline int partitioner(int p_first, int p_last, T p_pivot, T *p_array) const { + + const int unmodified_first = p_first; + const int unmodified_last = p_last; + + while (true) { + while (compare(p_array[p_first], p_pivot)) { + if (Validate) { + ERR_BAD_COMPARE(p_first == unmodified_last - 1) + } + p_first++; + } + p_last--; + while (compare(p_pivot, p_array[p_last])) { + if (Validate) { + ERR_BAD_COMPARE(p_last == unmodified_first) + } + p_last--; + } + + if (!(p_first < p_last)) + return p_first; + + SWAP(p_array[p_first], p_array[p_last]); + p_first++; + } + } + + inline void introsort(int p_first, int p_last, T *p_array, int p_max_depth) const { + + while (p_last - p_first > INTROSORT_THRESHOLD) { + + if (p_max_depth == 0) { + partial_sort(p_first, p_last, p_last, p_array); + return; + } + + p_max_depth--; + + int cut = partitioner( + p_first, + p_last, + median_of_3( + p_array[p_first], + p_array[p_first + (p_last - p_first) / 2], + p_array[p_last - 1]), + p_array); + + introsort(cut, p_last, p_array, p_max_depth); + p_last = cut; + } + } + + inline void introselect(int p_first, int p_nth, int p_last, T *p_array, int p_max_depth) const { + + while (p_last - p_first > 3) { + + if (p_max_depth == 0) { + partial_select(p_first, p_nth + 1, p_last, p_array); + SWAP(p_first, p_nth); + return; + } + + p_max_depth--; + + int cut = partitioner( + p_first, + p_last, + median_of_3( + p_array[p_first], + p_array[p_first + (p_last - p_first) / 2], + p_array[p_last - 1]), + p_array); + + if (cut <= p_nth) + p_first = cut; + else + p_last = cut; + } + + insertion_sort(p_first, p_last, p_array); + } + + inline void unguarded_linear_insert(int p_last, T p_value, T *p_array) const { + + int next = p_last - 1; + while (compare(p_value, p_array[next])) { + if (Validate) { + ERR_BAD_COMPARE(next == 0) + } + p_array[p_last] = p_array[next]; + p_last = next; + next--; + } + p_array[p_last] = p_value; + } + + inline void linear_insert(int p_first, int p_last, T *p_array) const { + + T val = p_array[p_last]; + if (compare(val, p_array[p_first])) { + + for (int i = p_last; i > p_first; i--) + p_array[i] = p_array[i - 1]; + + p_array[p_first] = val; + } else + unguarded_linear_insert(p_last, val, p_array); + } + + inline void insertion_sort(int p_first, int p_last, T *p_array) const { + + if (p_first == p_last) + return; + for (int i = p_first + 1; i != p_last; i++) + linear_insert(p_first, i, p_array); + } + + inline void unguarded_insertion_sort(int p_first, int p_last, T *p_array) const { + + for (int i = p_first; i != p_last; i++) + unguarded_linear_insert(i, p_array[i], p_array); + } + + inline void final_insertion_sort(int p_first, int p_last, T *p_array) const { + + if (p_last - p_first > INTROSORT_THRESHOLD) { + insertion_sort(p_first, p_first + INTROSORT_THRESHOLD, p_array); + unguarded_insertion_sort(p_first + INTROSORT_THRESHOLD, p_last, p_array); + } else { + + insertion_sort(p_first, p_last, p_array); + } + } + + inline void sort_range(int p_first, int p_last, T *p_array) const { + + if (p_first != p_last) { + introsort(p_first, p_last, p_array, bitlog(p_last - p_first) * 2); + final_insertion_sort(p_first, p_last, p_array); + } + } + + inline void sort(T *p_array, int p_len) const { + + sort_range(0, p_len, p_array); + } + + inline void nth_element(int p_first, int p_last, int p_nth, T *p_array) const { + + if (p_first == p_last || p_nth == p_last) + return; + introselect(p_first, p_nth, p_last, p_array, bitlog(p_last - p_first) * 2); + } +}; + +#endif // SORT_ARRAY_H diff --git a/core/string_db.cpp b/core/string_db.cpp deleted file mode 100644 index c776c56023..0000000000 --- a/core/string_db.cpp +++ /dev/null @@ -1,426 +0,0 @@ -/*************************************************************************/ -/* string_db.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#include "string_db.h" - -#include "core/os/os.h" -#include "core/print_string.h" - -StaticCString StaticCString::create(const char *p_ptr) { - StaticCString scs; - scs.ptr = p_ptr; - return scs; -} - -StringName::_Data *StringName::_table[STRING_TABLE_LEN]; - -StringName _scs_create(const char *p_chr) { - - return (p_chr[0] ? StringName(StaticCString::create(p_chr)) : StringName()); -} - -bool StringName::configured = false; -Mutex *StringName::lock = NULL; - -void StringName::setup() { - - lock = Mutex::create(); - - ERR_FAIL_COND(configured); - for (int i = 0; i < STRING_TABLE_LEN; i++) { - - _table[i] = NULL; - } - configured = true; -} - -void StringName::cleanup() { - - lock->lock(); - - int lost_strings = 0; - for (int i = 0; i < STRING_TABLE_LEN; i++) { - - while (_table[i]) { - - _Data *d = _table[i]; - lost_strings++; - if (OS::get_singleton()->is_stdout_verbose()) { - if (d->cname) { - print_line("Orphan StringName: " + String(d->cname)); - } else { - print_line("Orphan StringName: " + String(d->name)); - } - } - - _table[i] = _table[i]->next; - memdelete(d); - } - } - if (lost_strings) { - print_verbose("StringName: " + itos(lost_strings) + " unclaimed string names at exit."); - } - lock->unlock(); - - memdelete(lock); -} - -void StringName::unref() { - - ERR_FAIL_COND(!configured); - - if (_data && _data->refcount.unref()) { - - lock->lock(); - - if (_data->prev) { - _data->prev->next = _data->next; - } else { - if (_table[_data->idx] != _data) { - ERR_PRINT("BUG!"); - } - _table[_data->idx] = _data->next; - } - - if (_data->next) { - _data->next->prev = _data->prev; - } - memdelete(_data); - lock->unlock(); - } - - _data = NULL; -} - -bool StringName::operator==(const String &p_name) const { - - if (!_data) { - - return (p_name.length() == 0); - } - - return (_data->get_name() == p_name); -} - -bool StringName::operator==(const char *p_name) const { - - if (!_data) { - - return (p_name[0] == 0); - } - - return (_data->get_name() == p_name); -} - -bool StringName::operator!=(const String &p_name) const { - - return !(operator==(p_name)); -} - -bool StringName::operator!=(const StringName &p_name) const { - - // the real magic of all this mess happens here. - // this is why path comparisons are very fast - return _data != p_name._data; -} - -void StringName::operator=(const StringName &p_name) { - - if (this == &p_name) - return; - - unref(); - - if (p_name._data && p_name._data->refcount.ref()) { - - _data = p_name._data; - } -} - -StringName::StringName(const StringName &p_name) { - - _data = NULL; - - ERR_FAIL_COND(!configured); - - if (p_name._data && p_name._data->refcount.ref()) { - _data = p_name._data; - } -} - -StringName::StringName(const char *p_name) { - - _data = NULL; - - ERR_FAIL_COND(!configured); - - if (!p_name || p_name[0] == 0) - return; //empty, ignore - - lock->lock(); - - uint32_t hash = String::hash(p_name); - - uint32_t idx = hash & STRING_TABLE_MASK; - - _data = _table[idx]; - - while (_data) { - - // compare hash first - if (_data->hash == hash && _data->get_name() == p_name) - break; - _data = _data->next; - } - - if (_data) { - if (_data->refcount.ref()) { - // exists - lock->unlock(); - return; - } else { - } - } - - _data = memnew(_Data); - _data->name = p_name; - _data->refcount.init(); - _data->hash = hash; - _data->idx = idx; - _data->cname = NULL; - _data->next = _table[idx]; - _data->prev = NULL; - if (_table[idx]) - _table[idx]->prev = _data; - _table[idx] = _data; - - lock->unlock(); -} - -StringName::StringName(const StaticCString &p_static_string) { - - _data = NULL; - - ERR_FAIL_COND(!configured); - - ERR_FAIL_COND(!p_static_string.ptr || !p_static_string.ptr[0]); - - lock->lock(); - - uint32_t hash = String::hash(p_static_string.ptr); - - uint32_t idx = hash & STRING_TABLE_MASK; - - _data = _table[idx]; - - while (_data) { - - // compare hash first - if (_data->hash == hash && _data->get_name() == p_static_string.ptr) - break; - _data = _data->next; - } - - if (_data) { - if (_data->refcount.ref()) { - // exists - lock->unlock(); - return; - } else { - } - } - - _data = memnew(_Data); - - _data->refcount.init(); - _data->hash = hash; - _data->idx = idx; - _data->cname = p_static_string.ptr; - _data->next = _table[idx]; - _data->prev = NULL; - if (_table[idx]) - _table[idx]->prev = _data; - _table[idx] = _data; - - lock->unlock(); -} - -StringName::StringName(const String &p_name) { - - _data = NULL; - - ERR_FAIL_COND(!configured); - - if (p_name == String()) - return; - - lock->lock(); - - uint32_t hash = p_name.hash(); - - uint32_t idx = hash & STRING_TABLE_MASK; - - _data = _table[idx]; - - while (_data) { - - if (_data->hash == hash && _data->get_name() == p_name) - break; - _data = _data->next; - } - - if (_data) { - if (_data->refcount.ref()) { - // exists - lock->unlock(); - return; - } else { - } - } - - _data = memnew(_Data); - _data->name = p_name; - _data->refcount.init(); - _data->hash = hash; - _data->idx = idx; - _data->cname = NULL; - _data->next = _table[idx]; - _data->prev = NULL; - if (_table[idx]) - _table[idx]->prev = _data; - _table[idx] = _data; - - lock->unlock(); -} - -StringName StringName::search(const char *p_name) { - - ERR_FAIL_COND_V(!configured, StringName()); - - ERR_FAIL_COND_V(!p_name, StringName()); - if (!p_name[0]) - return StringName(); - - lock->lock(); - - uint32_t hash = String::hash(p_name); - - uint32_t idx = hash & STRING_TABLE_MASK; - - _Data *_data = _table[idx]; - - while (_data) { - - // compare hash first - if (_data->hash == hash && _data->get_name() == p_name) - break; - _data = _data->next; - } - - if (_data && _data->refcount.ref()) { - lock->unlock(); - - return StringName(_data); - } - - lock->unlock(); - return StringName(); //does not exist -} - -StringName StringName::search(const CharType *p_name) { - - ERR_FAIL_COND_V(!configured, StringName()); - - ERR_FAIL_COND_V(!p_name, StringName()); - if (!p_name[0]) - return StringName(); - - lock->lock(); - - uint32_t hash = String::hash(p_name); - - uint32_t idx = hash & STRING_TABLE_MASK; - - _Data *_data = _table[idx]; - - while (_data) { - - // compare hash first - if (_data->hash == hash && _data->get_name() == p_name) - break; - _data = _data->next; - } - - if (_data && _data->refcount.ref()) { - lock->unlock(); - return StringName(_data); - } - - lock->unlock(); - return StringName(); //does not exist -} -StringName StringName::search(const String &p_name) { - - ERR_FAIL_COND_V(p_name == "", StringName()); - - lock->lock(); - - uint32_t hash = p_name.hash(); - - uint32_t idx = hash & STRING_TABLE_MASK; - - _Data *_data = _table[idx]; - - while (_data) { - - // compare hash first - if (_data->hash == hash && p_name == _data->get_name()) - break; - _data = _data->next; - } - - if (_data && _data->refcount.ref()) { - lock->unlock(); - return StringName(_data); - } - - lock->unlock(); - return StringName(); //does not exist -} - -StringName::StringName() { - - _data = NULL; -} - -StringName::~StringName() { - - unref(); -} diff --git a/core/string_db.h b/core/string_db.h deleted file mode 100644 index 06b24c28da..0000000000 --- a/core/string_db.h +++ /dev/null @@ -1,172 +0,0 @@ -/*************************************************************************/ -/* string_db.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#ifndef STRING_DB_H -#define STRING_DB_H - -#include "core/os/mutex.h" -#include "core/safe_refcount.h" -#include "core/ustring.h" -/** - @author Juan Linietsky -*/ - -struct StaticCString { - - const char *ptr; - static StaticCString create(const char *p_ptr); -}; - -class StringName { - - enum { - - STRING_TABLE_BITS = 12, - STRING_TABLE_LEN = 1 << STRING_TABLE_BITS, - STRING_TABLE_MASK = STRING_TABLE_LEN - 1 - }; - - struct _Data { - SafeRefCount refcount; - const char *cname; - String name; - - String get_name() const { return cname ? String(cname) : name; } - int idx; - uint32_t hash; - _Data *prev; - _Data *next; - _Data() { - cname = NULL; - next = prev = NULL; - idx = 0; - hash = 0; - } - }; - - static _Data *_table[STRING_TABLE_LEN]; - - _Data *_data; - - union _HashUnion { - - _Data *ptr; - uint32_t hash; - }; - - void unref(); - friend void register_core_types(); - friend void unregister_core_types(); - - static Mutex *lock; - static void setup(); - static void cleanup(); - static bool configured; - - StringName(_Data *p_data) { _data = p_data; } - -public: - operator const void *() const { return (_data && (_data->cname || !_data->name.empty())) ? (void *)1 : 0; } - - bool operator==(const String &p_name) const; - bool operator==(const char *p_name) const; - bool operator!=(const String &p_name) const; - _FORCE_INLINE_ bool operator<(const StringName &p_name) const { - - return _data < p_name._data; - } - _FORCE_INLINE_ bool operator==(const StringName &p_name) const { - // the real magic of all this mess happens here. - // this is why path comparisons are very fast - return _data == p_name._data; - } - _FORCE_INLINE_ uint32_t hash() const { - - if (_data) - return _data->hash; - else - return 0; - } - _FORCE_INLINE_ const void *data_unique_pointer() const { - return (void *)_data; - } - bool operator!=(const StringName &p_name) const; - - _FORCE_INLINE_ operator String() const { - - if (_data) { - if (_data->cname) - return String(_data->cname); - else - return _data->name; - } - - return String(); - } - - static StringName search(const char *p_name); - static StringName search(const CharType *p_name); - static StringName search(const String &p_name); - - struct AlphCompare { - - _FORCE_INLINE_ bool operator()(const StringName &l, const StringName &r) const { - - const char *l_cname = l._data ? l._data->cname : ""; - const char *r_cname = r._data ? r._data->cname : ""; - - if (l_cname) { - - if (r_cname) - return is_str_less(l_cname, r_cname); - else - return is_str_less(l_cname, r._data->name.ptr()); - } else { - - if (r_cname) - return is_str_less(l._data->name.ptr(), r_cname); - else - return is_str_less(l._data->name.ptr(), r._data->name.ptr()); - } - } - }; - - void operator=(const StringName &p_name); - StringName(const char *p_name); - StringName(const StringName &p_name); - StringName(const String &p_name); - StringName(const StaticCString &p_static_string); - StringName(); - ~StringName(); -}; - -StringName _scs_create(const char *p_chr); - -#endif diff --git a/core/string_name.cpp b/core/string_name.cpp new file mode 100644 index 0000000000..10b71ad3ac --- /dev/null +++ b/core/string_name.cpp @@ -0,0 +1,426 @@ +/*************************************************************************/ +/* string_name.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "string_name.h" + +#include "core/os/os.h" +#include "core/print_string.h" + +StaticCString StaticCString::create(const char *p_ptr) { + StaticCString scs; + scs.ptr = p_ptr; + return scs; +} + +StringName::_Data *StringName::_table[STRING_TABLE_LEN]; + +StringName _scs_create(const char *p_chr) { + + return (p_chr[0] ? StringName(StaticCString::create(p_chr)) : StringName()); +} + +bool StringName::configured = false; +Mutex *StringName::lock = NULL; + +void StringName::setup() { + + lock = Mutex::create(); + + ERR_FAIL_COND(configured); + for (int i = 0; i < STRING_TABLE_LEN; i++) { + + _table[i] = NULL; + } + configured = true; +} + +void StringName::cleanup() { + + lock->lock(); + + int lost_strings = 0; + for (int i = 0; i < STRING_TABLE_LEN; i++) { + + while (_table[i]) { + + _Data *d = _table[i]; + lost_strings++; + if (OS::get_singleton()->is_stdout_verbose()) { + if (d->cname) { + print_line("Orphan StringName: " + String(d->cname)); + } else { + print_line("Orphan StringName: " + String(d->name)); + } + } + + _table[i] = _table[i]->next; + memdelete(d); + } + } + if (lost_strings) { + print_verbose("StringName: " + itos(lost_strings) + " unclaimed string names at exit."); + } + lock->unlock(); + + memdelete(lock); +} + +void StringName::unref() { + + ERR_FAIL_COND(!configured); + + if (_data && _data->refcount.unref()) { + + lock->lock(); + + if (_data->prev) { + _data->prev->next = _data->next; + } else { + if (_table[_data->idx] != _data) { + ERR_PRINT("BUG!"); + } + _table[_data->idx] = _data->next; + } + + if (_data->next) { + _data->next->prev = _data->prev; + } + memdelete(_data); + lock->unlock(); + } + + _data = NULL; +} + +bool StringName::operator==(const String &p_name) const { + + if (!_data) { + + return (p_name.length() == 0); + } + + return (_data->get_name() == p_name); +} + +bool StringName::operator==(const char *p_name) const { + + if (!_data) { + + return (p_name[0] == 0); + } + + return (_data->get_name() == p_name); +} + +bool StringName::operator!=(const String &p_name) const { + + return !(operator==(p_name)); +} + +bool StringName::operator!=(const StringName &p_name) const { + + // the real magic of all this mess happens here. + // this is why path comparisons are very fast + return _data != p_name._data; +} + +void StringName::operator=(const StringName &p_name) { + + if (this == &p_name) + return; + + unref(); + + if (p_name._data && p_name._data->refcount.ref()) { + + _data = p_name._data; + } +} + +StringName::StringName(const StringName &p_name) { + + _data = NULL; + + ERR_FAIL_COND(!configured); + + if (p_name._data && p_name._data->refcount.ref()) { + _data = p_name._data; + } +} + +StringName::StringName(const char *p_name) { + + _data = NULL; + + ERR_FAIL_COND(!configured); + + if (!p_name || p_name[0] == 0) + return; //empty, ignore + + lock->lock(); + + uint32_t hash = String::hash(p_name); + + uint32_t idx = hash & STRING_TABLE_MASK; + + _data = _table[idx]; + + while (_data) { + + // compare hash first + if (_data->hash == hash && _data->get_name() == p_name) + break; + _data = _data->next; + } + + if (_data) { + if (_data->refcount.ref()) { + // exists + lock->unlock(); + return; + } else { + } + } + + _data = memnew(_Data); + _data->name = p_name; + _data->refcount.init(); + _data->hash = hash; + _data->idx = idx; + _data->cname = NULL; + _data->next = _table[idx]; + _data->prev = NULL; + if (_table[idx]) + _table[idx]->prev = _data; + _table[idx] = _data; + + lock->unlock(); +} + +StringName::StringName(const StaticCString &p_static_string) { + + _data = NULL; + + ERR_FAIL_COND(!configured); + + ERR_FAIL_COND(!p_static_string.ptr || !p_static_string.ptr[0]); + + lock->lock(); + + uint32_t hash = String::hash(p_static_string.ptr); + + uint32_t idx = hash & STRING_TABLE_MASK; + + _data = _table[idx]; + + while (_data) { + + // compare hash first + if (_data->hash == hash && _data->get_name() == p_static_string.ptr) + break; + _data = _data->next; + } + + if (_data) { + if (_data->refcount.ref()) { + // exists + lock->unlock(); + return; + } else { + } + } + + _data = memnew(_Data); + + _data->refcount.init(); + _data->hash = hash; + _data->idx = idx; + _data->cname = p_static_string.ptr; + _data->next = _table[idx]; + _data->prev = NULL; + if (_table[idx]) + _table[idx]->prev = _data; + _table[idx] = _data; + + lock->unlock(); +} + +StringName::StringName(const String &p_name) { + + _data = NULL; + + ERR_FAIL_COND(!configured); + + if (p_name == String()) + return; + + lock->lock(); + + uint32_t hash = p_name.hash(); + + uint32_t idx = hash & STRING_TABLE_MASK; + + _data = _table[idx]; + + while (_data) { + + if (_data->hash == hash && _data->get_name() == p_name) + break; + _data = _data->next; + } + + if (_data) { + if (_data->refcount.ref()) { + // exists + lock->unlock(); + return; + } else { + } + } + + _data = memnew(_Data); + _data->name = p_name; + _data->refcount.init(); + _data->hash = hash; + _data->idx = idx; + _data->cname = NULL; + _data->next = _table[idx]; + _data->prev = NULL; + if (_table[idx]) + _table[idx]->prev = _data; + _table[idx] = _data; + + lock->unlock(); +} + +StringName StringName::search(const char *p_name) { + + ERR_FAIL_COND_V(!configured, StringName()); + + ERR_FAIL_COND_V(!p_name, StringName()); + if (!p_name[0]) + return StringName(); + + lock->lock(); + + uint32_t hash = String::hash(p_name); + + uint32_t idx = hash & STRING_TABLE_MASK; + + _Data *_data = _table[idx]; + + while (_data) { + + // compare hash first + if (_data->hash == hash && _data->get_name() == p_name) + break; + _data = _data->next; + } + + if (_data && _data->refcount.ref()) { + lock->unlock(); + + return StringName(_data); + } + + lock->unlock(); + return StringName(); //does not exist +} + +StringName StringName::search(const CharType *p_name) { + + ERR_FAIL_COND_V(!configured, StringName()); + + ERR_FAIL_COND_V(!p_name, StringName()); + if (!p_name[0]) + return StringName(); + + lock->lock(); + + uint32_t hash = String::hash(p_name); + + uint32_t idx = hash & STRING_TABLE_MASK; + + _Data *_data = _table[idx]; + + while (_data) { + + // compare hash first + if (_data->hash == hash && _data->get_name() == p_name) + break; + _data = _data->next; + } + + if (_data && _data->refcount.ref()) { + lock->unlock(); + return StringName(_data); + } + + lock->unlock(); + return StringName(); //does not exist +} +StringName StringName::search(const String &p_name) { + + ERR_FAIL_COND_V(p_name == "", StringName()); + + lock->lock(); + + uint32_t hash = p_name.hash(); + + uint32_t idx = hash & STRING_TABLE_MASK; + + _Data *_data = _table[idx]; + + while (_data) { + + // compare hash first + if (_data->hash == hash && p_name == _data->get_name()) + break; + _data = _data->next; + } + + if (_data && _data->refcount.ref()) { + lock->unlock(); + return StringName(_data); + } + + lock->unlock(); + return StringName(); //does not exist +} + +StringName::StringName() { + + _data = NULL; +} + +StringName::~StringName() { + + unref(); +} diff --git a/core/string_name.h b/core/string_name.h new file mode 100644 index 0000000000..0984b0181f --- /dev/null +++ b/core/string_name.h @@ -0,0 +1,172 @@ +/*************************************************************************/ +/* string_name.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef STRING_NAME_H +#define STRING_NAME_H + +#include "core/os/mutex.h" +#include "core/safe_refcount.h" +#include "core/ustring.h" +/** + @author Juan Linietsky +*/ + +struct StaticCString { + + const char *ptr; + static StaticCString create(const char *p_ptr); +}; + +class StringName { + + enum { + + STRING_TABLE_BITS = 12, + STRING_TABLE_LEN = 1 << STRING_TABLE_BITS, + STRING_TABLE_MASK = STRING_TABLE_LEN - 1 + }; + + struct _Data { + SafeRefCount refcount; + const char *cname; + String name; + + String get_name() const { return cname ? String(cname) : name; } + int idx; + uint32_t hash; + _Data *prev; + _Data *next; + _Data() { + cname = NULL; + next = prev = NULL; + idx = 0; + hash = 0; + } + }; + + static _Data *_table[STRING_TABLE_LEN]; + + _Data *_data; + + union _HashUnion { + + _Data *ptr; + uint32_t hash; + }; + + void unref(); + friend void register_core_types(); + friend void unregister_core_types(); + + static Mutex *lock; + static void setup(); + static void cleanup(); + static bool configured; + + StringName(_Data *p_data) { _data = p_data; } + +public: + operator const void *() const { return (_data && (_data->cname || !_data->name.empty())) ? (void *)1 : 0; } + + bool operator==(const String &p_name) const; + bool operator==(const char *p_name) const; + bool operator!=(const String &p_name) const; + _FORCE_INLINE_ bool operator<(const StringName &p_name) const { + + return _data < p_name._data; + } + _FORCE_INLINE_ bool operator==(const StringName &p_name) const { + // the real magic of all this mess happens here. + // this is why path comparisons are very fast + return _data == p_name._data; + } + _FORCE_INLINE_ uint32_t hash() const { + + if (_data) + return _data->hash; + else + return 0; + } + _FORCE_INLINE_ const void *data_unique_pointer() const { + return (void *)_data; + } + bool operator!=(const StringName &p_name) const; + + _FORCE_INLINE_ operator String() const { + + if (_data) { + if (_data->cname) + return String(_data->cname); + else + return _data->name; + } + + return String(); + } + + static StringName search(const char *p_name); + static StringName search(const CharType *p_name); + static StringName search(const String &p_name); + + struct AlphCompare { + + _FORCE_INLINE_ bool operator()(const StringName &l, const StringName &r) const { + + const char *l_cname = l._data ? l._data->cname : ""; + const char *r_cname = r._data ? r._data->cname : ""; + + if (l_cname) { + + if (r_cname) + return is_str_less(l_cname, r_cname); + else + return is_str_less(l_cname, r._data->name.ptr()); + } else { + + if (r_cname) + return is_str_less(l._data->name.ptr(), r_cname); + else + return is_str_less(l._data->name.ptr(), r._data->name.ptr()); + } + } + }; + + void operator=(const StringName &p_name); + StringName(const char *p_name); + StringName(const StringName &p_name); + StringName(const String &p_name); + StringName(const StaticCString &p_static_string); + StringName(); + ~StringName(); +}; + +StringName _scs_create(const char *p_chr); + +#endif // STRING_NAME_H diff --git a/core/variant.h b/core/variant.h index 6ddaf17406..a819ba1f8c 100644 --- a/core/variant.h +++ b/core/variant.h @@ -38,7 +38,6 @@ #include "core/array.h" #include "core/color.h" #include "core/dictionary.h" -#include "core/dvector.h" #include "core/io/ip_address.h" #include "core/math/aabb.h" #include "core/math/basis.h" @@ -49,6 +48,7 @@ #include "core/math/transform_2d.h" #include "core/math/vector3.h" #include "core/node_path.h" +#include "core/pool_vector.h" #include "core/ref_ptr.h" #include "core/rid.h" #include "core/ustring.h" diff --git a/core/variant_construct_string.cpp b/core/variant_construct_string.cpp deleted file mode 100644 index 2cb7481634..0000000000 --- a/core/variant_construct_string.cpp +++ /dev/null @@ -1,438 +0,0 @@ -/*************************************************************************/ -/* variant_construct_string.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#include "variant.h" - -class VariantConstruct { - - enum TokenType { - TK_CURLY_BRACKET_OPEN, - TK_CURLY_BRACKET_CLOSE, - TK_BRACKET_OPEN, - TK_BRACKET_CLOSE, - TK_IDENTIFIER, - TK_STRING, - TK_NUMBER, - TK_COLON, - TK_COMMA, - TK_EOF, - TK_MAX - }; - - enum Expecting { - - EXPECT_OBJECT, - EXPECT_OBJECT_KEY, - EXPECT_COLON, - EXPECT_OBJECT_VALUE, - }; - - struct Token { - - TokenType type; - Variant value; - }; - - static const char *tk_name[TK_MAX]; - - static String _print_var(const Variant &p_var); - - static Error _get_token(const CharType *p_str, int &index, int p_len, Token &r_token, int &line, String &r_err_str); - static Error _parse_value(Variant &value, Token &token, const CharType *p_str, int &index, int p_len, int &line, String &r_err_str, Variant::ObjectConstruct *p_construct, void *p_ud); - static Error _parse_array(Array &array, const CharType *p_str, int &index, int p_len, int &line, String &r_err_str, Variant::ObjectConstruct *p_construct, void *p_ud); - static Error _parse_dict(Dictionary &dict, const CharType *p_str, int &index, int p_len, int &line, String &r_err_str, Variant::ObjectConstruct *p_construct, void *p_ud); - -public: - static Error parse(const String &p_string, Variant &r_ret, String &r_err_str, int &r_err_line, Variant::ObjectConstruct *p_construct, void *p_ud); -}; - -const char *VariantConstruct::tk_name[TK_MAX] = { - "'{'", - "'}'", - "'['", - "']'", - "identifier", - "string", - "number", - "':'", - "','", - "EOF", -}; - -Error VariantConstruct::_get_token(const CharType *p_str, int &index, int p_len, Token &r_token, int &line, String &r_err_str) { - - while (true) { - switch (p_str[index]) { - - case '\n': { - - line++; - index++; - break; - }; - case 0: { - r_token.type = TK_EOF; - return OK; - } break; - case '{': { - - r_token.type = TK_CURLY_BRACKET_OPEN; - index++; - return OK; - }; - case '}': { - - r_token.type = TK_CURLY_BRACKET_CLOSE; - index++; - return OK; - }; - case '[': { - - r_token.type = TK_BRACKET_OPEN; - index++; - return OK; - }; - case ']': { - - r_token.type = TK_BRACKET_CLOSE; - index++; - return OK; - }; - case ':': { - - r_token.type = TK_COLON; - index++; - return OK; - }; - case ',': { - - r_token.type = TK_COMMA; - index++; - return OK; - }; - case '"': { - - index++; - String str; - while (true) { - if (p_str[index] == 0) { - r_err_str = "Unterminated String"; - return ERR_PARSE_ERROR; - } else if (p_str[index] == '"') { - index++; - break; - } else if (p_str[index] == '\\') { - //escaped characters... - index++; - CharType next = p_str[index]; - if (next == 0) { - r_err_str = "Unterminated String"; - return ERR_PARSE_ERROR; - } - CharType res = 0; - - switch (next) { - - case 'b': res = 8; break; - case 't': res = 9; break; - case 'n': res = 10; break; - case 'f': res = 12; break; - case 'r': res = 13; break; - case '\"': res = '\"'; break; - case '\\': res = '\\'; break; - case '/': res = '/'; break; - case 'u': { - //hexnumbarh - oct is deprecated - - for (int j = 0; j < 4; j++) { - CharType c = p_str[index + j + 1]; - if (c == 0) { - r_err_str = "Unterminated String"; - return ERR_PARSE_ERROR; - } - if (!((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'))) { - - r_err_str = "Malformed hex constant in string"; - return ERR_PARSE_ERROR; - } - CharType v; - if (c >= '0' && c <= '9') { - v = c - '0'; - } else if (c >= 'a' && c <= 'f') { - v = c - 'a'; - v += 10; - } else if (c >= 'A' && c <= 'F') { - v = c - 'A'; - v += 10; - } else { - ERR_PRINT("BUG"); - v = 0; - } - - res <<= 4; - res |= v; - } - index += 4; //will add at the end anyway - - } break; - default: { - - r_err_str = "Invalid escape sequence"; - return ERR_PARSE_ERROR; - } break; - } - - str += res; - - } else { - if (p_str[index] == '\n') - line++; - str += p_str[index]; - } - index++; - } - - r_token.type = TK_STRING; - r_token.value = str; - return OK; - - } break; - default: { - - if (p_str[index] <= 32) { - index++; - break; - } - - if (p_str[index] == '-' || (p_str[index] >= '0' && p_str[index] <= '9')) { - //a number - const CharType *rptr; - double number = String::to_double(&p_str[index], &rptr); - index += (rptr - &p_str[index]); - r_token.type = TK_NUMBER; - r_token.value = number; - return OK; - - } else if ((p_str[index] >= 'A' && p_str[index] <= 'Z') || (p_str[index] >= 'a' && p_str[index] <= 'z')) { - - String id; - - while ((p_str[index] >= 'A' && p_str[index] <= 'Z') || (p_str[index] >= 'a' && p_str[index] <= 'z')) { - - id += p_str[index]; - index++; - } - - r_token.type = TK_IDENTIFIER; - r_token.value = id; - return OK; - } else { - r_err_str = "Unexpected character."; - return ERR_PARSE_ERROR; - } - } - } - } - - return ERR_PARSE_ERROR; -} - -Error VariantConstruct::_parse_value(Variant &value, Token &token, const CharType *p_str, int &index, int p_len, int &line, String &r_err_str, Variant::ObjectConstruct *p_construct, void *p_ud) { - - if (token.type == TK_CURLY_BRACKET_OPEN) { - - Dictionary d; - Error err = _parse_dict(d, p_str, index, p_len, line, r_err_str, p_construct, p_ud); - if (err) - return err; - value = d; - return OK; - } else if (token.type == TK_BRACKET_OPEN) { - - Array a; - Error err = _parse_array(a, p_str, index, p_len, line, r_err_str, p_construct, p_ud); - if (err) - return err; - value = a; - return OK; - - } else if (token.type == TK_IDENTIFIER) { - - String id = token.value; - if (id == "true") - value = true; - else if (id == "false") - value = false; - else if (id == "null") - value = Variant(); - else { - r_err_str = "Expected 'true','false' or 'null', got '" + id + "'."; - return ERR_PARSE_ERROR; - } - return OK; - - } else if (token.type == TK_NUMBER) { - - value = token.value; - return OK; - } else if (token.type == TK_STRING) { - - value = token.value; - return OK; - } else { - r_err_str = "Expected value, got " + String(tk_name[token.type]) + "."; - return ERR_PARSE_ERROR; - } - - return ERR_PARSE_ERROR; -} - -Error VariantConstruct::_parse_array(Array &array, const CharType *p_str, int &index, int p_len, int &line, String &r_err_str, Variant::ObjectConstruct *p_construct, void *p_ud) { - - Token token; - bool need_comma = false; - - while (index < p_len) { - - Error err = _get_token(p_str, index, p_len, token, line, r_err_str); - if (err != OK) - return err; - - if (token.type == TK_BRACKET_CLOSE) { - - return OK; - } - - if (need_comma) { - - if (token.type != TK_COMMA) { - - r_err_str = "Expected ','"; - return ERR_PARSE_ERROR; - } else { - need_comma = false; - continue; - } - } - - Variant v; - err = _parse_value(v, token, p_str, index, p_len, line, r_err_str, p_construct, p_ud); - if (err) - return err; - - array.push_back(v); - need_comma = true; - } - - return OK; -} - -Error VariantConstruct::_parse_dict(Dictionary &dict, const CharType *p_str, int &index, int p_len, int &line, String &r_err_str, Variant::ObjectConstruct *p_construct, void *p_ud) { - - bool at_key = true; - Variant key; - Token token; - bool need_comma = false; - - while (index < p_len) { - - if (at_key) { - - Error err = _get_token(p_str, index, p_len, token, line, r_err_str); - if (err != OK) - return err; - - if (token.type == TK_CURLY_BRACKET_CLOSE) { - - return OK; - } - - if (need_comma) { - - if (token.type != TK_COMMA) { - - r_err_str = "Expected '}' or ','"; - return ERR_PARSE_ERROR; - } else { - need_comma = false; - continue; - } - } - - err = _parse_value(key, token, p_str, index, p_len, line, r_err_str, p_construct, p_ud); - - if (err != OK) - return err; - - err = _get_token(p_str, index, p_len, token, line, r_err_str); - - if (err != OK) - return err; - - if (token.type != TK_COLON) { - - r_err_str = "Expected ':'"; - return ERR_PARSE_ERROR; - } - at_key = false; - } else { - - Error err = _get_token(p_str, index, p_len, token, line, r_err_str); - if (err != OK) - return err; - - Variant v; - err = _parse_value(v, token, p_str, index, p_len, line, r_err_str, p_construct, p_ud); - if (err) - return err; - dict[key] = v; - need_comma = true; - at_key = true; - } - } - - return OK; -} - -Error VariantConstruct::parse(const String &p_string, Variant &r_ret, String &r_err_str, int &r_err_line, Variant::ObjectConstruct *p_construct, void *p_ud) { - - const CharType *str = p_string.ptr(); - int idx = 0; - int len = p_string.length(); - Token token; - r_err_line = 0; - String aux_key; - - Error err = _get_token(str, idx, len, token, r_err_line, r_err_str); - if (err) - return err; - - return _parse_value(r_ret, token, str, idx, len, r_err_line, r_err_str, p_construct, p_ud); -} diff --git a/core/vector.h b/core/vector.h index 90b3d90826..93ee003519 100644 --- a/core/vector.h +++ b/core/vector.h @@ -40,7 +40,7 @@ #include "core/cowdata.h" #include "core/error_macros.h" #include "core/os/memory.h" -#include "core/sort.h" +#include "core/sort_array.h" template class VectorWriteProxy { diff --git a/drivers/gles2/rasterizer_storage_gles2.h b/drivers/gles2/rasterizer_storage_gles2.h index ba48ddd185..a0fa2aacc5 100644 --- a/drivers/gles2/rasterizer_storage_gles2.h +++ b/drivers/gles2/rasterizer_storage_gles2.h @@ -31,7 +31,7 @@ #ifndef RASTERIZERSTORAGEGLES2_H #define RASTERIZERSTORAGEGLES2_H -#include "core/dvector.h" +#include "core/pool_vector.h" #include "core/self_list.h" #include "servers/visual/rasterizer.h" #include "servers/visual/shader_language.h" diff --git a/drivers/windows/shell_windows.cpp b/drivers/windows/shell_windows.cpp deleted file mode 100644 index 731d16d18d..0000000000 --- a/drivers/windows/shell_windows.cpp +++ /dev/null @@ -1,67 +0,0 @@ -/*************************************************************************/ -/* shell_windows.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#ifdef WINDOWS_ENABLED - -#ifdef UWP_ENABLED - -// Use Launcher class on windows 8 - -#else - -// -// C++ Implementation: shell_windows -// -// Description: -// -// -// Author: Juan Linietsky , (C) 2008 -// -// Copyright: See COPYING file that comes with this distribution -// -// -#include "shell_windows.h" - -#include - -void ShellWindows::execute(String p_path) { - - ShellExecuteW(NULL, L"open", p_path.c_str(), NULL, NULL, SW_SHOWNORMAL); -} - -ShellWindows::ShellWindows() { -} - -ShellWindows::~ShellWindows() { -} - -#endif - -#endif diff --git a/drivers/windows/shell_windows.h b/drivers/windows/shell_windows.h deleted file mode 100644 index 9e9edd2f62..0000000000 --- a/drivers/windows/shell_windows.h +++ /dev/null @@ -1,52 +0,0 @@ -/*************************************************************************/ -/* shell_windows.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#ifndef SHELL_WINDOWS_H -#define SHELL_WINDOWS_H - -#include "core/os/shell.h" - -#ifdef WINDOWS_ENABLED - -/** - @author Juan Linietsky -*/ - -class ShellWindows : public Shell { -public: - virtual void execute(String p_path); - - ShellWindows(); - - ~ShellWindows(); -}; - -#endif -#endif diff --git a/editor/editor_file_system.cpp b/editor/editor_file_system.cpp index fe8d57d1a1..a262f1886c 100644 --- a/editor/editor_file_system.cpp +++ b/editor/editor_file_system.cpp @@ -30,7 +30,7 @@ #include "editor_file_system.h" -#include "core/io/resource_import.h" +#include "core/io/resource_importer.h" #include "core/io/resource_loader.h" #include "core/io/resource_saver.h" #include "core/os/file_access.h" diff --git a/editor/import/editor_import_plugin.h b/editor/import/editor_import_plugin.h index 9e64fdb7c7..607d99e6e2 100644 --- a/editor/import/editor_import_plugin.h +++ b/editor/import/editor_import_plugin.h @@ -31,7 +31,7 @@ #ifndef EDITOR_IMPORT_PLUGIN_H #define EDITOR_IMPORT_PLUGIN_H -#include "core/io/resource_import.h" +#include "core/io/resource_importer.h" class EditorImportPlugin : public ResourceImporter { GDCLASS(EditorImportPlugin, Reference) diff --git a/editor/import/resource_importer_bitmask.h b/editor/import/resource_importer_bitmask.h index b0168e2b53..7cfb0c4a98 100644 --- a/editor/import/resource_importer_bitmask.h +++ b/editor/import/resource_importer_bitmask.h @@ -32,7 +32,7 @@ #define RESOURCE_IMPORTER_BITMASK_H #include "core/image.h" -#include "core/io/resource_import.h" +#include "core/io/resource_importer.h" class StreamBitMap; diff --git a/editor/import/resource_importer_csv_translation.h b/editor/import/resource_importer_csv_translation.h index 3d74731e8c..cf16826535 100644 --- a/editor/import/resource_importer_csv_translation.h +++ b/editor/import/resource_importer_csv_translation.h @@ -31,7 +31,7 @@ #ifndef RESOURCEIMPORTERCSVTRANSLATION_H #define RESOURCEIMPORTERCSVTRANSLATION_H -#include "core/io/resource_import.h" +#include "core/io/resource_importer.h" class ResourceImporterCSVTranslation : public ResourceImporter { GDCLASS(ResourceImporterCSVTranslation, ResourceImporter) diff --git a/editor/import/resource_importer_image.h b/editor/import/resource_importer_image.h index b38d833c5b..ffe05bdf58 100644 --- a/editor/import/resource_importer_image.h +++ b/editor/import/resource_importer_image.h @@ -32,7 +32,7 @@ #define RESOURCE_IMPORTER_IMAGE_H #include "core/image.h" -#include "core/io/resource_import.h" +#include "core/io/resource_importer.h" class ResourceImporterImage : public ResourceImporter { GDCLASS(ResourceImporterImage, ResourceImporter) diff --git a/editor/import/resource_importer_layered_texture.h b/editor/import/resource_importer_layered_texture.h index 599fdf12fa..6a616e09d6 100644 --- a/editor/import/resource_importer_layered_texture.h +++ b/editor/import/resource_importer_layered_texture.h @@ -32,7 +32,7 @@ #define RESOURCE_IMPORTER_LAYERED_TEXTURE_H #include "core/image.h" -#include "core/io/resource_import.h" +#include "core/io/resource_importer.h" class StreamTexture; diff --git a/editor/import/resource_importer_scene.h b/editor/import/resource_importer_scene.h index 9435b6599a..9d06b411d6 100644 --- a/editor/import/resource_importer_scene.h +++ b/editor/import/resource_importer_scene.h @@ -31,7 +31,7 @@ #ifndef RESOURCEIMPORTERSCENE_H #define RESOURCEIMPORTERSCENE_H -#include "core/io/resource_import.h" +#include "core/io/resource_importer.h" #include "scene/resources/animation.h" #include "scene/resources/mesh.h" #include "scene/resources/shape.h" diff --git a/editor/import/resource_importer_texture.h b/editor/import/resource_importer_texture.h index 900654c114..408af1edcf 100644 --- a/editor/import/resource_importer_texture.h +++ b/editor/import/resource_importer_texture.h @@ -32,7 +32,7 @@ #define RESOURCEIMPORTTEXTURE_H #include "core/image.h" -#include "core/io/resource_import.h" +#include "core/io/resource_importer.h" class StreamTexture; diff --git a/editor/import/resource_importer_wav.h b/editor/import/resource_importer_wav.h index 68e677b977..755dea3d84 100644 --- a/editor/import/resource_importer_wav.h +++ b/editor/import/resource_importer_wav.h @@ -31,7 +31,7 @@ #ifndef RESOURCEIMPORTWAV_H #define RESOURCEIMPORTWAV_H -#include "core/io/resource_import.h" +#include "core/io/resource_importer.h" class ResourceImporterWAV : public ResourceImporter { GDCLASS(ResourceImporterWAV, ResourceImporter) diff --git a/editor/import_dock.h b/editor/import_dock.h index 1d43e00b63..77a34e80eb 100644 --- a/editor/import_dock.h +++ b/editor/import_dock.h @@ -32,7 +32,7 @@ #define IMPORTDOCK_H #include "core/io/config_file.h" -#include "core/io/resource_import.h" +#include "core/io/resource_importer.h" #include "editor/editor_file_system.h" #include "editor/editor_inspector.h" #include "scene/gui/box_container.h" diff --git a/editor/plugins/spatial_editor_plugin.cpp b/editor/plugins/spatial_editor_plugin.cpp index 9ece812c49..0704e57bb9 100644 --- a/editor/plugins/spatial_editor_plugin.cpp +++ b/editor/plugins/spatial_editor_plugin.cpp @@ -35,7 +35,7 @@ #include "core/os/keyboard.h" #include "core/print_string.h" #include "core/project_settings.h" -#include "core/sort.h" +#include "core/sort_array.h" #include "editor/editor_node.h" #include "editor/editor_settings.h" #include "editor/plugins/animation_player_editor_plugin.h" diff --git a/modules/csg/csg.cpp b/modules/csg/csg.cpp index 12282b4730..a0be0138d3 100644 --- a/modules/csg/csg.cpp +++ b/modules/csg/csg.cpp @@ -32,7 +32,7 @@ #include "core/math/face3.h" #include "core/math/geometry.h" #include "core/os/os.h" -#include "core/sort.h" +#include "core/sort_array.h" #include "thirdparty/misc/triangulator.h" void CSGBrush::clear() { diff --git a/modules/csg/csg.h b/modules/csg/csg.h index ac16575e82..4fa1a945cc 100644 --- a/modules/csg/csg.h +++ b/modules/csg/csg.h @@ -31,7 +31,6 @@ #ifndef CSG_H #define CSG_H -#include "core/dvector.h" #include "core/map.h" #include "core/math/aabb.h" #include "core/math/plane.h" @@ -39,6 +38,7 @@ #include "core/math/transform.h" #include "core/math/vector3.h" #include "core/oa_hash_map.h" +#include "core/pool_vector.h" #include "scene/resources/material.h" struct CSGBrush { diff --git a/modules/gdnative/gdnative/array.cpp b/modules/gdnative/gdnative/array.cpp index 18da9d811e..6849ff03d7 100644 --- a/modules/gdnative/gdnative/array.cpp +++ b/modules/gdnative/gdnative/array.cpp @@ -34,7 +34,7 @@ #include "core/os/memory.h" #include "core/color.h" -#include "core/dvector.h" +#include "core/pool_vector.h" #include "core/variant.h" diff --git a/modules/gdnative/gdnative/pool_arrays.cpp b/modules/gdnative/gdnative/pool_arrays.cpp index 68e064d829..74c540ca14 100644 --- a/modules/gdnative/gdnative/pool_arrays.cpp +++ b/modules/gdnative/gdnative/pool_arrays.cpp @@ -31,7 +31,7 @@ #include "gdnative/pool_arrays.h" #include "core/array.h" -#include "core/dvector.h" +#include "core/pool_vector.h" #include "core/variant.h" #include "core/color.h" diff --git a/modules/gdnative/gdnative/string.cpp b/modules/gdnative/gdnative/string.cpp index 4b8d79305c..913c57eb56 100644 --- a/modules/gdnative/gdnative/string.cpp +++ b/modules/gdnative/gdnative/string.cpp @@ -30,7 +30,7 @@ #include "gdnative/string.h" -#include "core/string_db.h" +#include "core/string_name.h" #include "core/ustring.h" #include "core/variant.h" diff --git a/modules/gdnative/gdnative/string_name.cpp b/modules/gdnative/gdnative/string_name.cpp index d2862c5980..dcbb773c25 100644 --- a/modules/gdnative/gdnative/string_name.cpp +++ b/modules/gdnative/gdnative/string_name.cpp @@ -30,7 +30,7 @@ #include "gdnative/string_name.h" -#include "core/string_db.h" +#include "core/string_name.h" #include "core/ustring.h" #include diff --git a/modules/gdscript/gdscript_function.h b/modules/gdscript/gdscript_function.h index a412b2950f..cefc28d77f 100644 --- a/modules/gdscript/gdscript_function.h +++ b/modules/gdscript/gdscript_function.h @@ -36,7 +36,7 @@ #include "core/reference.h" #include "core/script_language.h" #include "core/self_list.h" -#include "core/string_db.h" +#include "core/string_name.h" #include "core/variant.h" class GDScriptInstance; diff --git a/modules/gdscript/gdscript_tokenizer.h b/modules/gdscript/gdscript_tokenizer.h index abacdf0322..e4315f7969 100644 --- a/modules/gdscript/gdscript_tokenizer.h +++ b/modules/gdscript/gdscript_tokenizer.h @@ -32,7 +32,7 @@ #define GDSCRIPT_TOKENIZER_H #include "core/pair.h" -#include "core/string_db.h" +#include "core/string_name.h" #include "core/ustring.h" #include "core/variant.h" #include "core/vmap.h" diff --git a/modules/mono/glue/base_object_glue.cpp b/modules/mono/glue/base_object_glue.cpp index 2963619b79..fad02b01d3 100644 --- a/modules/mono/glue/base_object_glue.cpp +++ b/modules/mono/glue/base_object_glue.cpp @@ -33,7 +33,7 @@ #ifdef MONO_GLUE_ENABLED #include "core/reference.h" -#include "core/string_db.h" +#include "core/string_name.h" #include "../csharp_script.h" #include "../mono_gd/gd_mono_internals.h" diff --git a/modules/stb_vorbis/resource_importer_ogg_vorbis.h b/modules/stb_vorbis/resource_importer_ogg_vorbis.h index ca2d662e61..f61fc91cda 100644 --- a/modules/stb_vorbis/resource_importer_ogg_vorbis.h +++ b/modules/stb_vorbis/resource_importer_ogg_vorbis.h @@ -32,7 +32,7 @@ #define RESOURCEIMPORTEROGGVORBIS_H #include "audio_stream_ogg_vorbis.h" -#include "core/io/resource_import.h" +#include "core/io/resource_importer.h" class ResourceImporterOGGVorbis : public ResourceImporter { GDCLASS(ResourceImporterOGGVorbis, ResourceImporter) diff --git a/scene/scene_string_names.h b/scene/scene_string_names.h index 103b06dbc1..4d1a7f255c 100644 --- a/scene/scene_string_names.h +++ b/scene/scene_string_names.h @@ -32,7 +32,7 @@ #define SCENE_STRING_NAMES_H #include "core/node_path.h" -#include "core/string_db.h" +#include "core/string_name.h" class SceneStringNames { friend void register_scene_types(); diff --git a/servers/physics/shape_sw.cpp b/servers/physics/shape_sw.cpp index fdc5eccc5a..d40de669fd 100644 --- a/servers/physics/shape_sw.cpp +++ b/servers/physics/shape_sw.cpp @@ -32,7 +32,7 @@ #include "core/math/geometry.h" #include "core/math/quick_hull.h" -#include "core/sort.h" +#include "core/sort_array.h" #define _POINT_SNAP 0.001953125 #define _EDGE_IS_VALID_SUPPORT_THRESHOLD 0.0002 diff --git a/servers/physics_2d/shape_2d_sw.cpp b/servers/physics_2d/shape_2d_sw.cpp index 558700f400..b622550ec9 100644 --- a/servers/physics_2d/shape_2d_sw.cpp +++ b/servers/physics_2d/shape_2d_sw.cpp @@ -31,7 +31,7 @@ #include "shape_2d_sw.h" #include "core/math/geometry.h" -#include "core/sort.h" +#include "core/sort_array.h" void Shape2DSW::configure(const Rect2 &p_aabb) { aabb = p_aabb; diff --git a/servers/visual/shader_language.h b/servers/visual/shader_language.h index 185bad4222..acc3297bed 100644 --- a/servers/visual/shader_language.h +++ b/servers/visual/shader_language.h @@ -33,7 +33,7 @@ #include "core/list.h" #include "core/map.h" -#include "core/string_db.h" +#include "core/string_name.h" #include "core/typedefs.h" #include "core/ustring.h" #include "core/variant.h" diff --git a/servers/visual/visual_server_raster.cpp b/servers/visual/visual_server_raster.cpp index 7be3bc562d..b18fabd467 100644 --- a/servers/visual/visual_server_raster.cpp +++ b/servers/visual/visual_server_raster.cpp @@ -33,7 +33,7 @@ #include "core/io/marshalls.h" #include "core/os/os.h" #include "core/project_settings.h" -#include "core/sort.h" +#include "core/sort_array.h" #include "visual_server_canvas.h" #include "visual_server_global.h" #include "visual_server_scene.h" diff --git a/servers/visual/visual_server_raster.h b/servers/visual/visual_server_raster.h index e6434189f9..ec6e50753e 100644 --- a/servers/visual/visual_server_raster.h +++ b/servers/visual/visual_server_raster.h @@ -31,7 +31,6 @@ #ifndef VISUAL_SERVER_RASTER_H #define VISUAL_SERVER_RASTER_H -#include "core/allocators.h" #include "core/math/octree.h" #include "servers/visual/rasterizer.h" #include "servers/visual_server.h" diff --git a/servers/visual/visual_server_scene.h b/servers/visual/visual_server_scene.h index 539855bdc4..7583acd88f 100644 --- a/servers/visual/visual_server_scene.h +++ b/servers/visual/visual_server_scene.h @@ -33,7 +33,6 @@ #include "servers/visual/rasterizer.h" -#include "core/allocators.h" #include "core/math/geometry.h" #include "core/math/octree.h" #include "core/os/semaphore.h" @@ -120,7 +119,6 @@ public: VS::ScenarioDebugMode debug; RID self; - // well wtf, balloon allocator is slower? Octree octree; -- cgit v1.2.3 From 75dae1b9a9db8f29f53cadce6ebbccf8698939b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Verschelde?= Date: Tue, 12 Feb 2019 14:23:35 +0100 Subject: Drivers, main, servers: Ensure classes match their header filename Renamed: - `drivers/alsamidi/alsa_midi.h` -> `midi_driver_alsamidi.h` (same for `coremidi` and `winmidi`) - `main/timer_sync.h` -> `main_timer_sync.h` - `servers/visual/visual_server_global.h` -> `visual_server_globals.h` --- drivers/alsamidi/alsa_midi.cpp | 202 -------------------- drivers/alsamidi/alsa_midi.h | 69 ------- drivers/alsamidi/midi_driver_alsamidi.cpp | 202 ++++++++++++++++++++ drivers/alsamidi/midi_driver_alsamidi.h | 69 +++++++ drivers/coremidi/core_midi.cpp | 123 ------------ drivers/coremidi/core_midi.h | 62 ------ drivers/coremidi/midi_driver_coremidi.cpp | 123 ++++++++++++ drivers/coremidi/midi_driver_coremidi.h | 62 ++++++ drivers/winmidi/midi_driver_winmidi.cpp | 107 +++++++++++ drivers/winmidi/midi_driver_winmidi.h | 61 ++++++ drivers/winmidi/win_midi.cpp | 107 ----------- drivers/winmidi/win_midi.h | 61 ------ main/main.cpp | 2 +- main/main_timer_sync.cpp | 223 ++++++++++++++++++++++ main/main_timer_sync.h | 101 ++++++++++ main/timer_sync.cpp | 223 ---------------------- main/timer_sync.h | 101 ---------- modules/gdnative/arvr/arvr_interface_gdnative.cpp | 2 +- modules/mobile_vr/mobile_vr_interface.cpp | 2 +- platform/osx/os_osx.h | 2 +- platform/windows/os_windows.h | 9 +- platform/x11/os_x11.h | 2 +- servers/visual/visual_server_canvas.cpp | 2 +- servers/visual/visual_server_global.cpp | 40 ---- servers/visual/visual_server_global.h | 54 ------ servers/visual/visual_server_globals.cpp | 40 ++++ servers/visual/visual_server_globals.h | 54 ++++++ servers/visual/visual_server_raster.cpp | 2 +- servers/visual/visual_server_raster.h | 2 +- servers/visual/visual_server_scene.cpp | 2 +- servers/visual/visual_server_viewport.cpp | 2 +- 31 files changed, 1057 insertions(+), 1056 deletions(-) delete mode 100644 drivers/alsamidi/alsa_midi.cpp delete mode 100644 drivers/alsamidi/alsa_midi.h create mode 100644 drivers/alsamidi/midi_driver_alsamidi.cpp create mode 100644 drivers/alsamidi/midi_driver_alsamidi.h delete mode 100644 drivers/coremidi/core_midi.cpp delete mode 100644 drivers/coremidi/core_midi.h create mode 100644 drivers/coremidi/midi_driver_coremidi.cpp create mode 100644 drivers/coremidi/midi_driver_coremidi.h create mode 100644 drivers/winmidi/midi_driver_winmidi.cpp create mode 100644 drivers/winmidi/midi_driver_winmidi.h delete mode 100644 drivers/winmidi/win_midi.cpp delete mode 100644 drivers/winmidi/win_midi.h create mode 100644 main/main_timer_sync.cpp create mode 100644 main/main_timer_sync.h delete mode 100644 main/timer_sync.cpp delete mode 100644 main/timer_sync.h delete mode 100644 servers/visual/visual_server_global.cpp delete mode 100644 servers/visual/visual_server_global.h create mode 100644 servers/visual/visual_server_globals.cpp create mode 100644 servers/visual/visual_server_globals.h diff --git a/drivers/alsamidi/alsa_midi.cpp b/drivers/alsamidi/alsa_midi.cpp deleted file mode 100644 index cd90c8912b..0000000000 --- a/drivers/alsamidi/alsa_midi.cpp +++ /dev/null @@ -1,202 +0,0 @@ -/*************************************************************************/ -/* alsa_midi.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#ifdef ALSAMIDI_ENABLED - -#include "alsa_midi.h" - -#include "core/os/os.h" -#include "core/print_string.h" - -#include - -static int get_message_size(uint8_t message) { - switch (message & 0xF0) { - case 0x80: // note off - case 0x90: // note on - case 0xA0: // aftertouch - case 0xB0: // continuous controller - return 3; - - case 0xC0: // patch change - case 0xD0: // channel pressure - case 0xE0: // pitch bend - return 2; - } - - return 256; -} - -void MIDIDriverALSAMidi::thread_func(void *p_udata) { - MIDIDriverALSAMidi *md = (MIDIDriverALSAMidi *)p_udata; - uint64_t timestamp = 0; - uint8_t buffer[256]; - int expected_size = 255; - int bytes = 0; - - while (!md->exit_thread) { - int ret; - - md->lock(); - - for (int i = 0; i < md->connected_inputs.size(); i++) { - snd_rawmidi_t *midi_in = md->connected_inputs[i]; - do { - uint8_t byte = 0; - ret = snd_rawmidi_read(midi_in, &byte, 1); - if (ret < 0) { - if (ret != -EAGAIN) { - ERR_PRINTS("snd_rawmidi_read error: " + String(snd_strerror(ret))); - } - } else { - if (byte & 0x80) { - // Flush previous packet if there is any - if (bytes) { - md->receive_input_packet(timestamp, buffer, bytes); - bytes = 0; - } - expected_size = get_message_size(byte); - } - - if (bytes < 256) { - buffer[bytes++] = byte; - // If we know the size of the current packet receive it if it reached the expected size - if (bytes >= expected_size) { - md->receive_input_packet(timestamp, buffer, bytes); - bytes = 0; - } - } - } - } while (ret > 0); - } - - md->unlock(); - - OS::get_singleton()->delay_usec(1000); - } -} - -Error MIDIDriverALSAMidi::open() { - - void **hints; - - if (snd_device_name_hint(-1, "rawmidi", &hints) < 0) - return ERR_CANT_OPEN; - - int i = 0; - for (void **n = hints; *n != NULL; n++) { - char *name = snd_device_name_get_hint(*n, "NAME"); - - if (name != NULL) { - snd_rawmidi_t *midi_in; - int ret = snd_rawmidi_open(&midi_in, NULL, name, SND_RAWMIDI_NONBLOCK); - if (ret >= 0) { - connected_inputs.insert(i++, midi_in); - } - } - - if (name != NULL) - free(name); - } - snd_device_name_free_hint(hints); - - mutex = Mutex::create(); - thread = Thread::create(MIDIDriverALSAMidi::thread_func, this); - - return OK; -} - -void MIDIDriverALSAMidi::close() { - - if (thread) { - exit_thread = true; - Thread::wait_to_finish(thread); - - memdelete(thread); - thread = NULL; - } - - if (mutex) { - memdelete(mutex); - mutex = NULL; - } - - for (int i = 0; i < connected_inputs.size(); i++) { - snd_rawmidi_t *midi_in = connected_inputs[i]; - snd_rawmidi_close(midi_in); - } - connected_inputs.clear(); -} - -void MIDIDriverALSAMidi::lock() const { - - if (mutex) - mutex->lock(); -} - -void MIDIDriverALSAMidi::unlock() const { - - if (mutex) - mutex->unlock(); -} - -PoolStringArray MIDIDriverALSAMidi::get_connected_inputs() { - - PoolStringArray list; - - lock(); - for (int i = 0; i < connected_inputs.size(); i++) { - snd_rawmidi_t *midi_in = connected_inputs[i]; - snd_rawmidi_info_t *info; - - snd_rawmidi_info_malloc(&info); - snd_rawmidi_info(midi_in, info); - list.push_back(snd_rawmidi_info_get_name(info)); - snd_rawmidi_info_free(info); - } - unlock(); - - return list; -} - -MIDIDriverALSAMidi::MIDIDriverALSAMidi() { - - mutex = NULL; - thread = NULL; - - exit_thread = false; -} - -MIDIDriverALSAMidi::~MIDIDriverALSAMidi() { - - close(); -} - -#endif diff --git a/drivers/alsamidi/alsa_midi.h b/drivers/alsamidi/alsa_midi.h deleted file mode 100644 index 054a7b474e..0000000000 --- a/drivers/alsamidi/alsa_midi.h +++ /dev/null @@ -1,69 +0,0 @@ -/*************************************************************************/ -/* alsa_midi.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#ifdef ALSAMIDI_ENABLED - -#ifndef ALSA_MIDI_H -#define ALSA_MIDI_H - -#include "core/os/midi_driver.h" -#include "core/os/mutex.h" -#include "core/os/thread.h" -#include "core/vector.h" - -#include -#include - -class MIDIDriverALSAMidi : public MIDIDriver { - - Thread *thread; - Mutex *mutex; - - Vector connected_inputs; - - bool exit_thread; - - static void thread_func(void *p_udata); - - void lock() const; - void unlock() const; - -public: - virtual Error open(); - virtual void close(); - - virtual PoolStringArray get_connected_inputs(); - - MIDIDriverALSAMidi(); - virtual ~MIDIDriverALSAMidi(); -}; - -#endif -#endif diff --git a/drivers/alsamidi/midi_driver_alsamidi.cpp b/drivers/alsamidi/midi_driver_alsamidi.cpp new file mode 100644 index 0000000000..aae0ae0216 --- /dev/null +++ b/drivers/alsamidi/midi_driver_alsamidi.cpp @@ -0,0 +1,202 @@ +/*************************************************************************/ +/* midi_driver_alsamidi.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifdef ALSAMIDI_ENABLED + +#include "midi_driver_alsamidi.h" + +#include "core/os/os.h" +#include "core/print_string.h" + +#include + +static int get_message_size(uint8_t message) { + switch (message & 0xF0) { + case 0x80: // note off + case 0x90: // note on + case 0xA0: // aftertouch + case 0xB0: // continuous controller + return 3; + + case 0xC0: // patch change + case 0xD0: // channel pressure + case 0xE0: // pitch bend + return 2; + } + + return 256; +} + +void MIDIDriverALSAMidi::thread_func(void *p_udata) { + MIDIDriverALSAMidi *md = (MIDIDriverALSAMidi *)p_udata; + uint64_t timestamp = 0; + uint8_t buffer[256]; + int expected_size = 255; + int bytes = 0; + + while (!md->exit_thread) { + int ret; + + md->lock(); + + for (int i = 0; i < md->connected_inputs.size(); i++) { + snd_rawmidi_t *midi_in = md->connected_inputs[i]; + do { + uint8_t byte = 0; + ret = snd_rawmidi_read(midi_in, &byte, 1); + if (ret < 0) { + if (ret != -EAGAIN) { + ERR_PRINTS("snd_rawmidi_read error: " + String(snd_strerror(ret))); + } + } else { + if (byte & 0x80) { + // Flush previous packet if there is any + if (bytes) { + md->receive_input_packet(timestamp, buffer, bytes); + bytes = 0; + } + expected_size = get_message_size(byte); + } + + if (bytes < 256) { + buffer[bytes++] = byte; + // If we know the size of the current packet receive it if it reached the expected size + if (bytes >= expected_size) { + md->receive_input_packet(timestamp, buffer, bytes); + bytes = 0; + } + } + } + } while (ret > 0); + } + + md->unlock(); + + OS::get_singleton()->delay_usec(1000); + } +} + +Error MIDIDriverALSAMidi::open() { + + void **hints; + + if (snd_device_name_hint(-1, "rawmidi", &hints) < 0) + return ERR_CANT_OPEN; + + int i = 0; + for (void **n = hints; *n != NULL; n++) { + char *name = snd_device_name_get_hint(*n, "NAME"); + + if (name != NULL) { + snd_rawmidi_t *midi_in; + int ret = snd_rawmidi_open(&midi_in, NULL, name, SND_RAWMIDI_NONBLOCK); + if (ret >= 0) { + connected_inputs.insert(i++, midi_in); + } + } + + if (name != NULL) + free(name); + } + snd_device_name_free_hint(hints); + + mutex = Mutex::create(); + thread = Thread::create(MIDIDriverALSAMidi::thread_func, this); + + return OK; +} + +void MIDIDriverALSAMidi::close() { + + if (thread) { + exit_thread = true; + Thread::wait_to_finish(thread); + + memdelete(thread); + thread = NULL; + } + + if (mutex) { + memdelete(mutex); + mutex = NULL; + } + + for (int i = 0; i < connected_inputs.size(); i++) { + snd_rawmidi_t *midi_in = connected_inputs[i]; + snd_rawmidi_close(midi_in); + } + connected_inputs.clear(); +} + +void MIDIDriverALSAMidi::lock() const { + + if (mutex) + mutex->lock(); +} + +void MIDIDriverALSAMidi::unlock() const { + + if (mutex) + mutex->unlock(); +} + +PoolStringArray MIDIDriverALSAMidi::get_connected_inputs() { + + PoolStringArray list; + + lock(); + for (int i = 0; i < connected_inputs.size(); i++) { + snd_rawmidi_t *midi_in = connected_inputs[i]; + snd_rawmidi_info_t *info; + + snd_rawmidi_info_malloc(&info); + snd_rawmidi_info(midi_in, info); + list.push_back(snd_rawmidi_info_get_name(info)); + snd_rawmidi_info_free(info); + } + unlock(); + + return list; +} + +MIDIDriverALSAMidi::MIDIDriverALSAMidi() { + + mutex = NULL; + thread = NULL; + + exit_thread = false; +} + +MIDIDriverALSAMidi::~MIDIDriverALSAMidi() { + + close(); +} + +#endif // ALSAMIDI_ENABLED diff --git a/drivers/alsamidi/midi_driver_alsamidi.h b/drivers/alsamidi/midi_driver_alsamidi.h new file mode 100644 index 0000000000..b6956cc32f --- /dev/null +++ b/drivers/alsamidi/midi_driver_alsamidi.h @@ -0,0 +1,69 @@ +/*************************************************************************/ +/* midi_driver_alsamidi.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifdef ALSAMIDI_ENABLED + +#ifndef MIDI_DRIVER_ALSAMIDI_H +#define MIDI_DRIVER_ALSAMIDI_H + +#include "core/os/midi_driver.h" +#include "core/os/mutex.h" +#include "core/os/thread.h" +#include "core/vector.h" + +#include +#include + +class MIDIDriverALSAMidi : public MIDIDriver { + + Thread *thread; + Mutex *mutex; + + Vector connected_inputs; + + bool exit_thread; + + static void thread_func(void *p_udata); + + void lock() const; + void unlock() const; + +public: + virtual Error open(); + virtual void close(); + + virtual PoolStringArray get_connected_inputs(); + + MIDIDriverALSAMidi(); + virtual ~MIDIDriverALSAMidi(); +}; + +#endif // MIDI_DRIVER_ALSAMIDI_H +#endif // ALSAMIDI_ENABLED diff --git a/drivers/coremidi/core_midi.cpp b/drivers/coremidi/core_midi.cpp deleted file mode 100644 index 7d3477213f..0000000000 --- a/drivers/coremidi/core_midi.cpp +++ /dev/null @@ -1,123 +0,0 @@ -/*************************************************************************/ -/* core_midi.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#ifdef COREMIDI_ENABLED - -#include "core_midi.h" - -#include "core/print_string.h" - -#include -#include - -void MIDIDriverCoreMidi::read(const MIDIPacketList *packet_list, void *read_proc_ref_con, void *src_conn_ref_con) { - MIDIPacket *packet = const_cast(packet_list->packet); - for (int i = 0; i < packet_list->numPackets; i++) { - receive_input_packet(packet->timeStamp, packet->data, packet->length); - packet = MIDIPacketNext(packet); - } -} - -Error MIDIDriverCoreMidi::open() { - - CFStringRef name = CFStringCreateWithCString(NULL, "Godot", kCFStringEncodingASCII); - OSStatus result = MIDIClientCreate(name, NULL, NULL, &client); - CFRelease(name); - if (result != noErr) { - ERR_PRINTS("MIDIClientCreate failed, code: " + itos(result)); - return ERR_CANT_OPEN; - } - - result = MIDIInputPortCreate(client, CFSTR("Godot Input"), MIDIDriverCoreMidi::read, (void *)this, &port_in); - if (result != noErr) { - ERR_PRINTS("MIDIInputPortCreate failed, code: " + itos(result)); - return ERR_CANT_OPEN; - } - - int sources = MIDIGetNumberOfSources(); - for (int i = 0; i < sources; i++) { - - MIDIEndpointRef source = MIDIGetSource(i); - if (source) { - MIDIPortConnectSource(port_in, source, (void *)this); - connected_sources.insert(i, source); - } - } - - return OK; -} - -void MIDIDriverCoreMidi::close() { - - for (int i = 0; i < connected_sources.size(); i++) { - MIDIEndpointRef source = connected_sources[i]; - MIDIPortDisconnectSource(port_in, source); - } - connected_sources.clear(); - - if (port_in != 0) { - MIDIPortDispose(port_in); - port_in = 0; - } - - if (client != 0) { - MIDIClientDispose(client); - client = 0; - } -} - -PoolStringArray MIDIDriverCoreMidi::get_connected_inputs() { - - PoolStringArray list; - - for (int i = 0; i < connected_sources.size(); i++) { - MIDIEndpointRef source = connected_sources[i]; - CFStringRef ref = NULL; - char name[256]; - - MIDIObjectGetStringProperty(source, kMIDIPropertyDisplayName, &ref); - CFStringGetCString(ref, name, sizeof(name), kCFStringEncodingUTF8); - CFRelease(ref); - - list.push_back(name); - } - - return list; -} - -MIDIDriverCoreMidi::MIDIDriverCoreMidi() : - client(0) { -} - -MIDIDriverCoreMidi::~MIDIDriverCoreMidi() { - close(); -} - -#endif diff --git a/drivers/coremidi/core_midi.h b/drivers/coremidi/core_midi.h deleted file mode 100644 index 7a10b5548e..0000000000 --- a/drivers/coremidi/core_midi.h +++ /dev/null @@ -1,62 +0,0 @@ -/*************************************************************************/ -/* core_midi.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#ifdef COREMIDI_ENABLED - -#ifndef CORE_MIDI_H -#define CORE_MIDI_H - -#include "core/os/midi_driver.h" -#include "core/vector.h" - -#include -#include - -class MIDIDriverCoreMidi : public MIDIDriver { - - MIDIClientRef client; - MIDIPortRef port_in; - - Vector connected_sources; - - static void read(const MIDIPacketList *packet_list, void *read_proc_ref_con, void *src_conn_ref_con); - -public: - virtual Error open(); - virtual void close(); - - PoolStringArray get_connected_inputs(); - - MIDIDriverCoreMidi(); - virtual ~MIDIDriverCoreMidi(); -}; - -#endif -#endif diff --git a/drivers/coremidi/midi_driver_coremidi.cpp b/drivers/coremidi/midi_driver_coremidi.cpp new file mode 100644 index 0000000000..7a92ac0702 --- /dev/null +++ b/drivers/coremidi/midi_driver_coremidi.cpp @@ -0,0 +1,123 @@ +/*************************************************************************/ +/* midi_driver_coremidi.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifdef COREMIDI_ENABLED + +#include "midi_driver_coremidi.h" + +#include "core/print_string.h" + +#include +#include + +void MIDIDriverCoreMidi::read(const MIDIPacketList *packet_list, void *read_proc_ref_con, void *src_conn_ref_con) { + MIDIPacket *packet = const_cast(packet_list->packet); + for (int i = 0; i < packet_list->numPackets; i++) { + receive_input_packet(packet->timeStamp, packet->data, packet->length); + packet = MIDIPacketNext(packet); + } +} + +Error MIDIDriverCoreMidi::open() { + + CFStringRef name = CFStringCreateWithCString(NULL, "Godot", kCFStringEncodingASCII); + OSStatus result = MIDIClientCreate(name, NULL, NULL, &client); + CFRelease(name); + if (result != noErr) { + ERR_PRINTS("MIDIClientCreate failed, code: " + itos(result)); + return ERR_CANT_OPEN; + } + + result = MIDIInputPortCreate(client, CFSTR("Godot Input"), MIDIDriverCoreMidi::read, (void *)this, &port_in); + if (result != noErr) { + ERR_PRINTS("MIDIInputPortCreate failed, code: " + itos(result)); + return ERR_CANT_OPEN; + } + + int sources = MIDIGetNumberOfSources(); + for (int i = 0; i < sources; i++) { + + MIDIEndpointRef source = MIDIGetSource(i); + if (source) { + MIDIPortConnectSource(port_in, source, (void *)this); + connected_sources.insert(i, source); + } + } + + return OK; +} + +void MIDIDriverCoreMidi::close() { + + for (int i = 0; i < connected_sources.size(); i++) { + MIDIEndpointRef source = connected_sources[i]; + MIDIPortDisconnectSource(port_in, source); + } + connected_sources.clear(); + + if (port_in != 0) { + MIDIPortDispose(port_in); + port_in = 0; + } + + if (client != 0) { + MIDIClientDispose(client); + client = 0; + } +} + +PoolStringArray MIDIDriverCoreMidi::get_connected_inputs() { + + PoolStringArray list; + + for (int i = 0; i < connected_sources.size(); i++) { + MIDIEndpointRef source = connected_sources[i]; + CFStringRef ref = NULL; + char name[256]; + + MIDIObjectGetStringProperty(source, kMIDIPropertyDisplayName, &ref); + CFStringGetCString(ref, name, sizeof(name), kCFStringEncodingUTF8); + CFRelease(ref); + + list.push_back(name); + } + + return list; +} + +MIDIDriverCoreMidi::MIDIDriverCoreMidi() : + client(0) { +} + +MIDIDriverCoreMidi::~MIDIDriverCoreMidi() { + close(); +} + +#endif // COREMIDI_ENABLED diff --git a/drivers/coremidi/midi_driver_coremidi.h b/drivers/coremidi/midi_driver_coremidi.h new file mode 100644 index 0000000000..23c2a19812 --- /dev/null +++ b/drivers/coremidi/midi_driver_coremidi.h @@ -0,0 +1,62 @@ +/*************************************************************************/ +/* midi_driver_coremidi.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifdef COREMIDI_ENABLED + +#ifndef MIDI_DRIVER_COREMIDI_H +#define MIDI_DRIVER_COREMIDI_H + +#include "core/os/midi_driver.h" +#include "core/vector.h" + +#include +#include + +class MIDIDriverCoreMidi : public MIDIDriver { + + MIDIClientRef client; + MIDIPortRef port_in; + + Vector connected_sources; + + static void read(const MIDIPacketList *packet_list, void *read_proc_ref_con, void *src_conn_ref_con); + +public: + virtual Error open(); + virtual void close(); + + PoolStringArray get_connected_inputs(); + + MIDIDriverCoreMidi(); + virtual ~MIDIDriverCoreMidi(); +}; + +#endif // MIDI_DRIVER_COREMIDI_H +#endif // COREMIDI_ENABLED diff --git a/drivers/winmidi/midi_driver_winmidi.cpp b/drivers/winmidi/midi_driver_winmidi.cpp new file mode 100644 index 0000000000..65676b629a --- /dev/null +++ b/drivers/winmidi/midi_driver_winmidi.cpp @@ -0,0 +1,107 @@ +/*************************************************************************/ +/* midi_driver_winmidi.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifdef WINMIDI_ENABLED + +#include "midi_driver_winmidi.h" + +#include "core/print_string.h" + +void MIDIDriverWinMidi::read(HMIDIIN hMidiIn, UINT wMsg, DWORD_PTR dwInstance, DWORD_PTR dwParam1, DWORD_PTR dwParam2) { + + if (wMsg == MIM_DATA) { + receive_input_packet((uint64_t)dwParam2, (uint8_t *)&dwParam1, 3); + } +} + +Error MIDIDriverWinMidi::open() { + + for (UINT i = 0; i < midiInGetNumDevs(); i++) { + HMIDIIN midi_in; + + MMRESULT res = midiInOpen(&midi_in, i, (DWORD_PTR)read, (DWORD_PTR)this, CALLBACK_FUNCTION); + if (res == MMSYSERR_NOERROR) { + midiInStart(midi_in); + connected_sources.insert(i, midi_in); + } else { + char err[256]; + midiInGetErrorText(res, err, 256); + ERR_PRINTS("midiInOpen error: " + String(err)); + + MIDIINCAPS caps; + res = midiInGetDevCaps(i, &caps, sizeof(MIDIINCAPS)); + if (res == MMSYSERR_NOERROR) { + ERR_PRINTS("Can't open MIDI device \"" + String(caps.szPname) + "\", is it being used by another application?"); + } + } + } + + return OK; +} + +PoolStringArray MIDIDriverWinMidi::get_connected_inputs() { + + PoolStringArray list; + + for (int i = 0; i < connected_sources.size(); i++) { + HMIDIIN midi_in = connected_sources[i]; + UINT id = 0; + MMRESULT res = midiInGetID(midi_in, &id); + if (res == MMSYSERR_NOERROR) { + MIDIINCAPS caps; + res = midiInGetDevCaps(i, &caps, sizeof(MIDIINCAPS)); + if (res == MMSYSERR_NOERROR) { + list.push_back(caps.szPname); + } + } + } + + return list; +} + +void MIDIDriverWinMidi::close() { + + for (int i = 0; i < connected_sources.size(); i++) { + HMIDIIN midi_in = connected_sources[i]; + midiInStop(midi_in); + midiInClose(midi_in); + } + connected_sources.clear(); +} + +MIDIDriverWinMidi::MIDIDriverWinMidi() { +} + +MIDIDriverWinMidi::~MIDIDriverWinMidi() { + + close(); +} + +#endif // WINMIDI_ENABLED diff --git a/drivers/winmidi/midi_driver_winmidi.h b/drivers/winmidi/midi_driver_winmidi.h new file mode 100644 index 0000000000..2eaa70ef8d --- /dev/null +++ b/drivers/winmidi/midi_driver_winmidi.h @@ -0,0 +1,61 @@ +/*************************************************************************/ +/* midi_driver_winmidi.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifdef WINMIDI_ENABLED + +#ifndef MIDI_DRIVER_WINMIDI_H +#define MIDI_DRIVER_WINMIDI_H + +#include "core/os/midi_driver.h" +#include "core/vector.h" + +#include +#include + +#include + +class MIDIDriverWinMidi : public MIDIDriver { + + Vector connected_sources; + + static void CALLBACK read(HMIDIIN hMidiIn, UINT wMsg, DWORD_PTR dwInstance, DWORD_PTR dwParam1, DWORD_PTR dwParam2); + +public: + virtual Error open(); + virtual void close(); + + virtual PoolStringArray get_connected_inputs(); + + MIDIDriverWinMidi(); + virtual ~MIDIDriverWinMidi(); +}; + +#endif // MIDI_DRIVER_WINMIDI_H +#endif // WINMIDI_ENABLED diff --git a/drivers/winmidi/win_midi.cpp b/drivers/winmidi/win_midi.cpp deleted file mode 100644 index 26bba34661..0000000000 --- a/drivers/winmidi/win_midi.cpp +++ /dev/null @@ -1,107 +0,0 @@ -/*************************************************************************/ -/* win_midi.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#ifdef WINMIDI_ENABLED - -#include "win_midi.h" - -#include "core/print_string.h" - -void MIDIDriverWinMidi::read(HMIDIIN hMidiIn, UINT wMsg, DWORD_PTR dwInstance, DWORD_PTR dwParam1, DWORD_PTR dwParam2) { - - if (wMsg == MIM_DATA) { - receive_input_packet((uint64_t)dwParam2, (uint8_t *)&dwParam1, 3); - } -} - -Error MIDIDriverWinMidi::open() { - - for (UINT i = 0; i < midiInGetNumDevs(); i++) { - HMIDIIN midi_in; - - MMRESULT res = midiInOpen(&midi_in, i, (DWORD_PTR)read, (DWORD_PTR)this, CALLBACK_FUNCTION); - if (res == MMSYSERR_NOERROR) { - midiInStart(midi_in); - connected_sources.insert(i, midi_in); - } else { - char err[256]; - midiInGetErrorText(res, err, 256); - ERR_PRINTS("midiInOpen error: " + String(err)); - - MIDIINCAPS caps; - res = midiInGetDevCaps(i, &caps, sizeof(MIDIINCAPS)); - if (res == MMSYSERR_NOERROR) { - ERR_PRINTS("Can't open MIDI device \"" + String(caps.szPname) + "\", is it being used by another application?"); - } - } - } - - return OK; -} - -PoolStringArray MIDIDriverWinMidi::get_connected_inputs() { - - PoolStringArray list; - - for (int i = 0; i < connected_sources.size(); i++) { - HMIDIIN midi_in = connected_sources[i]; - UINT id = 0; - MMRESULT res = midiInGetID(midi_in, &id); - if (res == MMSYSERR_NOERROR) { - MIDIINCAPS caps; - res = midiInGetDevCaps(i, &caps, sizeof(MIDIINCAPS)); - if (res == MMSYSERR_NOERROR) { - list.push_back(caps.szPname); - } - } - } - - return list; -} - -void MIDIDriverWinMidi::close() { - - for (int i = 0; i < connected_sources.size(); i++) { - HMIDIIN midi_in = connected_sources[i]; - midiInStop(midi_in); - midiInClose(midi_in); - } - connected_sources.clear(); -} - -MIDIDriverWinMidi::MIDIDriverWinMidi() { -} - -MIDIDriverWinMidi::~MIDIDriverWinMidi() { - - close(); -} - -#endif diff --git a/drivers/winmidi/win_midi.h b/drivers/winmidi/win_midi.h deleted file mode 100644 index 4341f7ca7e..0000000000 --- a/drivers/winmidi/win_midi.h +++ /dev/null @@ -1,61 +0,0 @@ -/*************************************************************************/ -/* win_midi.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#ifdef WINMIDI_ENABLED - -#ifndef WIN_MIDI_H -#define WIN_MIDI_H - -#include "core/os/midi_driver.h" -#include "core/vector.h" - -#include -#include - -#include - -class MIDIDriverWinMidi : public MIDIDriver { - - Vector connected_sources; - - static void CALLBACK read(HMIDIIN hMidiIn, UINT wMsg, DWORD_PTR dwInstance, DWORD_PTR dwParam1, DWORD_PTR dwParam2); - -public: - virtual Error open(); - virtual void close(); - - virtual PoolStringArray get_connected_inputs(); - - MIDIDriverWinMidi(); - virtual ~MIDIDriverWinMidi(); -}; - -#endif -#endif diff --git a/main/main.cpp b/main/main.cpp index f9044b61cd..5ccc6662e8 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -53,11 +53,11 @@ #include "drivers/register_driver_types.h" #include "main/app_icon.gen.h" #include "main/input_default.h" +#include "main/main_timer_sync.h" #include "main/performance.h" #include "main/splash.gen.h" #include "main/splash_editor.gen.h" #include "main/tests/test_main.h" -#include "main/timer_sync.h" #include "modules/register_module_types.h" #include "platform/register_platform_apis.h" #include "scene/main/scene_tree.h" diff --git a/main/main_timer_sync.cpp b/main/main_timer_sync.cpp new file mode 100644 index 0000000000..f7388c8517 --- /dev/null +++ b/main/main_timer_sync.cpp @@ -0,0 +1,223 @@ +/*************************************************************************/ +/* main_timer_sync.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "main_timer_sync.h" + +void MainFrameTime::clamp_idle(float min_idle_step, float max_idle_step) { + if (idle_step < min_idle_step) { + idle_step = min_idle_step; + } else if (idle_step > max_idle_step) { + idle_step = max_idle_step; + } +} + +///////////////////////////////// + +// returns the fraction of p_frame_slice required for the timer to overshoot +// before advance_core considers changing the physics_steps return from +// the typical values as defined by typical_physics_steps +float MainTimerSync::get_physics_jitter_fix() { + return Engine::get_singleton()->get_physics_jitter_fix(); +} + +// gets our best bet for the average number of physics steps per render frame +// return value: number of frames back this data is consistent +int MainTimerSync::get_average_physics_steps(float &p_min, float &p_max) { + p_min = typical_physics_steps[0]; + p_max = p_min + 1; + + for (int i = 1; i < CONTROL_STEPS; ++i) { + const float typical_lower = typical_physics_steps[i]; + const float current_min = typical_lower / (i + 1); + if (current_min > p_max) + return i; // bail out of further restrictions would void the interval + else if (current_min > p_min) + p_min = current_min; + const float current_max = (typical_lower + 1) / (i + 1); + if (current_max < p_min) + return i; + else if (current_max < p_max) + p_max = current_max; + } + + return CONTROL_STEPS; +} + +// advance physics clock by p_idle_step, return appropriate number of steps to simulate +MainFrameTime MainTimerSync::advance_core(float p_frame_slice, int p_iterations_per_second, float p_idle_step) { + MainFrameTime ret; + + ret.idle_step = p_idle_step; + + // simple determination of number of physics iteration + time_accum += ret.idle_step; + ret.physics_steps = floor(time_accum * p_iterations_per_second); + + int min_typical_steps = typical_physics_steps[0]; + int max_typical_steps = min_typical_steps + 1; + + // given the past recorded steps and typical steps to match, calculate bounds for this + // step to be typical + bool update_typical = false; + + for (int i = 0; i < CONTROL_STEPS - 1; ++i) { + int steps_left_to_match_typical = typical_physics_steps[i + 1] - accumulated_physics_steps[i]; + if (steps_left_to_match_typical > max_typical_steps || + steps_left_to_match_typical + 1 < min_typical_steps) { + update_typical = true; + break; + } + + if (steps_left_to_match_typical > min_typical_steps) + min_typical_steps = steps_left_to_match_typical; + if (steps_left_to_match_typical + 1 < max_typical_steps) + max_typical_steps = steps_left_to_match_typical + 1; + } + + // try to keep it consistent with previous iterations + if (ret.physics_steps < min_typical_steps) { + const int max_possible_steps = floor((time_accum)*p_iterations_per_second + get_physics_jitter_fix()); + if (max_possible_steps < min_typical_steps) { + ret.physics_steps = max_possible_steps; + update_typical = true; + } else { + ret.physics_steps = min_typical_steps; + } + } else if (ret.physics_steps > max_typical_steps) { + const int min_possible_steps = floor((time_accum)*p_iterations_per_second - get_physics_jitter_fix()); + if (min_possible_steps > max_typical_steps) { + ret.physics_steps = min_possible_steps; + update_typical = true; + } else { + ret.physics_steps = max_typical_steps; + } + } + + time_accum -= ret.physics_steps * p_frame_slice; + + // keep track of accumulated step counts + for (int i = CONTROL_STEPS - 2; i >= 0; --i) { + accumulated_physics_steps[i + 1] = accumulated_physics_steps[i] + ret.physics_steps; + } + accumulated_physics_steps[0] = ret.physics_steps; + + if (update_typical) { + for (int i = CONTROL_STEPS - 1; i >= 0; --i) { + if (typical_physics_steps[i] > accumulated_physics_steps[i]) { + typical_physics_steps[i] = accumulated_physics_steps[i]; + } else if (typical_physics_steps[i] < accumulated_physics_steps[i] - 1) { + typical_physics_steps[i] = accumulated_physics_steps[i] - 1; + } + } + } + + return ret; +} + +// calls advance_core, keeps track of deficit it adds to animaption_step, make sure the deficit sum stays close to zero +MainFrameTime MainTimerSync::advance_checked(float p_frame_slice, int p_iterations_per_second, float p_idle_step) { + if (fixed_fps != -1) + p_idle_step = 1.0 / fixed_fps; + + // compensate for last deficit + p_idle_step += time_deficit; + + MainFrameTime ret = advance_core(p_frame_slice, p_iterations_per_second, p_idle_step); + + // we will do some clamping on ret.idle_step and need to sync those changes to time_accum, + // that's easiest if we just remember their fixed difference now + const double idle_minus_accum = ret.idle_step - time_accum; + + // first, least important clamping: keep ret.idle_step consistent with typical_physics_steps. + // this smoothes out the idle steps and culls small but quick variations. + { + float min_average_physics_steps, max_average_physics_steps; + int consistent_steps = get_average_physics_steps(min_average_physics_steps, max_average_physics_steps); + if (consistent_steps > 3) { + ret.clamp_idle(min_average_physics_steps * p_frame_slice, max_average_physics_steps * p_frame_slice); + } + } + + // second clamping: keep abs(time_deficit) < jitter_fix * frame_slise + float max_clock_deviation = get_physics_jitter_fix() * p_frame_slice; + ret.clamp_idle(p_idle_step - max_clock_deviation, p_idle_step + max_clock_deviation); + + // last clamping: make sure time_accum is between 0 and p_frame_slice for consistency between physics and idle + ret.clamp_idle(idle_minus_accum, idle_minus_accum + p_frame_slice); + + // restore time_accum + time_accum = ret.idle_step - idle_minus_accum; + + // track deficit + time_deficit = p_idle_step - ret.idle_step; + + return ret; +} + +// determine wall clock step since last iteration +float MainTimerSync::get_cpu_idle_step() { + uint64_t cpu_ticks_elapsed = current_cpu_ticks_usec - last_cpu_ticks_usec; + last_cpu_ticks_usec = current_cpu_ticks_usec; + + return cpu_ticks_elapsed / 1000000.0; +} + +MainTimerSync::MainTimerSync() : + last_cpu_ticks_usec(0), + current_cpu_ticks_usec(0), + time_accum(0), + time_deficit(0), + fixed_fps(0) { + for (int i = CONTROL_STEPS - 1; i >= 0; --i) { + typical_physics_steps[i] = i; + accumulated_physics_steps[i] = i; + } +} + +// start the clock +void MainTimerSync::init(uint64_t p_cpu_ticks_usec) { + current_cpu_ticks_usec = last_cpu_ticks_usec = p_cpu_ticks_usec; +} + +// set measured wall clock time +void MainTimerSync::set_cpu_ticks_usec(uint64_t p_cpu_ticks_usec) { + current_cpu_ticks_usec = p_cpu_ticks_usec; +} + +void MainTimerSync::set_fixed_fps(int p_fixed_fps) { + fixed_fps = p_fixed_fps; +} + +// advance one frame, return timesteps to take +MainFrameTime MainTimerSync::advance(float p_frame_slice, int p_iterations_per_second) { + float cpu_idle_step = get_cpu_idle_step(); + + return advance_checked(p_frame_slice, p_iterations_per_second, cpu_idle_step); +} diff --git a/main/main_timer_sync.h b/main/main_timer_sync.h new file mode 100644 index 0000000000..179119edce --- /dev/null +++ b/main/main_timer_sync.h @@ -0,0 +1,101 @@ +/*************************************************************************/ +/* main_timer_sync.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef MAIN_TIMER_SYNC_H +#define MAIN_TIMER_SYNC_H + +#include "core/engine.h" + +struct MainFrameTime { + float idle_step; // time to advance idles for (argument to process()) + int physics_steps; // number of times to iterate the physics engine + + void clamp_idle(float min_idle_step, float max_idle_step); +}; + +class MainTimerSync { + // wall clock time measured on the main thread + uint64_t last_cpu_ticks_usec; + uint64_t current_cpu_ticks_usec; + + // logical game time since last physics timestep + float time_accum; + + // current difference between wall clock time and reported sum of idle_steps + float time_deficit; + + // number of frames back for keeping accumulated physics steps roughly constant. + // value of 12 chosen because that is what is required to make 144 Hz monitors + // behave well with 60 Hz physics updates. The only worse commonly available refresh + // would be 85, requiring CONTROL_STEPS = 17. + static const int CONTROL_STEPS = 12; + + // sum of physics steps done over the last (i+1) frames + int accumulated_physics_steps[CONTROL_STEPS]; + + // typical value for accumulated_physics_steps[i] is either this or this plus one + int typical_physics_steps[CONTROL_STEPS]; + + int fixed_fps; + +protected: + // returns the fraction of p_frame_slice required for the timer to overshoot + // before advance_core considers changing the physics_steps return from + // the typical values as defined by typical_physics_steps + float get_physics_jitter_fix(); + + // gets our best bet for the average number of physics steps per render frame + // return value: number of frames back this data is consistent + int get_average_physics_steps(float &p_min, float &p_max); + + // advance physics clock by p_idle_step, return appropriate number of steps to simulate + MainFrameTime advance_core(float p_frame_slice, int p_iterations_per_second, float p_idle_step); + + // calls advance_core, keeps track of deficit it adds to animaption_step, make sure the deficit sum stays close to zero + MainFrameTime advance_checked(float p_frame_slice, int p_iterations_per_second, float p_idle_step); + + // determine wall clock step since last iteration + float get_cpu_idle_step(); + +public: + MainTimerSync(); + + // start the clock + void init(uint64_t p_cpu_ticks_usec); + // set measured wall clock time + void set_cpu_ticks_usec(uint64_t p_cpu_ticks_usec); + //set fixed fps + void set_fixed_fps(int p_fixed_fps); + + // advance one frame, return timesteps to take + MainFrameTime advance(float p_frame_slice, int p_iterations_per_second); +}; + +#endif // MAIN_TIMER_SYNC_H diff --git a/main/timer_sync.cpp b/main/timer_sync.cpp deleted file mode 100644 index 5ee834880f..0000000000 --- a/main/timer_sync.cpp +++ /dev/null @@ -1,223 +0,0 @@ -/*************************************************************************/ -/* timer_sync.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#include "timer_sync.h" - -void MainFrameTime::clamp_idle(float min_idle_step, float max_idle_step) { - if (idle_step < min_idle_step) { - idle_step = min_idle_step; - } else if (idle_step > max_idle_step) { - idle_step = max_idle_step; - } -} - -///////////////////////////////// - -// returns the fraction of p_frame_slice required for the timer to overshoot -// before advance_core considers changing the physics_steps return from -// the typical values as defined by typical_physics_steps -float MainTimerSync::get_physics_jitter_fix() { - return Engine::get_singleton()->get_physics_jitter_fix(); -} - -// gets our best bet for the average number of physics steps per render frame -// return value: number of frames back this data is consistent -int MainTimerSync::get_average_physics_steps(float &p_min, float &p_max) { - p_min = typical_physics_steps[0]; - p_max = p_min + 1; - - for (int i = 1; i < CONTROL_STEPS; ++i) { - const float typical_lower = typical_physics_steps[i]; - const float current_min = typical_lower / (i + 1); - if (current_min > p_max) - return i; // bail out of further restrictions would void the interval - else if (current_min > p_min) - p_min = current_min; - const float current_max = (typical_lower + 1) / (i + 1); - if (current_max < p_min) - return i; - else if (current_max < p_max) - p_max = current_max; - } - - return CONTROL_STEPS; -} - -// advance physics clock by p_idle_step, return appropriate number of steps to simulate -MainFrameTime MainTimerSync::advance_core(float p_frame_slice, int p_iterations_per_second, float p_idle_step) { - MainFrameTime ret; - - ret.idle_step = p_idle_step; - - // simple determination of number of physics iteration - time_accum += ret.idle_step; - ret.physics_steps = floor(time_accum * p_iterations_per_second); - - int min_typical_steps = typical_physics_steps[0]; - int max_typical_steps = min_typical_steps + 1; - - // given the past recorded steps and typical steps to match, calculate bounds for this - // step to be typical - bool update_typical = false; - - for (int i = 0; i < CONTROL_STEPS - 1; ++i) { - int steps_left_to_match_typical = typical_physics_steps[i + 1] - accumulated_physics_steps[i]; - if (steps_left_to_match_typical > max_typical_steps || - steps_left_to_match_typical + 1 < min_typical_steps) { - update_typical = true; - break; - } - - if (steps_left_to_match_typical > min_typical_steps) - min_typical_steps = steps_left_to_match_typical; - if (steps_left_to_match_typical + 1 < max_typical_steps) - max_typical_steps = steps_left_to_match_typical + 1; - } - - // try to keep it consistent with previous iterations - if (ret.physics_steps < min_typical_steps) { - const int max_possible_steps = floor((time_accum)*p_iterations_per_second + get_physics_jitter_fix()); - if (max_possible_steps < min_typical_steps) { - ret.physics_steps = max_possible_steps; - update_typical = true; - } else { - ret.physics_steps = min_typical_steps; - } - } else if (ret.physics_steps > max_typical_steps) { - const int min_possible_steps = floor((time_accum)*p_iterations_per_second - get_physics_jitter_fix()); - if (min_possible_steps > max_typical_steps) { - ret.physics_steps = min_possible_steps; - update_typical = true; - } else { - ret.physics_steps = max_typical_steps; - } - } - - time_accum -= ret.physics_steps * p_frame_slice; - - // keep track of accumulated step counts - for (int i = CONTROL_STEPS - 2; i >= 0; --i) { - accumulated_physics_steps[i + 1] = accumulated_physics_steps[i] + ret.physics_steps; - } - accumulated_physics_steps[0] = ret.physics_steps; - - if (update_typical) { - for (int i = CONTROL_STEPS - 1; i >= 0; --i) { - if (typical_physics_steps[i] > accumulated_physics_steps[i]) { - typical_physics_steps[i] = accumulated_physics_steps[i]; - } else if (typical_physics_steps[i] < accumulated_physics_steps[i] - 1) { - typical_physics_steps[i] = accumulated_physics_steps[i] - 1; - } - } - } - - return ret; -} - -// calls advance_core, keeps track of deficit it adds to animaption_step, make sure the deficit sum stays close to zero -MainFrameTime MainTimerSync::advance_checked(float p_frame_slice, int p_iterations_per_second, float p_idle_step) { - if (fixed_fps != -1) - p_idle_step = 1.0 / fixed_fps; - - // compensate for last deficit - p_idle_step += time_deficit; - - MainFrameTime ret = advance_core(p_frame_slice, p_iterations_per_second, p_idle_step); - - // we will do some clamping on ret.idle_step and need to sync those changes to time_accum, - // that's easiest if we just remember their fixed difference now - const double idle_minus_accum = ret.idle_step - time_accum; - - // first, least important clamping: keep ret.idle_step consistent with typical_physics_steps. - // this smoothes out the idle steps and culls small but quick variations. - { - float min_average_physics_steps, max_average_physics_steps; - int consistent_steps = get_average_physics_steps(min_average_physics_steps, max_average_physics_steps); - if (consistent_steps > 3) { - ret.clamp_idle(min_average_physics_steps * p_frame_slice, max_average_physics_steps * p_frame_slice); - } - } - - // second clamping: keep abs(time_deficit) < jitter_fix * frame_slise - float max_clock_deviation = get_physics_jitter_fix() * p_frame_slice; - ret.clamp_idle(p_idle_step - max_clock_deviation, p_idle_step + max_clock_deviation); - - // last clamping: make sure time_accum is between 0 and p_frame_slice for consistency between physics and idle - ret.clamp_idle(idle_minus_accum, idle_minus_accum + p_frame_slice); - - // restore time_accum - time_accum = ret.idle_step - idle_minus_accum; - - // track deficit - time_deficit = p_idle_step - ret.idle_step; - - return ret; -} - -// determine wall clock step since last iteration -float MainTimerSync::get_cpu_idle_step() { - uint64_t cpu_ticks_elapsed = current_cpu_ticks_usec - last_cpu_ticks_usec; - last_cpu_ticks_usec = current_cpu_ticks_usec; - - return cpu_ticks_elapsed / 1000000.0; -} - -MainTimerSync::MainTimerSync() : - last_cpu_ticks_usec(0), - current_cpu_ticks_usec(0), - time_accum(0), - time_deficit(0), - fixed_fps(0) { - for (int i = CONTROL_STEPS - 1; i >= 0; --i) { - typical_physics_steps[i] = i; - accumulated_physics_steps[i] = i; - } -} - -// start the clock -void MainTimerSync::init(uint64_t p_cpu_ticks_usec) { - current_cpu_ticks_usec = last_cpu_ticks_usec = p_cpu_ticks_usec; -} - -// set measured wall clock time -void MainTimerSync::set_cpu_ticks_usec(uint64_t p_cpu_ticks_usec) { - current_cpu_ticks_usec = p_cpu_ticks_usec; -} - -void MainTimerSync::set_fixed_fps(int p_fixed_fps) { - fixed_fps = p_fixed_fps; -} - -// advance one frame, return timesteps to take -MainFrameTime MainTimerSync::advance(float p_frame_slice, int p_iterations_per_second) { - float cpu_idle_step = get_cpu_idle_step(); - - return advance_checked(p_frame_slice, p_iterations_per_second, cpu_idle_step); -} diff --git a/main/timer_sync.h b/main/timer_sync.h deleted file mode 100644 index fcce6d7a9a..0000000000 --- a/main/timer_sync.h +++ /dev/null @@ -1,101 +0,0 @@ -/*************************************************************************/ -/* timer_sync.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#ifndef TIMER_SYNC_H -#define TIMER_SYNC_H - -#include "core/engine.h" - -struct MainFrameTime { - float idle_step; // time to advance idles for (argument to process()) - int physics_steps; // number of times to iterate the physics engine - - void clamp_idle(float min_idle_step, float max_idle_step); -}; - -class MainTimerSync { - // wall clock time measured on the main thread - uint64_t last_cpu_ticks_usec; - uint64_t current_cpu_ticks_usec; - - // logical game time since last physics timestep - float time_accum; - - // current difference between wall clock time and reported sum of idle_steps - float time_deficit; - - // number of frames back for keeping accumulated physics steps roughly constant. - // value of 12 chosen because that is what is required to make 144 Hz monitors - // behave well with 60 Hz physics updates. The only worse commonly available refresh - // would be 85, requiring CONTROL_STEPS = 17. - static const int CONTROL_STEPS = 12; - - // sum of physics steps done over the last (i+1) frames - int accumulated_physics_steps[CONTROL_STEPS]; - - // typical value for accumulated_physics_steps[i] is either this or this plus one - int typical_physics_steps[CONTROL_STEPS]; - - int fixed_fps; - -protected: - // returns the fraction of p_frame_slice required for the timer to overshoot - // before advance_core considers changing the physics_steps return from - // the typical values as defined by typical_physics_steps - float get_physics_jitter_fix(); - - // gets our best bet for the average number of physics steps per render frame - // return value: number of frames back this data is consistent - int get_average_physics_steps(float &p_min, float &p_max); - - // advance physics clock by p_idle_step, return appropriate number of steps to simulate - MainFrameTime advance_core(float p_frame_slice, int p_iterations_per_second, float p_idle_step); - - // calls advance_core, keeps track of deficit it adds to animaption_step, make sure the deficit sum stays close to zero - MainFrameTime advance_checked(float p_frame_slice, int p_iterations_per_second, float p_idle_step); - - // determine wall clock step since last iteration - float get_cpu_idle_step(); - -public: - MainTimerSync(); - - // start the clock - void init(uint64_t p_cpu_ticks_usec); - // set measured wall clock time - void set_cpu_ticks_usec(uint64_t p_cpu_ticks_usec); - //set fixed fps - void set_fixed_fps(int p_fixed_fps); - - // advance one frame, return timesteps to take - MainFrameTime advance(float p_frame_slice, int p_iterations_per_second); -}; - -#endif // TIMER_SYNC_H diff --git a/modules/gdnative/arvr/arvr_interface_gdnative.cpp b/modules/gdnative/arvr/arvr_interface_gdnative.cpp index 01fbc316cf..11509fc20a 100644 --- a/modules/gdnative/arvr/arvr_interface_gdnative.cpp +++ b/modules/gdnative/arvr/arvr_interface_gdnative.cpp @@ -31,7 +31,7 @@ #include "arvr_interface_gdnative.h" #include "main/input_default.h" #include "servers/arvr/arvr_positional_tracker.h" -#include "servers/visual/visual_server_global.h" +#include "servers/visual/visual_server_globals.h" ARVRInterfaceGDNative::ARVRInterfaceGDNative() { // testing diff --git a/modules/mobile_vr/mobile_vr_interface.cpp b/modules/mobile_vr/mobile_vr_interface.cpp index 78cc667718..b4fbd417d7 100644 --- a/modules/mobile_vr/mobile_vr_interface.cpp +++ b/modules/mobile_vr/mobile_vr_interface.cpp @@ -31,7 +31,7 @@ #include "mobile_vr_interface.h" #include "core/os/input.h" #include "core/os/os.h" -#include "servers/visual/visual_server_global.h" +#include "servers/visual/visual_server_globals.h" StringName MobileVRInterface::get_name() const { return "Native mobile"; diff --git a/platform/osx/os_osx.h b/platform/osx/os_osx.h index 927c8c9b00..32199e0adb 100644 --- a/platform/osx/os_osx.h +++ b/platform/osx/os_osx.h @@ -34,7 +34,7 @@ #include "core/os/input.h" #include "crash_handler_osx.h" #include "drivers/coreaudio/audio_driver_coreaudio.h" -#include "drivers/coremidi/core_midi.h" +#include "drivers/coremidi/midi_driver_coremidi.h" #include "drivers/unix/os_unix.h" #include "joypad_osx.h" #include "main/input_default.h" diff --git a/platform/windows/os_windows.h b/platform/windows/os_windows.h index 771789c86b..ba84c2098e 100644 --- a/platform/windows/os_windows.h +++ b/platform/windows/os_windows.h @@ -30,14 +30,18 @@ #ifndef OS_WINDOWS_H #define OS_WINDOWS_H + #include "context_gl_win.h" #include "core/os/input.h" #include "core/os/os.h" #include "core/project_settings.h" #include "crash_handler_win.h" #include "drivers/rtaudio/audio_driver_rtaudio.h" +#include "drivers/unix/ip_unix.h" #include "drivers/wasapi/audio_driver_wasapi.h" -#include "drivers/winmidi/win_midi.h" +#include "drivers/winmidi/midi_driver_winmidi.h" +#include "key_mapping_win.h" +#include "main/input_default.h" #include "power_windows.h" #include "servers/audio_server.h" #include "servers/visual/rasterizer.h" @@ -45,9 +49,6 @@ #ifdef XAUDIO2_ENABLED #include "drivers/xaudio2/audio_driver_xaudio2.h" #endif -#include "drivers/unix/ip_unix.h" -#include "key_mapping_win.h" -#include "main/input_default.h" #include #include diff --git a/platform/x11/os_x11.h b/platform/x11/os_x11.h index cf1619bae2..6d1a66af84 100644 --- a/platform/x11/os_x11.h +++ b/platform/x11/os_x11.h @@ -35,7 +35,7 @@ #include "core/os/input.h" #include "crash_handler_x11.h" #include "drivers/alsa/audio_driver_alsa.h" -#include "drivers/alsamidi/alsa_midi.h" +#include "drivers/alsamidi/midi_driver_alsamidi.h" #include "drivers/pulseaudio/audio_driver_pulseaudio.h" #include "drivers/unix/os_unix.h" #include "joypad_linux.h" diff --git a/servers/visual/visual_server_canvas.cpp b/servers/visual/visual_server_canvas.cpp index bb02027479..e1ecba6334 100644 --- a/servers/visual/visual_server_canvas.cpp +++ b/servers/visual/visual_server_canvas.cpp @@ -29,7 +29,7 @@ /*************************************************************************/ #include "visual_server_canvas.h" -#include "visual_server_global.h" +#include "visual_server_globals.h" #include "visual_server_raster.h" #include "visual_server_viewport.h" diff --git a/servers/visual/visual_server_global.cpp b/servers/visual/visual_server_global.cpp deleted file mode 100644 index 2d6d489759..0000000000 --- a/servers/visual/visual_server_global.cpp +++ /dev/null @@ -1,40 +0,0 @@ -/*************************************************************************/ -/* visual_server_global.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#include "visual_server_global.h" - -RasterizerStorage *VisualServerGlobals::storage = NULL; -RasterizerCanvas *VisualServerGlobals::canvas_render = NULL; -RasterizerScene *VisualServerGlobals::scene_render = NULL; -Rasterizer *VisualServerGlobals::rasterizer = NULL; - -VisualServerCanvas *VisualServerGlobals::canvas = NULL; -VisualServerViewport *VisualServerGlobals::viewport = NULL; -VisualServerScene *VisualServerGlobals::scene = NULL; diff --git a/servers/visual/visual_server_global.h b/servers/visual/visual_server_global.h deleted file mode 100644 index b510307e81..0000000000 --- a/servers/visual/visual_server_global.h +++ /dev/null @@ -1,54 +0,0 @@ -/*************************************************************************/ -/* visual_server_global.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#ifndef VISUALSERVERGLOBAL_H -#define VISUALSERVERGLOBAL_H - -#include "rasterizer.h" - -class VisualServerCanvas; -class VisualServerViewport; -class VisualServerScene; - -class VisualServerGlobals { -public: - static RasterizerStorage *storage; - static RasterizerCanvas *canvas_render; - static RasterizerScene *scene_render; - static Rasterizer *rasterizer; - - static VisualServerCanvas *canvas; - static VisualServerViewport *viewport; - static VisualServerScene *scene; -}; - -#define VSG VisualServerGlobals - -#endif // VISUALSERVERGLOBAL_H diff --git a/servers/visual/visual_server_globals.cpp b/servers/visual/visual_server_globals.cpp new file mode 100644 index 0000000000..5c247c7f0f --- /dev/null +++ b/servers/visual/visual_server_globals.cpp @@ -0,0 +1,40 @@ +/*************************************************************************/ +/* visual_server_globals.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "visual_server_globals.h" + +RasterizerStorage *VisualServerGlobals::storage = NULL; +RasterizerCanvas *VisualServerGlobals::canvas_render = NULL; +RasterizerScene *VisualServerGlobals::scene_render = NULL; +Rasterizer *VisualServerGlobals::rasterizer = NULL; + +VisualServerCanvas *VisualServerGlobals::canvas = NULL; +VisualServerViewport *VisualServerGlobals::viewport = NULL; +VisualServerScene *VisualServerGlobals::scene = NULL; diff --git a/servers/visual/visual_server_globals.h b/servers/visual/visual_server_globals.h new file mode 100644 index 0000000000..04d52aa1eb --- /dev/null +++ b/servers/visual/visual_server_globals.h @@ -0,0 +1,54 @@ +/*************************************************************************/ +/* visual_server_globals.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef VISUAL_SERVER_GLOBALS_H +#define VISUAL_SERVER_GLOBALS_H + +#include "rasterizer.h" + +class VisualServerCanvas; +class VisualServerViewport; +class VisualServerScene; + +class VisualServerGlobals { +public: + static RasterizerStorage *storage; + static RasterizerCanvas *canvas_render; + static RasterizerScene *scene_render; + static Rasterizer *rasterizer; + + static VisualServerCanvas *canvas; + static VisualServerViewport *viewport; + static VisualServerScene *scene; +}; + +#define VSG VisualServerGlobals + +#endif // VISUAL_SERVER_GLOBALS_H diff --git a/servers/visual/visual_server_raster.cpp b/servers/visual/visual_server_raster.cpp index b18fabd467..6622433b17 100644 --- a/servers/visual/visual_server_raster.cpp +++ b/servers/visual/visual_server_raster.cpp @@ -35,7 +35,7 @@ #include "core/project_settings.h" #include "core/sort_array.h" #include "visual_server_canvas.h" -#include "visual_server_global.h" +#include "visual_server_globals.h" #include "visual_server_scene.h" // careful, these may run in different threads than the visual server diff --git a/servers/visual/visual_server_raster.h b/servers/visual/visual_server_raster.h index ec6e50753e..89a759b963 100644 --- a/servers/visual/visual_server_raster.h +++ b/servers/visual/visual_server_raster.h @@ -35,7 +35,7 @@ #include "servers/visual/rasterizer.h" #include "servers/visual_server.h" #include "visual_server_canvas.h" -#include "visual_server_global.h" +#include "visual_server_globals.h" #include "visual_server_scene.h" #include "visual_server_viewport.h" /** diff --git a/servers/visual/visual_server_scene.cpp b/servers/visual/visual_server_scene.cpp index c8d64fca45..5d0456686a 100644 --- a/servers/visual/visual_server_scene.cpp +++ b/servers/visual/visual_server_scene.cpp @@ -30,7 +30,7 @@ #include "visual_server_scene.h" #include "core/os/os.h" -#include "visual_server_global.h" +#include "visual_server_globals.h" #include "visual_server_raster.h" #include /* CAMERA API */ diff --git a/servers/visual/visual_server_viewport.cpp b/servers/visual/visual_server_viewport.cpp index 7a7ae3a823..d6e43b0f00 100644 --- a/servers/visual/visual_server_viewport.cpp +++ b/servers/visual/visual_server_viewport.cpp @@ -32,7 +32,7 @@ #include "core/project_settings.h" #include "visual_server_canvas.h" -#include "visual_server_global.h" +#include "visual_server_globals.h" #include "visual_server_scene.h" void VisualServerViewport::_draw_viewport(Viewport *p_viewport, ARVRInterface::Eyes p_eye) { -- cgit v1.2.3 From bc26d0d6cdd1c28a0a243131468bf5f698dff18f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Verschelde?= Date: Tue, 12 Feb 2019 15:43:54 +0100 Subject: Platform: Ensure classes match their header filename Also drop some unused files. Renamed: - `platform/iphone/sem_iphone.h` -> `semaphore_iphone.h` (same for `osx`) - `platform/uwp/gl_context_egl.h` -> `context_egl_uwp.h` - in `platform/windows`: `context_gl_win.h`, `crash_handler_win.h`, `godot_win.cpp`, `joypad.h` and `key_mapping_win.h` all renamed to use `windows`. Some classes renamed accordingly too. - `EditorExportAndroid` and `EditorExportUWP` renamed to `EditorExportPlatformAndroid` and `EditorExportPlatformUWP` - `power_android` and `power_osx` renamed to `PowerAndroid` and `PowerOSX` - `OSUWP` renamed to `OS_UWP` Dropped: - `platform/windows/ctxgl_procaddr.h` --- platform/android/export/export.cpp | 12 +- platform/android/os_android.cpp | 2 +- platform/android/os_android.h | 2 +- platform/android/power_android.cpp | 12 +- platform/android/power_android.h | 13 +- platform/iphone/SCsub | 2 +- platform/iphone/os_iphone.cpp | 3 +- platform/iphone/power_iphone.h | 6 +- platform/iphone/sem_iphone.cpp | 111 ------ platform/iphone/sem_iphone.h | 59 --- platform/iphone/semaphore_iphone.cpp | 112 ++++++ platform/iphone/semaphore_iphone.h | 59 +++ platform/osx/SCsub | 2 +- platform/osx/crash_handler_osx.h | 2 +- platform/osx/crash_handler_osx.mm | 4 +- platform/osx/os_osx.h | 3 +- platform/osx/os_osx.mm | 4 +- platform/osx/power_osx.cpp | 16 +- platform/osx/power_osx.h | 13 +- platform/osx/sem_osx.cpp | 106 ------ platform/osx/sem_osx.h | 59 --- platform/osx/semaphore_osx.cpp | 107 ++++++ platform/osx/semaphore_osx.h | 59 +++ platform/server/SCsub | 2 +- platform/server/os_server.cpp | 2 +- platform/server/os_server.h | 4 +- platform/uwp/SCsub | 4 +- platform/uwp/app.cpp | 10 +- platform/uwp/app.h | 2 +- platform/uwp/context_egl_uwp.cpp | 221 ++++++++++++ platform/uwp/context_egl_uwp.h | 87 +++++ platform/uwp/export/export.cpp | 20 +- platform/uwp/gl_context_egl.cpp | 221 ------------ platform/uwp/gl_context_egl.h | 86 ----- platform/uwp/os_uwp.cpp | 170 ++++----- platform/uwp/os_uwp.h | 16 +- platform/uwp/power_uwp.h | 6 +- platform/windows/SCsub | 11 +- platform/windows/context_gl_win.cpp | 185 ---------- platform/windows/context_gl_win.h | 76 ---- platform/windows/context_gl_windows.cpp | 185 ++++++++++ platform/windows/context_gl_windows.h | 76 ++++ platform/windows/crash_handler_win.cpp | 216 ----------- platform/windows/crash_handler_win.h | 57 --- platform/windows/crash_handler_windows.cpp | 218 +++++++++++ platform/windows/crash_handler_windows.h | 57 +++ platform/windows/ctxgl_procaddr.cpp | 188 ---------- platform/windows/ctxgl_procaddr.h | 39 -- platform/windows/godot_win.cpp | 198 ---------- platform/windows/godot_windows.cpp | 199 ++++++++++ platform/windows/joypad.cpp | 558 ----------------------------- platform/windows/joypad.h | 148 -------- platform/windows/joypad_windows.cpp | 558 +++++++++++++++++++++++++++++ platform/windows/joypad_windows.h | 149 ++++++++ platform/windows/key_mapping_win.cpp | 253 ------------- platform/windows/key_mapping_win.h | 48 --- platform/windows/key_mapping_windows.cpp | 253 +++++++++++++ platform/windows/key_mapping_windows.h | 48 +++ platform/windows/os_windows.cpp | 6 +- platform/windows/os_windows.h | 8 +- platform/windows/power_windows.h | 6 +- platform/x11/crash_handler_x11.cpp | 9 +- platform/x11/crash_handler_x11.h | 2 +- platform/x11/power_x11.h | 6 +- 64 files changed, 2581 insertions(+), 2795 deletions(-) delete mode 100644 platform/iphone/sem_iphone.cpp delete mode 100644 platform/iphone/sem_iphone.h create mode 100644 platform/iphone/semaphore_iphone.cpp create mode 100644 platform/iphone/semaphore_iphone.h delete mode 100644 platform/osx/sem_osx.cpp delete mode 100644 platform/osx/sem_osx.h create mode 100644 platform/osx/semaphore_osx.cpp create mode 100644 platform/osx/semaphore_osx.h create mode 100644 platform/uwp/context_egl_uwp.cpp create mode 100644 platform/uwp/context_egl_uwp.h delete mode 100644 platform/uwp/gl_context_egl.cpp delete mode 100644 platform/uwp/gl_context_egl.h delete mode 100644 platform/windows/context_gl_win.cpp delete mode 100644 platform/windows/context_gl_win.h create mode 100644 platform/windows/context_gl_windows.cpp create mode 100644 platform/windows/context_gl_windows.h delete mode 100644 platform/windows/crash_handler_win.cpp delete mode 100644 platform/windows/crash_handler_win.h create mode 100644 platform/windows/crash_handler_windows.cpp create mode 100644 platform/windows/crash_handler_windows.h delete mode 100644 platform/windows/ctxgl_procaddr.cpp delete mode 100644 platform/windows/ctxgl_procaddr.h delete mode 100644 platform/windows/godot_win.cpp create mode 100644 platform/windows/godot_windows.cpp delete mode 100644 platform/windows/joypad.cpp delete mode 100644 platform/windows/joypad.h create mode 100644 platform/windows/joypad_windows.cpp create mode 100644 platform/windows/joypad_windows.h delete mode 100644 platform/windows/key_mapping_win.cpp delete mode 100644 platform/windows/key_mapping_win.h create mode 100644 platform/windows/key_mapping_windows.cpp create mode 100644 platform/windows/key_mapping_windows.h diff --git a/platform/android/export/export.cpp b/platform/android/export/export.cpp index f293eef2ba..60cc33e6bf 100644 --- a/platform/android/export/export.cpp +++ b/platform/android/export/export.cpp @@ -206,9 +206,9 @@ static const LauncherIcon launcher_icons[] = { { "launcher_icons/mdpi_48x48", "res/drawable-mdpi-v4/icon.png" } }; -class EditorExportAndroid : public EditorExportPlatform { +class EditorExportPlatformAndroid : public EditorExportPlatform { - GDCLASS(EditorExportAndroid, EditorExportPlatform) + GDCLASS(EditorExportPlatformAndroid, EditorExportPlatform) Ref logo; Ref run_icon; @@ -235,7 +235,7 @@ class EditorExportAndroid : public EditorExportPlatform { static void _device_poll_thread(void *ud) { - EditorExportAndroid *ea = (EditorExportAndroid *)ud; + EditorExportPlatformAndroid *ea = (EditorExportPlatformAndroid *)ud; while (!ea->quit_request) { @@ -1925,7 +1925,7 @@ public: virtual void resolve_platform_feature_priorities(const Ref &p_preset, Set &p_features) { } - EditorExportAndroid() { + EditorExportPlatformAndroid() { Ref img = memnew(Image(_android_logo)); logo.instance(); @@ -1941,7 +1941,7 @@ public: device_thread = Thread::create(_device_poll_thread, this); } - ~EditorExportAndroid() { + ~EditorExportPlatformAndroid() { quit_request = true; Thread::wait_to_finish(device_thread); memdelete(device_lock); @@ -1969,6 +1969,6 @@ void register_android_exporter() { EDITOR_DEF("export/android/timestamping_authority_url", ""); EDITOR_DEF("export/android/shutdown_adb_on_exit", true); - Ref exporter = Ref(memnew(EditorExportAndroid)); + Ref exporter = Ref(memnew(EditorExportPlatformAndroid)); EditorExport::get_singleton()->add_export_platform(exporter); } diff --git a/platform/android/os_android.cpp b/platform/android/os_android.cpp index 2ee0b34c48..3ba8468e0b 100644 --- a/platform/android/os_android.cpp +++ b/platform/android/os_android.cpp @@ -175,7 +175,7 @@ Error OS_Android::initialize(const VideoMode &p_desired, int p_video_driver, int input = memnew(InputDefault); input->set_fallback_mapping("Default Android Gamepad"); - //power_manager = memnew(power_android); + //power_manager = memnew(PowerAndroid); return OK; } diff --git a/platform/android/os_android.h b/platform/android/os_android.h index 3c591af4bb..1e5b89e24d 100644 --- a/platform/android/os_android.h +++ b/platform/android/os_android.h @@ -134,7 +134,7 @@ private: SetKeepScreenOnFunc set_keep_screen_on_func; AlertFunc alert_func; - //power_android *power_manager; + //PowerAndroid *power_manager; int video_driver_index; public: diff --git a/platform/android/power_android.cpp b/platform/android/power_android.cpp index 40b9d81189..4d2fbfbf1a 100644 --- a/platform/android/power_android.cpp +++ b/platform/android/power_android.cpp @@ -190,7 +190,7 @@ int Android_JNI_GetPowerInfo(int *plugged, int *charged, int *battery, int *seco return 0; } -bool power_android::GetPowerInfo_Android() { +bool PowerAndroid::GetPowerInfo_Android() { int battery; int plugged; int charged; @@ -218,7 +218,7 @@ bool power_android::GetPowerInfo_Android() { return true; } -OS::PowerState power_android::get_power_state() { +OS::PowerState PowerAndroid::get_power_state() { if (GetPowerInfo_Android()) { return power_state; } else { @@ -227,7 +227,7 @@ OS::PowerState power_android::get_power_state() { } } -int power_android::get_power_seconds_left() { +int PowerAndroid::get_power_seconds_left() { if (GetPowerInfo_Android()) { return nsecs_left; } else { @@ -236,7 +236,7 @@ int power_android::get_power_seconds_left() { } } -int power_android::get_power_percent_left() { +int PowerAndroid::get_power_percent_left() { if (GetPowerInfo_Android()) { return percent_left; } else { @@ -245,11 +245,11 @@ int power_android::get_power_percent_left() { } } -power_android::power_android() : +PowerAndroid::PowerAndroid() : nsecs_left(-1), percent_left(-1), power_state(OS::POWERSTATE_UNKNOWN) { } -power_android::~power_android() { +PowerAndroid::~PowerAndroid() { } diff --git a/platform/android/power_android.h b/platform/android/power_android.h index 9730c53674..6cb745b6c0 100644 --- a/platform/android/power_android.h +++ b/platform/android/power_android.h @@ -28,13 +28,14 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef PLATFORM_ANDROID_POWER_ANDROID_H_ -#define PLATFORM_ANDROID_POWER_ANDROID_H_ +#ifndef POWER_ANDROID_H +#define POWER_ANDROID_H #include "core/os/os.h" + #include -class power_android { +class PowerAndroid { struct LocalReferenceHolder { JNIEnv *m_env; @@ -65,8 +66,8 @@ private: public: static int s_active; - power_android(); - virtual ~power_android(); + PowerAndroid(); + virtual ~PowerAndroid(); static bool LocalReferenceHolder_Init(struct LocalReferenceHolder *refholder, JNIEnv *env); static struct LocalReferenceHolder LocalReferenceHolder_Setup(const char *func); static void LocalReferenceHolder_Cleanup(struct LocalReferenceHolder *refholder); @@ -76,4 +77,4 @@ public: int get_power_percent_left(); }; -#endif /* PLATFORM_ANDROID_POWER_ANDROID_H_ */ +#endif // POWER_ANDROID_H diff --git a/platform/iphone/SCsub b/platform/iphone/SCsub index d5540fe8db..41991bce86 100644 --- a/platform/iphone/SCsub +++ b/platform/iphone/SCsub @@ -7,7 +7,7 @@ import os iphone_lib = [ 'godot_iphone.cpp', 'os_iphone.cpp', - 'sem_iphone.cpp', + 'semaphore_iphone.cpp', 'gl_view.mm', 'main.m', 'app_delegate.mm', diff --git a/platform/iphone/os_iphone.cpp b/platform/iphone/os_iphone.cpp index 16634c3b30..c939e234b9 100644 --- a/platform/iphone/os_iphone.cpp +++ b/platform/iphone/os_iphone.cpp @@ -45,9 +45,10 @@ #include "core/project_settings.h" #include "drivers/unix/syslog_logger.h" -#include "sem_iphone.h" +#include "semaphore_iphone.h" #include "ios.h" + #include int OSIPhone::get_video_driver_count() const { diff --git a/platform/iphone/power_iphone.h b/platform/iphone/power_iphone.h index eb930b99c5..d7d4bf4a69 100644 --- a/platform/iphone/power_iphone.h +++ b/platform/iphone/power_iphone.h @@ -28,8 +28,8 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef PLATFORM_IPHONE_POWER_IPHONE_H_ -#define PLATFORM_IPHONE_POWER_IPHONE_H_ +#ifndef POWER_IPHONE_H +#define POWER_IPHONE_H #include @@ -50,4 +50,4 @@ public: int get_power_percent_left(); }; -#endif /* PLATFORM_IPHONE_POWER_IPHONE_H_ */ +#endif // POWER_IPHONE_H diff --git a/platform/iphone/sem_iphone.cpp b/platform/iphone/sem_iphone.cpp deleted file mode 100644 index 05cdb6a2f7..0000000000 --- a/platform/iphone/sem_iphone.cpp +++ /dev/null @@ -1,111 +0,0 @@ -/*************************************************************************/ -/* sem_iphone.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#include "sem_iphone.h" - -#include -#include - -void cgsem_init(cgsem_t *); -void cgsem_post(cgsem_t *); -void cgsem_wait(cgsem_t *); -void cgsem_destroy(cgsem_t *); - -void cgsem_init(cgsem_t *cgsem) { - int flags, fd, i; - - pipe(cgsem->pipefd); - - /* Make the pipes FD_CLOEXEC to allow them to close should we call - * execv on restart. */ - for (i = 0; i < 2; i++) { - fd = cgsem->pipefd[i]; - flags = fcntl(fd, F_GETFD, 0); - flags |= FD_CLOEXEC; - fcntl(fd, F_SETFD, flags); - } -} - -void cgsem_post(cgsem_t *cgsem) { - const char buf = 1; - - write(cgsem->pipefd[1], &buf, 1); -} - -void cgsem_wait(cgsem_t *cgsem) { - char buf; - - read(cgsem->pipefd[0], &buf, 1); -} - -void cgsem_destroy(cgsem_t *cgsem) { - close(cgsem->pipefd[1]); - close(cgsem->pipefd[0]); -} - -#include "core/os/memory.h" -#include - -Error SemaphoreIphone::wait() { - - cgsem_wait(&sem); - return OK; -} - -Error SemaphoreIphone::post() { - - cgsem_post(&sem); - - return OK; -} -int SemaphoreIphone::get() const { - - return 0; -} - -Semaphore *SemaphoreIphone::create_semaphore_iphone() { - - return memnew(SemaphoreIphone); -} - -void SemaphoreIphone::make_default() { - - create_func = create_semaphore_iphone; -} - -SemaphoreIphone::SemaphoreIphone() { - - cgsem_init(&sem); -} - -SemaphoreIphone::~SemaphoreIphone() { - - cgsem_destroy(&sem); -} diff --git a/platform/iphone/sem_iphone.h b/platform/iphone/sem_iphone.h deleted file mode 100644 index 134bc723d9..0000000000 --- a/platform/iphone/sem_iphone.h +++ /dev/null @@ -1,59 +0,0 @@ -/*************************************************************************/ -/* sem_iphone.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#ifndef SEM_IPHONE_H -#define SEM_IPHONE_H - -struct cgsem { - int pipefd[2]; -}; - -typedef struct cgsem cgsem_t; - -#include "core/os/semaphore.h" - -class SemaphoreIphone : public Semaphore { - - mutable cgsem_t sem; - - static Semaphore *create_semaphore_iphone(); - -public: - virtual Error wait(); - virtual Error post(); - virtual int get() const; - - static void make_default(); - SemaphoreIphone(); - - ~SemaphoreIphone(); -}; - -#endif diff --git a/platform/iphone/semaphore_iphone.cpp b/platform/iphone/semaphore_iphone.cpp new file mode 100644 index 0000000000..cc7dde72f7 --- /dev/null +++ b/platform/iphone/semaphore_iphone.cpp @@ -0,0 +1,112 @@ +/*************************************************************************/ +/* semaphore_iphone.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "semaphore_iphone.h" + +#include +#include + +void cgsem_init(cgsem_t *); +void cgsem_post(cgsem_t *); +void cgsem_wait(cgsem_t *); +void cgsem_destroy(cgsem_t *); + +void cgsem_init(cgsem_t *cgsem) { + int flags, fd, i; + + pipe(cgsem->pipefd); + + /* Make the pipes FD_CLOEXEC to allow them to close should we call + * execv on restart. */ + for (i = 0; i < 2; i++) { + fd = cgsem->pipefd[i]; + flags = fcntl(fd, F_GETFD, 0); + flags |= FD_CLOEXEC; + fcntl(fd, F_SETFD, flags); + } +} + +void cgsem_post(cgsem_t *cgsem) { + const char buf = 1; + + write(cgsem->pipefd[1], &buf, 1); +} + +void cgsem_wait(cgsem_t *cgsem) { + char buf; + + read(cgsem->pipefd[0], &buf, 1); +} + +void cgsem_destroy(cgsem_t *cgsem) { + close(cgsem->pipefd[1]); + close(cgsem->pipefd[0]); +} + +#include "core/os/memory.h" + +#include + +Error SemaphoreIphone::wait() { + + cgsem_wait(&sem); + return OK; +} + +Error SemaphoreIphone::post() { + + cgsem_post(&sem); + + return OK; +} +int SemaphoreIphone::get() const { + + return 0; +} + +Semaphore *SemaphoreIphone::create_semaphore_iphone() { + + return memnew(SemaphoreIphone); +} + +void SemaphoreIphone::make_default() { + + create_func = create_semaphore_iphone; +} + +SemaphoreIphone::SemaphoreIphone() { + + cgsem_init(&sem); +} + +SemaphoreIphone::~SemaphoreIphone() { + + cgsem_destroy(&sem); +} diff --git a/platform/iphone/semaphore_iphone.h b/platform/iphone/semaphore_iphone.h new file mode 100644 index 0000000000..16658384e6 --- /dev/null +++ b/platform/iphone/semaphore_iphone.h @@ -0,0 +1,59 @@ +/*************************************************************************/ +/* semaphore_iphone.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef SEMAPHORE_IPHONE_H +#define SEMAPHORE_IPHONE_H + +struct cgsem { + int pipefd[2]; +}; + +typedef struct cgsem cgsem_t; + +#include "core/os/semaphore.h" + +class SemaphoreIphone : public Semaphore { + + mutable cgsem_t sem; + + static Semaphore *create_semaphore_iphone(); + +public: + virtual Error wait(); + virtual Error post(); + virtual int get() const; + + static void make_default(); + SemaphoreIphone(); + + ~SemaphoreIphone(); +}; + +#endif // SEMAPHORE_IPHONE_H diff --git a/platform/osx/SCsub b/platform/osx/SCsub index dc407eee9e..d2952ebdc0 100644 --- a/platform/osx/SCsub +++ b/platform/osx/SCsub @@ -10,7 +10,7 @@ files = [ 'crash_handler_osx.mm', 'os_osx.mm', 'godot_main_osx.mm', - 'sem_osx.cpp', + 'semaphore_osx.cpp', 'dir_access_osx.mm', 'joypad_osx.cpp', 'power_osx.cpp', diff --git a/platform/osx/crash_handler_osx.h b/platform/osx/crash_handler_osx.h index dead90ca90..6a72ce8ae9 100644 --- a/platform/osx/crash_handler_osx.h +++ b/platform/osx/crash_handler_osx.h @@ -45,4 +45,4 @@ public: ~CrashHandler(); }; -#endif +#endif // CRASH_HANDLER_OSX_H diff --git a/platform/osx/crash_handler_osx.mm b/platform/osx/crash_handler_osx.mm index 6684898085..ed8a955ae5 100644 --- a/platform/osx/crash_handler_osx.mm +++ b/platform/osx/crash_handler_osx.mm @@ -28,9 +28,11 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ +#include "crash_handler_osx.h" + +#include "core/os/os.h" #include "core/project_settings.h" #include "main/main.h" -#include "os_osx.h" #include #include diff --git a/platform/osx/os_osx.h b/platform/osx/os_osx.h index 32199e0adb..dfe7b27bd0 100644 --- a/platform/osx/os_osx.h +++ b/platform/osx/os_osx.h @@ -43,6 +43,7 @@ #include "servers/visual/rasterizer.h" #include "servers/visual/visual_server_wrap_mt.h" #include "servers/visual_server.h" + #include #include #include @@ -132,7 +133,7 @@ public: String im_text; Point2 im_selection; - power_osx *power_manager; + PowerOSX *power_manager; CrashHandler crash_handler; diff --git a/platform/osx/os_osx.mm b/platform/osx/os_osx.mm index 6b65c1a529..225e0aee06 100644 --- a/platform/osx/os_osx.mm +++ b/platform/osx/os_osx.mm @@ -37,7 +37,7 @@ #include "drivers/gles2/rasterizer_gles2.h" #include "drivers/gles3/rasterizer_gles3.h" #include "main/main.h" -#include "sem_osx.h" +#include "semaphore_osx.h" #include "servers/visual/visual_server_raster.h" #include @@ -1461,7 +1461,7 @@ Error OS_OSX::initialize(const VideoMode &p_desired, int p_video_driver, int p_a input = memnew(InputDefault); joypad_osx = memnew(JoypadOSX); - power_manager = memnew(power_osx); + power_manager = memnew(PowerOSX); _ensure_user_data_dir(); diff --git a/platform/osx/power_osx.cpp b/platform/osx/power_osx.cpp index a7cf9d831f..04d423d8c5 100644 --- a/platform/osx/power_osx.cpp +++ b/platform/osx/power_osx.cpp @@ -67,7 +67,7 @@ Adapted from corresponding SDL 2.0 code. CFDictionaryGetValueIfPresent(dict, CFSTR(k), (const void **)v) /* Note that AC power sources also include a laptop battery it is charging. */ -void power_osx::checkps(CFDictionaryRef dict, bool *have_ac, bool *have_battery, bool *charging) { +void PowerOSX::checkps(CFDictionaryRef dict, bool *have_ac, bool *have_battery, bool *charging) { CFStringRef strval; /* don't CFRelease() this. */ CFBooleanRef bval; CFNumberRef numval; @@ -169,7 +169,7 @@ void power_osx::checkps(CFDictionaryRef dict, bool *have_ac, bool *have_battery, #undef STRMATCH // CODE CHUNK IMPORTED FROM SDL 2.0 -bool power_osx::GetPowerInfo_MacOSX() { +bool PowerOSX::GetPowerInfo_MacOSX() { CFTypeRef blob = IOPSCopyPowerSourcesInfo(); nsecs_left = -1; @@ -211,14 +211,14 @@ bool power_osx::GetPowerInfo_MacOSX() { return true; /* always the definitive answer on Mac OS X. */ } -bool power_osx::UpdatePowerInfo() { +bool PowerOSX::UpdatePowerInfo() { if (GetPowerInfo_MacOSX()) { return true; } return false; } -OS::PowerState power_osx::get_power_state() { +OS::PowerState PowerOSX::get_power_state() { if (UpdatePowerInfo()) { return power_state; } else { @@ -226,7 +226,7 @@ OS::PowerState power_osx::get_power_state() { } } -int power_osx::get_power_seconds_left() { +int PowerOSX::get_power_seconds_left() { if (UpdatePowerInfo()) { return nsecs_left; } else { @@ -234,7 +234,7 @@ int power_osx::get_power_seconds_left() { } } -int power_osx::get_power_percent_left() { +int PowerOSX::get_power_percent_left() { if (UpdatePowerInfo()) { return percent_left; } else { @@ -242,11 +242,11 @@ int power_osx::get_power_percent_left() { } } -power_osx::power_osx() : +PowerOSX::PowerOSX() : nsecs_left(-1), percent_left(-1), power_state(OS::POWERSTATE_UNKNOWN) { } -power_osx::~power_osx() { +PowerOSX::~PowerOSX() { } diff --git a/platform/osx/power_osx.h b/platform/osx/power_osx.h index 0f18f9f691..40d0d40fd4 100644 --- a/platform/osx/power_osx.h +++ b/platform/osx/power_osx.h @@ -28,15 +28,16 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef PLATFORM_OSX_POWER_OSX_H_ -#define PLATFORM_OSX_POWER_OSX_H_ +#ifndef POWER_OSX_H +#define POWER_OSX_H #include "core/os/file_access.h" #include "core/os/os.h" #include "dir_access_osx.h" + #include -class power_osx { +class PowerOSX { private: int nsecs_left; @@ -47,12 +48,12 @@ private: bool UpdatePowerInfo(); public: - power_osx(); - virtual ~power_osx(); + PowerOSX(); + virtual ~PowerOSX(); OS::PowerState get_power_state(); int get_power_seconds_left(); int get_power_percent_left(); }; -#endif /* PLATFORM_OSX_POWER_OSX_H_ */ +#endif // POWER_OSX_H diff --git a/platform/osx/sem_osx.cpp b/platform/osx/sem_osx.cpp deleted file mode 100644 index 4c3bad4379..0000000000 --- a/platform/osx/sem_osx.cpp +++ /dev/null @@ -1,106 +0,0 @@ -/*************************************************************************/ -/* sem_osx.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#include "sem_osx.h" - -#include -#include - -void cgsem_init(cgsem_t *cgsem) { - int flags, fd, i; - - pipe(cgsem->pipefd); - - /* Make the pipes FD_CLOEXEC to allow them to close should we call - * execv on restart. */ - for (i = 0; i < 2; i++) { - fd = cgsem->pipefd[i]; - flags = fcntl(fd, F_GETFD, 0); - flags |= FD_CLOEXEC; - fcntl(fd, F_SETFD, flags); - } -} - -void cgsem_post(cgsem_t *cgsem) { - const char buf = 1; - - write(cgsem->pipefd[1], &buf, 1); -} - -void cgsem_wait(cgsem_t *cgsem) { - char buf; - - read(cgsem->pipefd[0], &buf, 1); -} - -void cgsem_destroy(cgsem_t *cgsem) { - close(cgsem->pipefd[1]); - close(cgsem->pipefd[0]); -} - -#include "core/os/memory.h" -#include - -Error SemaphoreOSX::wait() { - - cgsem_wait(&sem); - return OK; -} - -Error SemaphoreOSX::post() { - - cgsem_post(&sem); - - return OK; -} -int SemaphoreOSX::get() const { - - return 0; -} - -Semaphore *SemaphoreOSX::create_semaphore_osx() { - - return memnew(SemaphoreOSX); -} - -void SemaphoreOSX::make_default() { - - create_func = create_semaphore_osx; -} - -SemaphoreOSX::SemaphoreOSX() { - - cgsem_init(&sem); -} - -SemaphoreOSX::~SemaphoreOSX() { - - cgsem_destroy(&sem); -} diff --git a/platform/osx/sem_osx.h b/platform/osx/sem_osx.h deleted file mode 100644 index 563bdfdcb1..0000000000 --- a/platform/osx/sem_osx.h +++ /dev/null @@ -1,59 +0,0 @@ -/*************************************************************************/ -/* sem_osx.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#ifndef SEM_OSX_H -#define SEM_OSX_H - -struct cgsem { - int pipefd[2]; -}; - -typedef struct cgsem cgsem_t; - -#include "core/os/semaphore.h" - -class SemaphoreOSX : public Semaphore { - - mutable cgsem_t sem; - - static Semaphore *create_semaphore_osx(); - -public: - virtual Error wait(); - virtual Error post(); - virtual int get() const; - - static void make_default(); - SemaphoreOSX(); - - ~SemaphoreOSX(); -}; - -#endif diff --git a/platform/osx/semaphore_osx.cpp b/platform/osx/semaphore_osx.cpp new file mode 100644 index 0000000000..fe7d19bd9e --- /dev/null +++ b/platform/osx/semaphore_osx.cpp @@ -0,0 +1,107 @@ +/*************************************************************************/ +/* semaphore_osx.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "semaphore_osx.h" + +#include +#include + +void cgsem_init(cgsem_t *cgsem) { + int flags, fd, i; + + pipe(cgsem->pipefd); + + /* Make the pipes FD_CLOEXEC to allow them to close should we call + * execv on restart. */ + for (i = 0; i < 2; i++) { + fd = cgsem->pipefd[i]; + flags = fcntl(fd, F_GETFD, 0); + flags |= FD_CLOEXEC; + fcntl(fd, F_SETFD, flags); + } +} + +void cgsem_post(cgsem_t *cgsem) { + const char buf = 1; + + write(cgsem->pipefd[1], &buf, 1); +} + +void cgsem_wait(cgsem_t *cgsem) { + char buf; + + read(cgsem->pipefd[0], &buf, 1); +} + +void cgsem_destroy(cgsem_t *cgsem) { + close(cgsem->pipefd[1]); + close(cgsem->pipefd[0]); +} + +#include "core/os/memory.h" + +#include + +Error SemaphoreOSX::wait() { + + cgsem_wait(&sem); + return OK; +} + +Error SemaphoreOSX::post() { + + cgsem_post(&sem); + + return OK; +} +int SemaphoreOSX::get() const { + + return 0; +} + +Semaphore *SemaphoreOSX::create_semaphore_osx() { + + return memnew(SemaphoreOSX); +} + +void SemaphoreOSX::make_default() { + + create_func = create_semaphore_osx; +} + +SemaphoreOSX::SemaphoreOSX() { + + cgsem_init(&sem); +} + +SemaphoreOSX::~SemaphoreOSX() { + + cgsem_destroy(&sem); +} diff --git a/platform/osx/semaphore_osx.h b/platform/osx/semaphore_osx.h new file mode 100644 index 0000000000..c8e7c45227 --- /dev/null +++ b/platform/osx/semaphore_osx.h @@ -0,0 +1,59 @@ +/*************************************************************************/ +/* semaphore_osx.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef SEMAPHORE_OSX_H +#define SEMAPHORE_OSX_H + +struct cgsem { + int pipefd[2]; +}; + +typedef struct cgsem cgsem_t; + +#include "core/os/semaphore.h" + +class SemaphoreOSX : public Semaphore { + + mutable cgsem_t sem; + + static Semaphore *create_semaphore_osx(); + +public: + virtual Error wait(); + virtual Error post(); + virtual int get() const; + + static void make_default(); + SemaphoreOSX(); + + ~SemaphoreOSX(); +}; + +#endif // SEMAPHORE_OSX_H diff --git a/platform/server/SCsub b/platform/server/SCsub index 51fd05a87e..62d45efbc0 100644 --- a/platform/server/SCsub +++ b/platform/server/SCsub @@ -13,7 +13,7 @@ common_server = [\ if sys.platform == "darwin": common_server.append("#platform/osx/crash_handler_osx.mm") common_server.append("#platform/osx/power_osx.cpp") - common_server.append("#platform/osx/sem_osx.cpp") + common_server.append("#platform/osx/semaphore_osx.cpp") else: common_server.append("#platform/x11/crash_handler_x11.cpp") common_server.append("#platform/x11/power_x11.cpp") diff --git a/platform/server/os_server.cpp b/platform/server/os_server.cpp index 9b6e7864e1..e643d3e8bb 100644 --- a/platform/server/os_server.cpp +++ b/platform/server/os_server.cpp @@ -93,7 +93,7 @@ Error OS_Server::initialize(const VideoMode &p_desired, int p_video_driver, int input = memnew(InputDefault); #ifdef __APPLE__ - power_manager = memnew(power_osx); + power_manager = memnew(PowerOSX); #else power_manager = memnew(PowerX11); #endif diff --git a/platform/server/os_server.h b/platform/server/os_server.h index 7273a690ca..312b5811d1 100644 --- a/platform/server/os_server.h +++ b/platform/server/os_server.h @@ -38,7 +38,7 @@ #ifdef __APPLE__ #include "platform/osx/crash_handler_osx.h" #include "platform/osx/power_osx.h" -#include "platform/osx/sem_osx.h" +#include "platform/osx/semaphore_osx.h" #else #include "platform/x11/crash_handler_x11.h" #include "platform/x11/power_x11.h" @@ -69,7 +69,7 @@ class OS_Server : public OS_Unix { InputDefault *input; #ifdef __APPLE__ - power_osx *power_manager; + PowerOSX *power_manager; #else PowerX11 *power_manager; #endif diff --git a/platform/uwp/SCsub b/platform/uwp/SCsub index fb0c4a92ae..c14290f0c4 100644 --- a/platform/uwp/SCsub +++ b/platform/uwp/SCsub @@ -4,11 +4,11 @@ Import('env') files = [ 'thread_uwp.cpp', - '#platform/windows/key_mapping_win.cpp', + '#platform/windows/key_mapping_windows.cpp', '#platform/windows/windows_terminal_logger.cpp', 'joypad_uwp.cpp', 'power_uwp.cpp', - 'gl_context_egl.cpp', + 'context_egl_uwp.cpp', 'app.cpp', 'os_uwp.cpp', ] diff --git a/platform/uwp/app.cpp b/platform/uwp/app.cpp index 1b8f9f3f9e..4f2ee0237a 100644 --- a/platform/uwp/app.cpp +++ b/platform/uwp/app.cpp @@ -39,7 +39,7 @@ #include "core/os/keyboard.h" #include "main/main.h" -#include "platform/windows/key_mapping_win.h" +#include "platform/windows/key_mapping_windows.h" #include @@ -99,7 +99,7 @@ void App::Initialize(CoreApplicationView ^ applicationView) { // Information about the Suspending and Resuming event handlers can be found here: // http://msdn.microsoft.com/en-us/library/windows/apps/xaml/hh994930.aspx - os = new OSUWP; + os = new OS_UWP; } // Called when the CoreWindow object is created (or re-created). @@ -398,7 +398,7 @@ void App::OnMouseMoved(MouseDevice ^ mouse_device, MouseEventArgs ^ args) { void App::key_event(Windows::UI::Core::CoreWindow ^ sender, bool p_pressed, Windows::UI::Core::KeyEventArgs ^ key_args, Windows::UI::Core::CharacterReceivedEventArgs ^ char_args) { - OSUWP::KeyEvent ke; + OS_UWP::KeyEvent ke; ke.control = sender->GetAsyncKeyState(VirtualKey::Control) == CoreVirtualKeyStates::Down; ke.alt = sender->GetAsyncKeyState(VirtualKey::Menu) == CoreVirtualKeyStates::Down; @@ -408,14 +408,14 @@ void App::key_event(Windows::UI::Core::CoreWindow ^ sender, bool p_pressed, Wind if (key_args != nullptr) { - ke.type = OSUWP::KeyEvent::MessageType::KEY_EVENT_MESSAGE; + ke.type = OS_UWP::KeyEvent::MessageType::KEY_EVENT_MESSAGE; ke.unicode = 0; ke.scancode = KeyMappingWindows::get_keysym((unsigned int)key_args->VirtualKey); ke.echo = (!p_pressed && !key_args->KeyStatus.IsKeyReleased) || (p_pressed && key_args->KeyStatus.WasKeyDown); } else { - ke.type = OSUWP::KeyEvent::MessageType::CHAR_EVENT_MESSAGE; + ke.type = OS_UWP::KeyEvent::MessageType::CHAR_EVENT_MESSAGE; ke.unicode = char_args->KeyCode; ke.scancode = 0; ke.echo = (!p_pressed && !char_args->KeyStatus.IsKeyReleased) || (p_pressed && char_args->KeyStatus.WasKeyDown); diff --git a/platform/uwp/app.h b/platform/uwp/app.h index d403dace9d..0bd996d483 100644 --- a/platform/uwp/app.h +++ b/platform/uwp/app.h @@ -103,7 +103,7 @@ namespace GodotUWP EGLSurface mEglSurface; CoreWindow^ window; - OSUWP* os; + OS_UWP* os; int last_touch_x[32]; // 20 fingers, index 31 reserved for the mouse int last_touch_y[32]; diff --git a/platform/uwp/context_egl_uwp.cpp b/platform/uwp/context_egl_uwp.cpp new file mode 100644 index 0000000000..061c54687c --- /dev/null +++ b/platform/uwp/context_egl_uwp.cpp @@ -0,0 +1,221 @@ +/*************************************************************************/ +/* context_egl_uwp.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "context_egl_uwp.h" + +#include "EGL/eglext.h" + +using Platform::Exception; + +void ContextEGL_UWP::release_current() { + + eglMakeCurrent(mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, mEglContext); +}; + +void ContextEGL_UWP::make_current() { + + eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext); +}; + +int ContextEGL_UWP::get_window_width() { + + return width; +}; + +int ContextEGL_UWP::get_window_height() { + + return height; +}; + +void ContextEGL_UWP::reset() { + + cleanup(); + + window = CoreWindow::GetForCurrentThread(); + initialize(); +}; + +void ContextEGL_UWP::swap_buffers() { + + if (eglSwapBuffers(mEglDisplay, mEglSurface) != EGL_TRUE) { + cleanup(); + + window = CoreWindow::GetForCurrentThread(); + initialize(); + + // tell rasterizer to reload textures and stuff? + } +}; + +Error ContextEGL_UWP::initialize() { + + EGLint configAttribList[] = { + EGL_RED_SIZE, 8, + EGL_GREEN_SIZE, 8, + EGL_BLUE_SIZE, 8, + EGL_ALPHA_SIZE, 8, + EGL_DEPTH_SIZE, 8, + EGL_STENCIL_SIZE, 8, + EGL_SAMPLE_BUFFERS, 0, + EGL_NONE + }; + + EGLint surfaceAttribList[] = { + EGL_NONE, EGL_NONE + }; + + EGLint numConfigs = 0; + EGLint majorVersion = 1; + EGLint minorVersion; + if (driver == GLES_2_0) { + minorVersion = 0; + } else { + minorVersion = 5; + } + EGLDisplay display = EGL_NO_DISPLAY; + EGLContext context = EGL_NO_CONTEXT; + EGLSurface surface = EGL_NO_SURFACE; + EGLConfig config = nullptr; + EGLint contextAttribs[3]; + if (driver == GLES_2_0) { + contextAttribs[0] = EGL_CONTEXT_CLIENT_VERSION; + contextAttribs[1] = 2; + contextAttribs[2] = EGL_NONE; + } else { + contextAttribs[0] = EGL_CONTEXT_CLIENT_VERSION; + contextAttribs[1] = 3; + contextAttribs[2] = EGL_NONE; + } + + try { + + const EGLint displayAttributes[] = { + /*EGL_PLATFORM_ANGLE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE, + EGL_PLATFORM_ANGLE_MAX_VERSION_MAJOR_ANGLE, 9, + EGL_PLATFORM_ANGLE_MAX_VERSION_MINOR_ANGLE, 3, + EGL_NONE,*/ + // These are the default display attributes, used to request ANGLE's D3D11 renderer. + // eglInitialize will only succeed with these attributes if the hardware supports D3D11 Feature Level 10_0+. + EGL_PLATFORM_ANGLE_TYPE_ANGLE, + EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE, + + // EGL_ANGLE_DISPLAY_ALLOW_RENDER_TO_BACK_BUFFER is an optimization that can have large performance benefits on mobile devices. + // Its syntax is subject to change, though. Please update your Visual Studio templates if you experience compilation issues with it. + EGL_ANGLE_DISPLAY_ALLOW_RENDER_TO_BACK_BUFFER, + EGL_TRUE, + + // EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE is an option that enables ANGLE to automatically call + // the IDXGIDevice3::Trim method on behalf of the application when it gets suspended. + // Calling IDXGIDevice3::Trim when an application is suspended is a Windows Store application certification requirement. + EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE, + EGL_TRUE, + EGL_NONE, + }; + + PFNEGLGETPLATFORMDISPLAYEXTPROC eglGetPlatformDisplayEXT = reinterpret_cast(eglGetProcAddress("eglGetPlatformDisplayEXT")); + + if (!eglGetPlatformDisplayEXT) { + throw Exception::CreateException(E_FAIL, L"Failed to get function eglGetPlatformDisplayEXT"); + } + + display = eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE, EGL_DEFAULT_DISPLAY, displayAttributes); + + if (display == EGL_NO_DISPLAY) { + throw Exception::CreateException(E_FAIL, L"Failed to get default EGL display"); + } + + if (eglInitialize(display, &majorVersion, &minorVersion) == EGL_FALSE) { + throw Exception::CreateException(E_FAIL, L"Failed to initialize EGL"); + } + + if (eglGetConfigs(display, NULL, 0, &numConfigs) == EGL_FALSE) { + throw Exception::CreateException(E_FAIL, L"Failed to get EGLConfig count"); + } + + if (eglChooseConfig(display, configAttribList, &config, 1, &numConfigs) == EGL_FALSE) { + throw Exception::CreateException(E_FAIL, L"Failed to choose first EGLConfig count"); + } + + surface = eglCreateWindowSurface(display, config, reinterpret_cast(window), surfaceAttribList); + if (surface == EGL_NO_SURFACE) { + throw Exception::CreateException(E_FAIL, L"Failed to create EGL fullscreen surface"); + } + + context = eglCreateContext(display, config, EGL_NO_CONTEXT, contextAttribs); + if (context == EGL_NO_CONTEXT) { + throw Exception::CreateException(E_FAIL, L"Failed to create EGL context"); + } + + if (eglMakeCurrent(display, surface, surface, context) == EGL_FALSE) { + throw Exception::CreateException(E_FAIL, L"Failed to make fullscreen EGLSurface current"); + } + } catch (...) { + return FAILED; + }; + + mEglDisplay = display; + mEglSurface = surface; + mEglContext = context; + + eglQuerySurface(display, surface, EGL_WIDTH, &width); + eglQuerySurface(display, surface, EGL_HEIGHT, &height); + + return OK; +}; + +void ContextEGL_UWP::cleanup() { + + if (mEglDisplay != EGL_NO_DISPLAY && mEglSurface != EGL_NO_SURFACE) { + eglDestroySurface(mEglDisplay, mEglSurface); + mEglSurface = EGL_NO_SURFACE; + } + + if (mEglDisplay != EGL_NO_DISPLAY && mEglContext != EGL_NO_CONTEXT) { + eglDestroyContext(mEglDisplay, mEglContext); + mEglContext = EGL_NO_CONTEXT; + } + + if (mEglDisplay != EGL_NO_DISPLAY) { + eglTerminate(mEglDisplay); + mEglDisplay = EGL_NO_DISPLAY; + } +}; + +ContextEGL_UWP::ContextEGL_UWP(CoreWindow ^ p_window, Driver p_driver) : + mEglDisplay(EGL_NO_DISPLAY), + mEglContext(EGL_NO_CONTEXT), + mEglSurface(EGL_NO_SURFACE), + driver(p_driver), + window(p_window) {} + +ContextEGL_UWP::~ContextEGL_UWP() { + + cleanup(); +}; diff --git a/platform/uwp/context_egl_uwp.h b/platform/uwp/context_egl_uwp.h new file mode 100644 index 0000000000..812bdfb688 --- /dev/null +++ b/platform/uwp/context_egl_uwp.h @@ -0,0 +1,87 @@ +/*************************************************************************/ +/* context_egl_uwp.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef CONTEXT_EGL_UWP_H +#define CONTEXT_EGL_UWP_H + +#include + +#include + +#include "core/error_list.h" +#include "core/os/os.h" +#include "drivers/gl_context/context_gl.h" + +using namespace Windows::UI::Core; + +class ContextEGL_UWP : public ContextGL { + +public: + enum Driver { + GLES_2_0, + GLES_3_0, + }; + +private: + CoreWindow ^ window; + + EGLDisplay mEglDisplay; + EGLContext mEglContext; + EGLSurface mEglSurface; + + EGLint width; + EGLint height; + + bool vsync; + + Driver driver; + +public: + virtual void release_current(); + + virtual void make_current(); + + virtual int get_window_width(); + virtual int get_window_height(); + virtual void swap_buffers(); + + virtual void set_use_vsync(bool use) { vsync = use; } + virtual bool is_using_vsync() const { return vsync; } + + virtual Error initialize(); + void reset(); + + void cleanup(); + + ContextEGL_UWP(CoreWindow ^ p_window, Driver p_driver); + virtual ~ContextEGL_UWP(); +}; + +#endif // CONTEXT_EGL_UWP_H diff --git a/platform/uwp/export/export.cpp b/platform/uwp/export/export.cpp index 6808016f13..a4655117a7 100644 --- a/platform/uwp/export/export.cpp +++ b/platform/uwp/export/export.cpp @@ -646,9 +646,9 @@ AppxPackager::~AppxPackager() {} //////////////////////////////////////////////////////////////////// -class EditorExportUWP : public EditorExportPlatform { +class EditorExportPlatformUWP : public EditorExportPlatform { - GDCLASS(EditorExportUWP, EditorExportPlatform); + GDCLASS(EditorExportPlatformUWP, EditorExportPlatform); Ref logo; @@ -1035,13 +1035,13 @@ public: r_features->push_back("s3tc"); r_features->push_back("etc"); switch ((int)p_preset->get("architecture/target")) { - case EditorExportUWP::ARM: { + case EditorExportPlatformUWP::ARM: { r_features->push_back("arm"); } break; - case EditorExportUWP::X86: { + case EditorExportPlatformUWP::X86: { r_features->push_back("32"); } break; - case EditorExportUWP::X64: { + case EditorExportPlatformUWP::X64: { r_features->push_back("64"); } break; } @@ -1123,13 +1123,13 @@ public: String platform_infix; switch (arch) { - case EditorExportUWP::ARM: { + case EditorExportPlatformUWP::ARM: { platform_infix = "arm"; } break; - case EditorExportUWP::X86: { + case EditorExportPlatformUWP::X86: { platform_infix = "x86"; } break; - case EditorExportUWP::X64: { + case EditorExportPlatformUWP::X64: { platform_infix = "x64"; } break; } @@ -1459,7 +1459,7 @@ public: virtual void resolve_platform_feature_priorities(const Ref &p_preset, Set &p_features) { } - EditorExportUWP() { + EditorExportPlatformUWP() { Ref img = memnew(Image(_uwp_logo)); logo.instance(); logo->create_from_image(img); @@ -1478,7 +1478,7 @@ void register_uwp_exporter() { EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::INT, "export/uwp/debug_algorithm", PROPERTY_HINT_ENUM, "MD5,SHA1,SHA256")); #endif // WINDOWS_ENABLED - Ref exporter; + Ref exporter; exporter.instance(); EditorExport::get_singleton()->add_export_platform(exporter); } diff --git a/platform/uwp/gl_context_egl.cpp b/platform/uwp/gl_context_egl.cpp deleted file mode 100644 index db15be3e06..0000000000 --- a/platform/uwp/gl_context_egl.cpp +++ /dev/null @@ -1,221 +0,0 @@ -/*************************************************************************/ -/* gl_context_egl.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#include "gl_context_egl.h" - -#include "EGL/eglext.h" - -using Platform::Exception; - -void ContextEGL::release_current() { - - eglMakeCurrent(mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, mEglContext); -}; - -void ContextEGL::make_current() { - - eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext); -}; - -int ContextEGL::get_window_width() { - - return width; -}; - -int ContextEGL::get_window_height() { - - return height; -}; - -void ContextEGL::reset() { - - cleanup(); - - window = CoreWindow::GetForCurrentThread(); - initialize(); -}; - -void ContextEGL::swap_buffers() { - - if (eglSwapBuffers(mEglDisplay, mEglSurface) != EGL_TRUE) { - cleanup(); - - window = CoreWindow::GetForCurrentThread(); - initialize(); - - // tell rasterizer to reload textures and stuff? - } -}; - -Error ContextEGL::initialize() { - - EGLint configAttribList[] = { - EGL_RED_SIZE, 8, - EGL_GREEN_SIZE, 8, - EGL_BLUE_SIZE, 8, - EGL_ALPHA_SIZE, 8, - EGL_DEPTH_SIZE, 8, - EGL_STENCIL_SIZE, 8, - EGL_SAMPLE_BUFFERS, 0, - EGL_NONE - }; - - EGLint surfaceAttribList[] = { - EGL_NONE, EGL_NONE - }; - - EGLint numConfigs = 0; - EGLint majorVersion = 1; - EGLint minorVersion; - if (driver == GLES_2_0) { - minorVersion = 0; - } else { - minorVersion = 5; - } - EGLDisplay display = EGL_NO_DISPLAY; - EGLContext context = EGL_NO_CONTEXT; - EGLSurface surface = EGL_NO_SURFACE; - EGLConfig config = nullptr; - EGLint contextAttribs[3]; - if (driver == GLES_2_0) { - contextAttribs[0] = EGL_CONTEXT_CLIENT_VERSION; - contextAttribs[1] = 2; - contextAttribs[2] = EGL_NONE; - } else { - contextAttribs[0] = EGL_CONTEXT_CLIENT_VERSION; - contextAttribs[1] = 3; - contextAttribs[2] = EGL_NONE; - } - - try { - - const EGLint displayAttributes[] = { - /*EGL_PLATFORM_ANGLE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE, - EGL_PLATFORM_ANGLE_MAX_VERSION_MAJOR_ANGLE, 9, - EGL_PLATFORM_ANGLE_MAX_VERSION_MINOR_ANGLE, 3, - EGL_NONE,*/ - // These are the default display attributes, used to request ANGLE's D3D11 renderer. - // eglInitialize will only succeed with these attributes if the hardware supports D3D11 Feature Level 10_0+. - EGL_PLATFORM_ANGLE_TYPE_ANGLE, - EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE, - - // EGL_ANGLE_DISPLAY_ALLOW_RENDER_TO_BACK_BUFFER is an optimization that can have large performance benefits on mobile devices. - // Its syntax is subject to change, though. Please update your Visual Studio templates if you experience compilation issues with it. - EGL_ANGLE_DISPLAY_ALLOW_RENDER_TO_BACK_BUFFER, - EGL_TRUE, - - // EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE is an option that enables ANGLE to automatically call - // the IDXGIDevice3::Trim method on behalf of the application when it gets suspended. - // Calling IDXGIDevice3::Trim when an application is suspended is a Windows Store application certification requirement. - EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE, - EGL_TRUE, - EGL_NONE, - }; - - PFNEGLGETPLATFORMDISPLAYEXTPROC eglGetPlatformDisplayEXT = reinterpret_cast(eglGetProcAddress("eglGetPlatformDisplayEXT")); - - if (!eglGetPlatformDisplayEXT) { - throw Exception::CreateException(E_FAIL, L"Failed to get function eglGetPlatformDisplayEXT"); - } - - display = eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE, EGL_DEFAULT_DISPLAY, displayAttributes); - - if (display == EGL_NO_DISPLAY) { - throw Exception::CreateException(E_FAIL, L"Failed to get default EGL display"); - } - - if (eglInitialize(display, &majorVersion, &minorVersion) == EGL_FALSE) { - throw Exception::CreateException(E_FAIL, L"Failed to initialize EGL"); - } - - if (eglGetConfigs(display, NULL, 0, &numConfigs) == EGL_FALSE) { - throw Exception::CreateException(E_FAIL, L"Failed to get EGLConfig count"); - } - - if (eglChooseConfig(display, configAttribList, &config, 1, &numConfigs) == EGL_FALSE) { - throw Exception::CreateException(E_FAIL, L"Failed to choose first EGLConfig count"); - } - - surface = eglCreateWindowSurface(display, config, reinterpret_cast(window), surfaceAttribList); - if (surface == EGL_NO_SURFACE) { - throw Exception::CreateException(E_FAIL, L"Failed to create EGL fullscreen surface"); - } - - context = eglCreateContext(display, config, EGL_NO_CONTEXT, contextAttribs); - if (context == EGL_NO_CONTEXT) { - throw Exception::CreateException(E_FAIL, L"Failed to create EGL context"); - } - - if (eglMakeCurrent(display, surface, surface, context) == EGL_FALSE) { - throw Exception::CreateException(E_FAIL, L"Failed to make fullscreen EGLSurface current"); - } - } catch (...) { - return FAILED; - }; - - mEglDisplay = display; - mEglSurface = surface; - mEglContext = context; - - eglQuerySurface(display, surface, EGL_WIDTH, &width); - eglQuerySurface(display, surface, EGL_HEIGHT, &height); - - return OK; -}; - -void ContextEGL::cleanup() { - - if (mEglDisplay != EGL_NO_DISPLAY && mEglSurface != EGL_NO_SURFACE) { - eglDestroySurface(mEglDisplay, mEglSurface); - mEglSurface = EGL_NO_SURFACE; - } - - if (mEglDisplay != EGL_NO_DISPLAY && mEglContext != EGL_NO_CONTEXT) { - eglDestroyContext(mEglDisplay, mEglContext); - mEglContext = EGL_NO_CONTEXT; - } - - if (mEglDisplay != EGL_NO_DISPLAY) { - eglTerminate(mEglDisplay); - mEglDisplay = EGL_NO_DISPLAY; - } -}; - -ContextEGL::ContextEGL(CoreWindow ^ p_window, Driver p_driver) : - mEglDisplay(EGL_NO_DISPLAY), - mEglContext(EGL_NO_CONTEXT), - mEglSurface(EGL_NO_SURFACE), - driver(p_driver), - window(p_window) {} - -ContextEGL::~ContextEGL() { - - cleanup(); -}; diff --git a/platform/uwp/gl_context_egl.h b/platform/uwp/gl_context_egl.h deleted file mode 100644 index 60feed2e24..0000000000 --- a/platform/uwp/gl_context_egl.h +++ /dev/null @@ -1,86 +0,0 @@ -/*************************************************************************/ -/* gl_context_egl.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#ifndef CONTEXT_EGL_H -#define CONTEXT_EGL_H - -#include - -#include "EGL/egl.h" -#include "core/error_list.h" -#include "core/os/os.h" -#include "drivers/gl_context/context_gl.h" - -using namespace Windows::UI::Core; - -class ContextEGL : public ContextGL { - -public: - enum Driver { - GLES_2_0, - GLES_3_0, - }; - -private: - CoreWindow ^ window; - - EGLDisplay mEglDisplay; - EGLContext mEglContext; - EGLSurface mEglSurface; - - EGLint width; - EGLint height; - - bool vsync; - - Driver driver; - -public: - virtual void release_current(); - - virtual void make_current(); - - virtual int get_window_width(); - virtual int get_window_height(); - virtual void swap_buffers(); - - virtual void set_use_vsync(bool use) { vsync = use; } - virtual bool is_using_vsync() const { return vsync; } - - virtual Error initialize(); - void reset(); - - void cleanup(); - - ContextEGL(CoreWindow ^ p_window, Driver p_driver); - virtual ~ContextEGL(); -}; - -#endif diff --git a/platform/uwp/os_uwp.cpp b/platform/uwp/os_uwp.cpp index ea4f63b49c..9c9280ac7e 100644 --- a/platform/uwp/os_uwp.cpp +++ b/platform/uwp/os_uwp.cpp @@ -67,22 +67,22 @@ using namespace Windows::Devices::Sensors; using namespace Windows::ApplicationModel::DataTransfer; using namespace concurrency; -int OSUWP::get_video_driver_count() const { +int OS_UWP::get_video_driver_count() const { return 2; } -Size2 OSUWP::get_window_size() const { +Size2 OS_UWP::get_window_size() const { Size2 size; size.width = video_mode.width; size.height = video_mode.height; return size; } -int OSUWP::get_current_video_driver() const { +int OS_UWP::get_current_video_driver() const { return video_driver_index; } -void OSUWP::set_window_size(const Size2 p_size) { +void OS_UWP::set_window_size(const Size2 p_size) { Windows::Foundation::Size new_size; new_size.Width = p_size.width; @@ -97,7 +97,7 @@ void OSUWP::set_window_size(const Size2 p_size) { } } -void OSUWP::set_window_fullscreen(bool p_enabled) { +void OS_UWP::set_window_fullscreen(bool p_enabled) { ApplicationView ^ view = ApplicationView::GetForCurrentView(); @@ -117,12 +117,12 @@ void OSUWP::set_window_fullscreen(bool p_enabled) { } } -bool OSUWP::is_window_fullscreen() const { +bool OS_UWP::is_window_fullscreen() const { return ApplicationView::GetForCurrentView()->IsFullScreenMode; } -void OSUWP::set_keep_screen_on(bool p_enabled) { +void OS_UWP::set_keep_screen_on(bool p_enabled) { if (is_keep_screen_on() == p_enabled) return; @@ -134,7 +134,7 @@ void OSUWP::set_keep_screen_on(bool p_enabled) { OS::set_keep_screen_on(p_enabled); } -void OSUWP::initialize_core() { +void OS_UWP::initialize_core() { last_button_state = 0; @@ -167,36 +167,36 @@ void OSUWP::initialize_core() { cursor_shape = CURSOR_ARROW; } -bool OSUWP::can_draw() const { +bool OS_UWP::can_draw() const { return !minimized; }; -void OSUWP::set_window(Windows::UI::Core::CoreWindow ^ p_window) { +void OS_UWP::set_window(Windows::UI::Core::CoreWindow ^ p_window) { window = p_window; } -void OSUWP::screen_size_changed() { +void OS_UWP::screen_size_changed() { gl_context->reset(); }; -Error OSUWP::initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver) { +Error OS_UWP::initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver) { main_loop = NULL; outside = true; - ContextEGL::Driver opengl_api_type = ContextEGL::GLES_2_0; + ContextEGL_UWP::Driver opengl_api_type = ContextEGL_UWP::GLES_2_0; if (p_video_driver == VIDEO_DRIVER_GLES2) { - opengl_api_type = ContextEGL::GLES_2_0; + opengl_api_type = ContextEGL_UWP::GLES_2_0; } bool gl_initialization_error = false; gl_context = NULL; while (!gl_context) { - gl_context = memnew(ContextEGL(window, opengl_api_type)); + gl_context = memnew(ContextEGL_UWP(window, opengl_api_type)); if (gl_context->initialize() != OK) { memdelete(gl_context); @@ -209,7 +209,7 @@ Error OSUWP::initialize(const VideoMode &p_desired, int p_video_driver, int p_au } p_video_driver = VIDEO_DRIVER_GLES2; - opengl_api_type = ContextEGL::GLES_2_0; + opengl_api_type = ContextEGL_UWP::GLES_2_0; } else { gl_initialization_error = true; break; @@ -218,7 +218,7 @@ Error OSUWP::initialize(const VideoMode &p_desired, int p_video_driver, int p_au } while (true) { - if (opengl_api_type == ContextEGL::GLES_3_0) { + if (opengl_api_type == ContextEGL_UWP::GLES_3_0) { if (RasterizerGLES3::is_viable() == OK) { RasterizerGLES3::register_config(); RasterizerGLES3::make_current(); @@ -226,7 +226,7 @@ Error OSUWP::initialize(const VideoMode &p_desired, int p_video_driver, int p_au } else { if (GLOBAL_GET("rendering/quality/driver/driver_fallback") == "Best") { p_video_driver = VIDEO_DRIVER_GLES2; - opengl_api_type = ContextEGL::GLES_2_0; + opengl_api_type = ContextEGL_UWP::GLES_2_0; continue; } else { gl_initialization_error = true; @@ -235,7 +235,7 @@ Error OSUWP::initialize(const VideoMode &p_desired, int p_video_driver, int p_au } } - if (opengl_api_type == ContextEGL::GLES_2_0) { + if (opengl_api_type == ContextEGL_UWP::GLES_2_0) { if (RasterizerGLES2::is_viable() == OK) { RasterizerGLES2::register_config(); RasterizerGLES2::make_current(); @@ -349,7 +349,7 @@ Error OSUWP::initialize(const VideoMode &p_desired, int p_video_driver, int p_au return OK; } -void OSUWP::set_clipboard(const String &p_text) { +void OS_UWP::set_clipboard(const String &p_text) { DataPackage ^ clip = ref new DataPackage(); clip->RequestedOperation = DataPackageOperation::Copy; @@ -358,7 +358,7 @@ void OSUWP::set_clipboard(const String &p_text) { Clipboard::SetContent(clip); }; -String OSUWP::get_clipboard() const { +String OS_UWP::get_clipboard() const { if (managed_object->clipboard != nullptr) return managed_object->clipboard->Data(); @@ -366,25 +366,25 @@ String OSUWP::get_clipboard() const { return ""; }; -void OSUWP::input_event(const Ref &p_event) { +void OS_UWP::input_event(const Ref &p_event) { input->parse_input_event(p_event); }; -void OSUWP::delete_main_loop() { +void OS_UWP::delete_main_loop() { if (main_loop) memdelete(main_loop); main_loop = NULL; } -void OSUWP::set_main_loop(MainLoop *p_main_loop) { +void OS_UWP::set_main_loop(MainLoop *p_main_loop) { input->set_main_loop(p_main_loop); main_loop = p_main_loop; } -void OSUWP::finalize() { +void OS_UWP::finalize() { if (main_loop) memdelete(main_loop); @@ -403,19 +403,19 @@ void OSUWP::finalize() { joypad = nullptr; } -void OSUWP::finalize_core() { +void OS_UWP::finalize_core() { NetSocketPosix::cleanup(); } -void OSUWP::alert(const String &p_alert, const String &p_title) { +void OS_UWP::alert(const String &p_alert, const String &p_title) { Platform::String ^ alert = ref new Platform::String(p_alert.c_str()); Platform::String ^ title = ref new Platform::String(p_title.c_str()); MessageDialog ^ msg = ref new MessageDialog(alert, title); - UICommand ^ close = ref new UICommand("Close", ref new UICommandInvokedHandler(managed_object, &OSUWP::ManagedType::alert_close)); + UICommand ^ close = ref new UICommand("Close", ref new UICommandInvokedHandler(managed_object, &OS_UWP::ManagedType::alert_close)); msg->Commands->Append(close); msg->DefaultCommandIndex = 0; @@ -424,17 +424,17 @@ void OSUWP::alert(const String &p_alert, const String &p_title) { msg->ShowAsync(); } -void OSUWP::ManagedType::alert_close(IUICommand ^ command) { +void OS_UWP::ManagedType::alert_close(IUICommand ^ command) { alert_close_handle = false; } -void OSUWP::ManagedType::on_clipboard_changed(Platform::Object ^ sender, Platform::Object ^ ev) { +void OS_UWP::ManagedType::on_clipboard_changed(Platform::Object ^ sender, Platform::Object ^ ev) { update_clipboard(); } -void OSUWP::ManagedType::update_clipboard() { +void OS_UWP::ManagedType::update_clipboard() { DataPackageView ^ data = Clipboard::GetContent(); @@ -446,7 +446,7 @@ void OSUWP::ManagedType::update_clipboard() { } } -void OSUWP::ManagedType::on_accelerometer_reading_changed(Accelerometer ^ sender, AccelerometerReadingChangedEventArgs ^ args) { +void OS_UWP::ManagedType::on_accelerometer_reading_changed(Accelerometer ^ sender, AccelerometerReadingChangedEventArgs ^ args) { AccelerometerReading ^ reading = args->Reading; @@ -456,7 +456,7 @@ void OSUWP::ManagedType::on_accelerometer_reading_changed(Accelerometer ^ sender reading->AccelerationZ)); } -void OSUWP::ManagedType::on_magnetometer_reading_changed(Magnetometer ^ sender, MagnetometerReadingChangedEventArgs ^ args) { +void OS_UWP::ManagedType::on_magnetometer_reading_changed(Magnetometer ^ sender, MagnetometerReadingChangedEventArgs ^ args) { MagnetometerReading ^ reading = args->Reading; @@ -466,7 +466,7 @@ void OSUWP::ManagedType::on_magnetometer_reading_changed(Magnetometer ^ sender, reading->MagneticFieldZ)); } -void OSUWP::ManagedType::on_gyroscope_reading_changed(Gyrometer ^ sender, GyrometerReadingChangedEventArgs ^ args) { +void OS_UWP::ManagedType::on_gyroscope_reading_changed(Gyrometer ^ sender, GyrometerReadingChangedEventArgs ^ args) { GyrometerReading ^ reading = args->Reading; @@ -476,7 +476,7 @@ void OSUWP::ManagedType::on_gyroscope_reading_changed(Gyrometer ^ sender, Gyrome reading->AngularVelocityZ)); } -void OSUWP::set_mouse_mode(MouseMode p_mode) { +void OS_UWP::set_mouse_mode(MouseMode p_mode) { if (p_mode == MouseMode::MOUSE_MODE_CAPTURED) { @@ -501,41 +501,41 @@ void OSUWP::set_mouse_mode(MouseMode p_mode) { SetEvent(mouse_mode_changed); } -OSUWP::MouseMode OSUWP::get_mouse_mode() const { +OS_UWP::MouseMode OS_UWP::get_mouse_mode() const { return mouse_mode; } -Point2 OSUWP::get_mouse_position() const { +Point2 OS_UWP::get_mouse_position() const { return Point2(old_x, old_y); } -int OSUWP::get_mouse_button_state() const { +int OS_UWP::get_mouse_button_state() const { return last_button_state; } -void OSUWP::set_window_title(const String &p_title) { +void OS_UWP::set_window_title(const String &p_title) { } -void OSUWP::set_video_mode(const VideoMode &p_video_mode, int p_screen) { +void OS_UWP::set_video_mode(const VideoMode &p_video_mode, int p_screen) { video_mode = p_video_mode; } -OS::VideoMode OSUWP::get_video_mode(int p_screen) const { +OS::VideoMode OS_UWP::get_video_mode(int p_screen) const { return video_mode; } -void OSUWP::get_fullscreen_mode_list(List *p_list, int p_screen) const { +void OS_UWP::get_fullscreen_mode_list(List *p_list, int p_screen) const { } -String OSUWP::get_name() { +String OS_UWP::get_name() { return "UWP"; } -OS::Date OSUWP::get_date(bool utc) const { +OS::Date OS_UWP::get_date(bool utc) const { SYSTEMTIME systemtime; if (utc) @@ -551,7 +551,7 @@ OS::Date OSUWP::get_date(bool utc) const { date.dst = false; return date; } -OS::Time OSUWP::get_time(bool utc) const { +OS::Time OS_UWP::get_time(bool utc) const { SYSTEMTIME systemtime; if (utc) @@ -566,7 +566,7 @@ OS::Time OSUWP::get_time(bool utc) const { return time; } -OS::TimeZoneInfo OSUWP::get_time_zone_info() const { +OS::TimeZoneInfo OS_UWP::get_time_zone_info() const { TIME_ZONE_INFORMATION info; bool daylight = false; if (GetTimeZoneInformation(&info) == TIME_ZONE_ID_DAYLIGHT) @@ -583,7 +583,7 @@ OS::TimeZoneInfo OSUWP::get_time_zone_info() const { return ret; } -uint64_t OSUWP::get_unix_time() const { +uint64_t OS_UWP::get_unix_time() const { FILETIME ft; SYSTEMTIME st; @@ -605,14 +605,14 @@ uint64_t OSUWP::get_unix_time() const { return (*(uint64_t *)&ft - *(uint64_t *)&fep) / 10000000; }; -void OSUWP::delay_usec(uint32_t p_usec) const { +void OS_UWP::delay_usec(uint32_t p_usec) const { int msec = p_usec < 1000 ? 1 : p_usec / 1000; // no Sleep() WaitForSingleObjectEx(GetCurrentThread(), msec, false); } -uint64_t OSUWP::get_ticks_usec() const { +uint64_t OS_UWP::get_ticks_usec() const { uint64_t ticks; uint64_t time; @@ -626,13 +626,13 @@ uint64_t OSUWP::get_ticks_usec() const { return time; } -void OSUWP::process_events() { +void OS_UWP::process_events() { joypad->process_controllers(); process_key_events(); } -void OSUWP::process_key_events() { +void OS_UWP::process_key_events() { for (int i = 0; i < key_event_pos; i++) { @@ -653,7 +653,7 @@ void OSUWP::process_key_events() { key_event_pos = 0; } -void OSUWP::queue_key_event(KeyEvent &p_event) { +void OS_UWP::queue_key_event(KeyEvent &p_event) { // This merges Char events with the previous Key event, so // the unicode can be retrieved without sending duplicate events. if (p_event.type == KeyEvent::MessageType::CHAR_EVENT_MESSAGE && key_event_pos > 0) { @@ -670,7 +670,7 @@ void OSUWP::queue_key_event(KeyEvent &p_event) { key_event_buffer[key_event_pos++] = p_event; } -void OSUWP::set_cursor_shape(CursorShape p_shape) { +void OS_UWP::set_cursor_shape(CursorShape p_shape) { ERR_FAIL_INDEX(p_shape, CURSOR_MAX); @@ -702,62 +702,62 @@ void OSUWP::set_cursor_shape(CursorShape p_shape) { cursor_shape = p_shape; } -void OSUWP::set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) { +void OS_UWP::set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) { // TODO } -Error OSUWP::execute(const String &p_path, const List &p_arguments, bool p_blocking, ProcessID *r_child_id, String *r_pipe, int *r_exitcode, bool read_stderr) { +Error OS_UWP::execute(const String &p_path, const List &p_arguments, bool p_blocking, ProcessID *r_child_id, String *r_pipe, int *r_exitcode, bool read_stderr) { return FAILED; }; -Error OSUWP::kill(const ProcessID &p_pid) { +Error OS_UWP::kill(const ProcessID &p_pid) { return FAILED; }; -Error OSUWP::set_cwd(const String &p_cwd) { +Error OS_UWP::set_cwd(const String &p_cwd) { return FAILED; } -String OSUWP::get_executable_path() const { +String OS_UWP::get_executable_path() const { return ""; } -void OSUWP::set_icon(const Ref &p_icon) { +void OS_UWP::set_icon(const Ref &p_icon) { } -bool OSUWP::has_environment(const String &p_var) const { +bool OS_UWP::has_environment(const String &p_var) const { return false; }; -String OSUWP::get_environment(const String &p_var) const { +String OS_UWP::get_environment(const String &p_var) const { return ""; }; -bool OSUWP::set_environment(const String &p_var, const String &p_value) const { +bool OS_UWP::set_environment(const String &p_var, const String &p_value) const { return false; } -String OSUWP::get_stdin_string(bool p_block) { +String OS_UWP::get_stdin_string(bool p_block) { return String(); } -void OSUWP::move_window_to_foreground() { +void OS_UWP::move_window_to_foreground() { } -Error OSUWP::shell_open(String p_uri) { +Error OS_UWP::shell_open(String p_uri) { return FAILED; } -String OSUWP::get_locale() const { +String OS_UWP::get_locale() const { #if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP // this should work on phone 8.1, but it doesn't return "en"; @@ -767,39 +767,39 @@ String OSUWP::get_locale() const { #endif } -void OSUWP::release_rendering_thread() { +void OS_UWP::release_rendering_thread() { gl_context->release_current(); } -void OSUWP::make_rendering_thread() { +void OS_UWP::make_rendering_thread() { gl_context->make_current(); } -void OSUWP::swap_buffers() { +void OS_UWP::swap_buffers() { gl_context->swap_buffers(); } -bool OSUWP::has_touchscreen_ui_hint() const { +bool OS_UWP::has_touchscreen_ui_hint() const { TouchCapabilities ^ tc = ref new TouchCapabilities(); return tc->TouchPresent != 0 || UIViewSettings::GetForCurrentView()->UserInteractionMode == UserInteractionMode::Touch; } -bool OSUWP::has_virtual_keyboard() const { +bool OS_UWP::has_virtual_keyboard() const { return UIViewSettings::GetForCurrentView()->UserInteractionMode == UserInteractionMode::Touch; } -void OSUWP::show_virtual_keyboard(const String &p_existing_text, const Rect2 &p_screen_rect) { +void OS_UWP::show_virtual_keyboard(const String &p_existing_text, const Rect2 &p_screen_rect) { InputPane ^ pane = InputPane::GetForCurrentView(); pane->TryShow(); } -void OSUWP::hide_virtual_keyboard() { +void OS_UWP::hide_virtual_keyboard() { InputPane ^ pane = InputPane::GetForCurrentView(); pane->TryHide(); @@ -818,7 +818,7 @@ static String format_error_message(DWORD id) { return msg; } -Error OSUWP::open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path) { +Error OS_UWP::open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path) { String full_path = "game/" + p_path; p_library_handle = (void *)LoadPackagedLibrary(full_path.c_str(), 0); @@ -830,14 +830,14 @@ Error OSUWP::open_dynamic_library(const String p_path, void *&p_library_handle, return OK; } -Error OSUWP::close_dynamic_library(void *p_library_handle) { +Error OS_UWP::close_dynamic_library(void *p_library_handle) { if (!FreeLibrary((HMODULE)p_library_handle)) { return FAILED; } return OK; } -Error OSUWP::get_dynamic_library_symbol_handle(void *p_library_handle, const String p_name, void *&p_symbol_handle, bool p_optional) { +Error OS_UWP::get_dynamic_library_symbol_handle(void *p_library_handle, const String p_name, void *&p_symbol_handle, bool p_optional) { p_symbol_handle = (void *)GetProcAddress((HMODULE)p_library_handle, p_name.utf8().get_data()); if (!p_symbol_handle) { if (!p_optional) { @@ -850,7 +850,7 @@ Error OSUWP::get_dynamic_library_symbol_handle(void *p_library_handle, const Str return OK; } -void OSUWP::run() { +void OS_UWP::run() { if (!main_loop) return; @@ -874,35 +874,35 @@ void OSUWP::run() { main_loop->finish(); } -MainLoop *OSUWP::get_main_loop() const { +MainLoop *OS_UWP::get_main_loop() const { return main_loop; } -String OSUWP::get_user_data_dir() const { +String OS_UWP::get_user_data_dir() const { Windows::Storage::StorageFolder ^ data_folder = Windows::Storage::ApplicationData::Current->LocalFolder; return String(data_folder->Path->Data()).replace("\\", "/"); } -bool OSUWP::_check_internal_feature_support(const String &p_feature) { +bool OS_UWP::_check_internal_feature_support(const String &p_feature) { return p_feature == "pc" || p_feature == "s3tc"; } -OS::PowerState OSUWP::get_power_state() { +OS::PowerState OS_UWP::get_power_state() { return power_manager->get_power_state(); } -int OSUWP::get_power_seconds_left() { +int OS_UWP::get_power_seconds_left() { return power_manager->get_power_seconds_left(); } -int OSUWP::get_power_percent_left() { +int OS_UWP::get_power_percent_left() { return power_manager->get_power_percent_left(); } -OSUWP::OSUWP() { +OS_UWP::OS_UWP() { key_event_pos = 0; force_quit = false; @@ -936,7 +936,7 @@ OSUWP::OSUWP() { _set_logger(memnew(CompositeLogger(loggers))); } -OSUWP::~OSUWP() { +OS_UWP::~OS_UWP() { #ifdef STDOUT_FILE fclose(stdo); #endif diff --git a/platform/uwp/os_uwp.h b/platform/uwp/os_uwp.h index 5475c4e60a..fd78b3cdf7 100644 --- a/platform/uwp/os_uwp.h +++ b/platform/uwp/os_uwp.h @@ -28,15 +28,15 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef OSUWP_H -#define OSUWP_H +#ifndef OS_UWP_H +#define OS_UWP_H +#include "context_egl_uwp.h" #include "core/math/transform_2d.h" #include "core/os/input.h" #include "core/os/os.h" #include "core/ustring.h" #include "drivers/xaudio2/audio_driver_xaudio2.h" -#include "gl_context_egl.h" #include "joypad_uwp.h" #include "main/input_default.h" #include "power_uwp.h" @@ -52,7 +52,7 @@ /** @author Juan Linietsky */ -class OSUWP : public OS { +class OS_UWP : public OS { public: struct KeyEvent { @@ -95,7 +95,7 @@ private: VisualServer *visual_server; int pressrc; - ContextEGL *gl_context; + ContextEGL_UWP *gl_context; Windows::UI::Core::CoreWindow ^ window; VideoMode video_mode; @@ -144,7 +144,7 @@ private: /* clang-format off */ internal: ManagedType() { alert_close_handle = false; } - property OSUWP* os; + property OS_UWP* os; /* clang-format on */ }; ManagedType ^ managed_object; @@ -262,8 +262,8 @@ public: void queue_key_event(KeyEvent &p_event); - OSUWP(); - ~OSUWP(); + OS_UWP(); + ~OS_UWP(); }; #endif diff --git a/platform/uwp/power_uwp.h b/platform/uwp/power_uwp.h index d6623f9340..cc19904a62 100644 --- a/platform/uwp/power_uwp.h +++ b/platform/uwp/power_uwp.h @@ -28,8 +28,8 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef PLATFORM_UWP_POWER_UWP_H_ -#define PLATFORM_UWP_POWER_UWP_H_ +#ifndef POWER_UWP_H +#define POWER_UWP_H #include "core/os/dir_access.h" #include "core/os/file_access.h" @@ -53,4 +53,4 @@ public: int get_power_percent_left(); }; -#endif /* PLATFORM_UWP_POWER_UWP_H_ */ +#endif // POWER_UWP_H diff --git a/platform/windows/SCsub b/platform/windows/SCsub index e07d373c4b..892d734734 100644 --- a/platform/windows/SCsub +++ b/platform/windows/SCsub @@ -7,13 +7,12 @@ from platform_methods import run_in_subprocess import platform_windows_builders common_win = [ - "godot_win.cpp", - "context_gl_win.cpp", - "crash_handler_win.cpp", + "godot_windows.cpp", + "context_gl_windows.cpp", + "crash_handler_windows.cpp", "os_windows.cpp", - "ctxgl_procaddr.cpp", - "key_mapping_win.cpp", - "joypad.cpp", + "key_mapping_windows.cpp", + "joypad_windows.cpp", "power_windows.cpp", "windows_terminal_logger.cpp" ] diff --git a/platform/windows/context_gl_win.cpp b/platform/windows/context_gl_win.cpp deleted file mode 100644 index 9d267c699f..0000000000 --- a/platform/windows/context_gl_win.cpp +++ /dev/null @@ -1,185 +0,0 @@ -/*************************************************************************/ -/* context_gl_win.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#if defined(OPENGL_ENABLED) || defined(GLES_ENABLED) - -// Author: Juan Linietsky , (C) 2008 - -#include "context_gl_win.h" - -#define WGL_CONTEXT_MAJOR_VERSION_ARB 0x2091 -#define WGL_CONTEXT_MINOR_VERSION_ARB 0x2092 -#define WGL_CONTEXT_FLAGS_ARB 0x2094 -#define WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x00000002 -#define WGL_CONTEXT_PROFILE_MASK_ARB 0x9126 -#define WGL_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001 - -typedef HGLRC(APIENTRY *PFNWGLCREATECONTEXTATTRIBSARBPROC)(HDC, HGLRC, const int *); - -void ContextGL_Win::release_current() { - - wglMakeCurrent(hDC, NULL); -} - -void ContextGL_Win::make_current() { - - wglMakeCurrent(hDC, hRC); -} - -int ContextGL_Win::get_window_width() { - - return OS::get_singleton()->get_video_mode().width; -} - -int ContextGL_Win::get_window_height() { - - return OS::get_singleton()->get_video_mode().height; -} - -void ContextGL_Win::swap_buffers() { - - SwapBuffers(hDC); -} - -void ContextGL_Win::set_use_vsync(bool p_use) { - - if (wglSwapIntervalEXT) { - wglSwapIntervalEXT(p_use ? 1 : 0); - } - use_vsync = p_use; -} - -bool ContextGL_Win::is_using_vsync() const { - - return use_vsync; -} - -#define _WGL_CONTEXT_DEBUG_BIT_ARB 0x0001 - -Error ContextGL_Win::initialize() { - - static PIXELFORMATDESCRIPTOR pfd = { - sizeof(PIXELFORMATDESCRIPTOR), // Size Of This Pixel Format Descriptor - 1, - PFD_DRAW_TO_WINDOW | // Format Must Support Window - PFD_SUPPORT_OPENGL | // Format Must Support OpenGL - PFD_DOUBLEBUFFER, - (BYTE)PFD_TYPE_RGBA, - (BYTE)(OS::get_singleton()->is_layered_allowed() ? 32 : 24), - (BYTE)0, (BYTE)0, (BYTE)0, (BYTE)0, (BYTE)0, (BYTE)0, // Color Bits Ignored - (BYTE)(OS::get_singleton()->is_layered_allowed() ? 8 : 0), // Alpha Buffer - (BYTE)0, // Shift Bit Ignored - (BYTE)0, // No Accumulation Buffer - (BYTE)0, (BYTE)0, (BYTE)0, (BYTE)0, // Accumulation Bits Ignored - (BYTE)24, // 24Bit Z-Buffer (Depth Buffer) - (BYTE)0, // No Stencil Buffer - (BYTE)0, // No Auxiliary Buffer - (BYTE)PFD_MAIN_PLANE, // Main Drawing Layer - (BYTE)0, // Reserved - 0, 0, 0 // Layer Masks Ignored - }; - - hDC = GetDC(hWnd); - if (!hDC) { - return ERR_CANT_CREATE; // Return FALSE - } - - pixel_format = ChoosePixelFormat(hDC, &pfd); - if (!pixel_format) // Did Windows Find A Matching Pixel Format? - { - return ERR_CANT_CREATE; // Return FALSE - } - - BOOL ret = SetPixelFormat(hDC, pixel_format, &pfd); - if (!ret) // Are We Able To Set The Pixel Format? - { - return ERR_CANT_CREATE; // Return FALSE - } - - hRC = wglCreateContext(hDC); - if (!hRC) // Are We Able To Get A Rendering Context? - { - return ERR_CANT_CREATE; // Return FALSE - } - - wglMakeCurrent(hDC, hRC); - - if (opengl_3_context) { - - int attribs[] = { - WGL_CONTEXT_MAJOR_VERSION_ARB, 3, //we want a 3.3 context - WGL_CONTEXT_MINOR_VERSION_ARB, 3, - //and it shall be forward compatible so that we can only use up to date functionality - WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_CORE_PROFILE_BIT_ARB, - WGL_CONTEXT_FLAGS_ARB, WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB /*| _WGL_CONTEXT_DEBUG_BIT_ARB*/, - 0 - }; //zero indicates the end of the array - - PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB = NULL; //pointer to the method - wglCreateContextAttribsARB = (PFNWGLCREATECONTEXTATTRIBSARBPROC)wglGetProcAddress("wglCreateContextAttribsARB"); - - if (wglCreateContextAttribsARB == NULL) //OpenGL 3.0 is not supported - { - wglDeleteContext(hRC); - return ERR_CANT_CREATE; - } - - HGLRC new_hRC = wglCreateContextAttribsARB(hDC, 0, attribs); - if (!new_hRC) { - wglDeleteContext(hRC); - return ERR_CANT_CREATE; // Return false - } - wglMakeCurrent(hDC, NULL); - wglDeleteContext(hRC); - hRC = new_hRC; - - if (!wglMakeCurrent(hDC, hRC)) // Try To Activate The Rendering Context - { - return ERR_CANT_CREATE; // Return FALSE - } - } - - wglSwapIntervalEXT = (PFNWGLSWAPINTERVALEXTPROC)wglGetProcAddress("wglSwapIntervalEXT"); - //glWrapperInit(wrapper_get_proc_address); - - return OK; -} - -ContextGL_Win::ContextGL_Win(HWND hwnd, bool p_opengl_3_context) { - - opengl_3_context = p_opengl_3_context; - hWnd = hwnd; - use_vsync = false; -} - -ContextGL_Win::~ContextGL_Win() { -} - -#endif diff --git a/platform/windows/context_gl_win.h b/platform/windows/context_gl_win.h deleted file mode 100644 index 3076bbb1e8..0000000000 --- a/platform/windows/context_gl_win.h +++ /dev/null @@ -1,76 +0,0 @@ -/*************************************************************************/ -/* context_gl_win.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#if defined(OPENGL_ENABLED) || defined(GLES_ENABLED) - -// Author: Juan Linietsky , (C) 2008 - -#ifndef CONTEXT_GL_WIN_H -#define CONTEXT_GL_WIN_H - -#include "core/error_list.h" -#include "core/os/os.h" -#include "drivers/gl_context/context_gl.h" - -#include - -typedef bool(APIENTRY *PFNWGLSWAPINTERVALEXTPROC)(int interval); - -class ContextGL_Win : public ContextGL { - - HDC hDC; - HGLRC hRC; - unsigned int pixel_format; - HWND hWnd; - bool opengl_3_context; - bool use_vsync; - - PFNWGLSWAPINTERVALEXTPROC wglSwapIntervalEXT; - -public: - virtual void release_current(); - - virtual void make_current(); - - virtual int get_window_width(); - virtual int get_window_height(); - virtual void swap_buffers(); - - virtual Error initialize(); - - virtual void set_use_vsync(bool p_use); - virtual bool is_using_vsync() const; - - ContextGL_Win(HWND hwnd, bool p_opengl_3_context); - virtual ~ContextGL_Win(); -}; - -#endif -#endif diff --git a/platform/windows/context_gl_windows.cpp b/platform/windows/context_gl_windows.cpp new file mode 100644 index 0000000000..e715999378 --- /dev/null +++ b/platform/windows/context_gl_windows.cpp @@ -0,0 +1,185 @@ +/*************************************************************************/ +/* context_gl_windows.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#if defined(OPENGL_ENABLED) || defined(GLES_ENABLED) + +// Author: Juan Linietsky , (C) 2008 + +#include "context_gl_windows.h" + +#define WGL_CONTEXT_MAJOR_VERSION_ARB 0x2091 +#define WGL_CONTEXT_MINOR_VERSION_ARB 0x2092 +#define WGL_CONTEXT_FLAGS_ARB 0x2094 +#define WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x00000002 +#define WGL_CONTEXT_PROFILE_MASK_ARB 0x9126 +#define WGL_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001 + +typedef HGLRC(APIENTRY *PFNWGLCREATECONTEXTATTRIBSARBPROC)(HDC, HGLRC, const int *); + +void ContextGL_Windows::release_current() { + + wglMakeCurrent(hDC, NULL); +} + +void ContextGL_Windows::make_current() { + + wglMakeCurrent(hDC, hRC); +} + +int ContextGL_Windows::get_window_width() { + + return OS::get_singleton()->get_video_mode().width; +} + +int ContextGL_Windows::get_window_height() { + + return OS::get_singleton()->get_video_mode().height; +} + +void ContextGL_Windows::swap_buffers() { + + SwapBuffers(hDC); +} + +void ContextGL_Windows::set_use_vsync(bool p_use) { + + if (wglSwapIntervalEXT) { + wglSwapIntervalEXT(p_use ? 1 : 0); + } + use_vsync = p_use; +} + +bool ContextGL_Windows::is_using_vsync() const { + + return use_vsync; +} + +#define _WGL_CONTEXT_DEBUG_BIT_ARB 0x0001 + +Error ContextGL_Windows::initialize() { + + static PIXELFORMATDESCRIPTOR pfd = { + sizeof(PIXELFORMATDESCRIPTOR), // Size Of This Pixel Format Descriptor + 1, + PFD_DRAW_TO_WINDOW | // Format Must Support Window + PFD_SUPPORT_OPENGL | // Format Must Support OpenGL + PFD_DOUBLEBUFFER, + (BYTE)PFD_TYPE_RGBA, + (BYTE)(OS::get_singleton()->is_layered_allowed() ? 32 : 24), + (BYTE)0, (BYTE)0, (BYTE)0, (BYTE)0, (BYTE)0, (BYTE)0, // Color Bits Ignored + (BYTE)(OS::get_singleton()->is_layered_allowed() ? 8 : 0), // Alpha Buffer + (BYTE)0, // Shift Bit Ignored + (BYTE)0, // No Accumulation Buffer + (BYTE)0, (BYTE)0, (BYTE)0, (BYTE)0, // Accumulation Bits Ignored + (BYTE)24, // 24Bit Z-Buffer (Depth Buffer) + (BYTE)0, // No Stencil Buffer + (BYTE)0, // No Auxiliary Buffer + (BYTE)PFD_MAIN_PLANE, // Main Drawing Layer + (BYTE)0, // Reserved + 0, 0, 0 // Layer Masks Ignored + }; + + hDC = GetDC(hWnd); + if (!hDC) { + return ERR_CANT_CREATE; // Return FALSE + } + + pixel_format = ChoosePixelFormat(hDC, &pfd); + if (!pixel_format) // Did Windows Find A Matching Pixel Format? + { + return ERR_CANT_CREATE; // Return FALSE + } + + BOOL ret = SetPixelFormat(hDC, pixel_format, &pfd); + if (!ret) // Are We Able To Set The Pixel Format? + { + return ERR_CANT_CREATE; // Return FALSE + } + + hRC = wglCreateContext(hDC); + if (!hRC) // Are We Able To Get A Rendering Context? + { + return ERR_CANT_CREATE; // Return FALSE + } + + wglMakeCurrent(hDC, hRC); + + if (opengl_3_context) { + + int attribs[] = { + WGL_CONTEXT_MAJOR_VERSION_ARB, 3, //we want a 3.3 context + WGL_CONTEXT_MINOR_VERSION_ARB, 3, + //and it shall be forward compatible so that we can only use up to date functionality + WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_CORE_PROFILE_BIT_ARB, + WGL_CONTEXT_FLAGS_ARB, WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB /*| _WGL_CONTEXT_DEBUG_BIT_ARB*/, + 0 + }; //zero indicates the end of the array + + PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB = NULL; //pointer to the method + wglCreateContextAttribsARB = (PFNWGLCREATECONTEXTATTRIBSARBPROC)wglGetProcAddress("wglCreateContextAttribsARB"); + + if (wglCreateContextAttribsARB == NULL) //OpenGL 3.0 is not supported + { + wglDeleteContext(hRC); + return ERR_CANT_CREATE; + } + + HGLRC new_hRC = wglCreateContextAttribsARB(hDC, 0, attribs); + if (!new_hRC) { + wglDeleteContext(hRC); + return ERR_CANT_CREATE; // Return false + } + wglMakeCurrent(hDC, NULL); + wglDeleteContext(hRC); + hRC = new_hRC; + + if (!wglMakeCurrent(hDC, hRC)) // Try To Activate The Rendering Context + { + return ERR_CANT_CREATE; // Return FALSE + } + } + + wglSwapIntervalEXT = (PFNWGLSWAPINTERVALEXTPROC)wglGetProcAddress("wglSwapIntervalEXT"); + //glWrapperInit(wrapper_get_proc_address); + + return OK; +} + +ContextGL_Windows::ContextGL_Windows(HWND hwnd, bool p_opengl_3_context) { + + opengl_3_context = p_opengl_3_context; + hWnd = hwnd; + use_vsync = false; +} + +ContextGL_Windows::~ContextGL_Windows() { +} + +#endif diff --git a/platform/windows/context_gl_windows.h b/platform/windows/context_gl_windows.h new file mode 100644 index 0000000000..09801b9146 --- /dev/null +++ b/platform/windows/context_gl_windows.h @@ -0,0 +1,76 @@ +/*************************************************************************/ +/* context_gl_windows.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#if defined(OPENGL_ENABLED) || defined(GLES_ENABLED) + +// Author: Juan Linietsky , (C) 2008 + +#ifndef CONTEXT_GL_WIN_H +#define CONTEXT_GL_WIN_H + +#include "core/error_list.h" +#include "core/os/os.h" +#include "drivers/gl_context/context_gl.h" + +#include + +typedef bool(APIENTRY *PFNWGLSWAPINTERVALEXTPROC)(int interval); + +class ContextGL_Windows : public ContextGL { + + HDC hDC; + HGLRC hRC; + unsigned int pixel_format; + HWND hWnd; + bool opengl_3_context; + bool use_vsync; + + PFNWGLSWAPINTERVALEXTPROC wglSwapIntervalEXT; + +public: + virtual void release_current(); + + virtual void make_current(); + + virtual int get_window_width(); + virtual int get_window_height(); + virtual void swap_buffers(); + + virtual Error initialize(); + + virtual void set_use_vsync(bool p_use); + virtual bool is_using_vsync() const; + + ContextGL_Windows(HWND hwnd, bool p_opengl_3_context); + virtual ~ContextGL_Windows(); +}; + +#endif +#endif diff --git a/platform/windows/crash_handler_win.cpp b/platform/windows/crash_handler_win.cpp deleted file mode 100644 index 1d93c6d8dd..0000000000 --- a/platform/windows/crash_handler_win.cpp +++ /dev/null @@ -1,216 +0,0 @@ -/*************************************************************************/ -/* crash_handler_win.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#include "core/project_settings.h" -#include "main/main.h" -#include "os_windows.h" - -#ifdef CRASH_HANDLER_EXCEPTION - -// Backtrace code code based on: https://stackoverflow.com/questions/6205981/windows-c-stack-trace-from-a-running-app - -#include -#include -#include - -#pragma comment(lib, "psapi.lib") -#pragma comment(lib, "dbghelp.lib") - -// Some versions of imagehlp.dll lack the proper packing directives themselves -// so we need to do it. -#pragma pack(push, before_imagehlp, 8) -#include -#pragma pack(pop, before_imagehlp) - -struct module_data { - std::string image_name; - std::string module_name; - void *base_address; - DWORD load_size; -}; - -class symbol { - typedef IMAGEHLP_SYMBOL64 sym_type; - sym_type *sym; - static const int max_name_len = 1024; - -public: - symbol(HANDLE process, DWORD64 address) : - sym((sym_type *)::operator new(sizeof(*sym) + max_name_len)) { - memset(sym, '\0', sizeof(*sym) + max_name_len); - sym->SizeOfStruct = sizeof(*sym); - sym->MaxNameLength = max_name_len; - DWORD64 displacement; - - SymGetSymFromAddr64(process, address, &displacement, sym); - } - - std::string name() { return std::string(sym->Name); } - std::string undecorated_name() { - if (*sym->Name == '\0') - return ""; - std::vector und_name(max_name_len); - UnDecorateSymbolName(sym->Name, &und_name[0], max_name_len, UNDNAME_COMPLETE); - return std::string(&und_name[0], strlen(&und_name[0])); - } -}; - -class get_mod_info { - HANDLE process; - -public: - get_mod_info(HANDLE h) : - process(h) {} - - module_data operator()(HMODULE module) { - module_data ret; - char temp[4096]; - MODULEINFO mi; - - GetModuleInformation(process, module, &mi, sizeof(mi)); - ret.base_address = mi.lpBaseOfDll; - ret.load_size = mi.SizeOfImage; - - GetModuleFileNameEx(process, module, temp, sizeof(temp)); - ret.image_name = temp; - GetModuleBaseName(process, module, temp, sizeof(temp)); - ret.module_name = temp; - std::vector img(ret.image_name.begin(), ret.image_name.end()); - std::vector mod(ret.module_name.begin(), ret.module_name.end()); - SymLoadModule64(process, 0, &img[0], &mod[0], (DWORD64)ret.base_address, ret.load_size); - return ret; - } -}; - -DWORD CrashHandlerException(EXCEPTION_POINTERS *ep) { - HANDLE process = GetCurrentProcess(); - HANDLE hThread = GetCurrentThread(); - DWORD offset_from_symbol = 0; - IMAGEHLP_LINE64 line = { 0 }; - std::vector modules; - DWORD cbNeeded; - std::vector module_handles(1); - - if (OS::get_singleton() == NULL || OS::get_singleton()->is_disable_crash_handler() || IsDebuggerPresent()) { - return EXCEPTION_CONTINUE_SEARCH; - } - - fprintf(stderr, "%s: Program crashed\n", __FUNCTION__); - - if (OS::get_singleton()->get_main_loop()) - OS::get_singleton()->get_main_loop()->notification(MainLoop::NOTIFICATION_CRASH); - - // Load the symbols: - if (!SymInitialize(process, NULL, false)) - return EXCEPTION_CONTINUE_SEARCH; - - SymSetOptions(SymGetOptions() | SYMOPT_LOAD_LINES | SYMOPT_UNDNAME); - EnumProcessModules(process, &module_handles[0], module_handles.size() * sizeof(HMODULE), &cbNeeded); - module_handles.resize(cbNeeded / sizeof(HMODULE)); - EnumProcessModules(process, &module_handles[0], module_handles.size() * sizeof(HMODULE), &cbNeeded); - std::transform(module_handles.begin(), module_handles.end(), std::back_inserter(modules), get_mod_info(process)); - void *base = modules[0].base_address; - - // Setup stuff: - CONTEXT *context = ep->ContextRecord; - STACKFRAME64 frame; - bool skip_first = false; - - frame.AddrPC.Mode = AddrModeFlat; - frame.AddrStack.Mode = AddrModeFlat; - frame.AddrFrame.Mode = AddrModeFlat; - -#ifdef _M_X64 - frame.AddrPC.Offset = context->Rip; - frame.AddrStack.Offset = context->Rsp; - frame.AddrFrame.Offset = context->Rbp; -#else - frame.AddrPC.Offset = context->Eip; - frame.AddrStack.Offset = context->Esp; - frame.AddrFrame.Offset = context->Ebp; - - // Skip the first one to avoid a duplicate on 32-bit mode - skip_first = true; -#endif - - line.SizeOfStruct = sizeof(line); - IMAGE_NT_HEADERS *h = ImageNtHeader(base); - DWORD image_type = h->FileHeader.Machine; - int n = 0; - String msg = GLOBAL_GET("debug/settings/crash_handler/message"); - - fprintf(stderr, "Dumping the backtrace. %ls\n", msg.c_str()); - - do { - if (skip_first) { - skip_first = false; - } else { - if (frame.AddrPC.Offset != 0) { - std::string fnName = symbol(process, frame.AddrPC.Offset).undecorated_name(); - - if (SymGetLineFromAddr64(process, frame.AddrPC.Offset, &offset_from_symbol, &line)) - fprintf(stderr, "[%d] %s (%s:%d)\n", n, fnName.c_str(), line.FileName, line.LineNumber); - else - fprintf(stderr, "[%d] %s\n", n, fnName.c_str()); - } else - fprintf(stderr, "[%d] ???\n", n); - - n++; - } - - if (!StackWalk64(image_type, process, hThread, &frame, context, NULL, SymFunctionTableAccess64, SymGetModuleBase64, NULL)) - break; - } while (frame.AddrReturn.Offset != 0 && n < 256); - - fprintf(stderr, "-- END OF BACKTRACE --\n"); - - SymCleanup(process); - - // Pass the exception to the OS - return EXCEPTION_CONTINUE_SEARCH; -} -#endif - -CrashHandler::CrashHandler() { - disabled = false; -} - -CrashHandler::~CrashHandler() { -} - -void CrashHandler::disable() { - if (disabled) - return; - - disabled = true; -} - -void CrashHandler::initialize() { -} diff --git a/platform/windows/crash_handler_win.h b/platform/windows/crash_handler_win.h deleted file mode 100644 index 016612a00e..0000000000 --- a/platform/windows/crash_handler_win.h +++ /dev/null @@ -1,57 +0,0 @@ -/*************************************************************************/ -/* crash_handler_win.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#ifndef CRASH_HANDLER_WIN_H -#define CRASH_HANDLER_WIN_H - -#include - -// Crash handler exception only enabled with MSVC -#if defined(DEBUG_ENABLED) && defined(MSVC) -#define CRASH_HANDLER_EXCEPTION 1 - -extern DWORD CrashHandlerException(EXCEPTION_POINTERS *ep); -#endif - -class CrashHandler { - - bool disabled; - -public: - void initialize(); - - void disable(); - bool is_disabled() const { return disabled; }; - - CrashHandler(); - ~CrashHandler(); -}; - -#endif diff --git a/platform/windows/crash_handler_windows.cpp b/platform/windows/crash_handler_windows.cpp new file mode 100644 index 0000000000..f93a449c7b --- /dev/null +++ b/platform/windows/crash_handler_windows.cpp @@ -0,0 +1,218 @@ +/*************************************************************************/ +/* crash_handler_windows.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "crash_handler_windows.h" + +#include "core/project_settings.h" +#include "main/main.h" +#include "os_windows.h" + +#ifdef CRASH_HANDLER_EXCEPTION + +// Backtrace code code based on: https://stackoverflow.com/questions/6205981/windows-c-stack-trace-from-a-running-app + +#include +#include +#include + +#pragma comment(lib, "psapi.lib") +#pragma comment(lib, "dbghelp.lib") + +// Some versions of imagehlp.dll lack the proper packing directives themselves +// so we need to do it. +#pragma pack(push, before_imagehlp, 8) +#include +#pragma pack(pop, before_imagehlp) + +struct module_data { + std::string image_name; + std::string module_name; + void *base_address; + DWORD load_size; +}; + +class symbol { + typedef IMAGEHLP_SYMBOL64 sym_type; + sym_type *sym; + static const int max_name_len = 1024; + +public: + symbol(HANDLE process, DWORD64 address) : + sym((sym_type *)::operator new(sizeof(*sym) + max_name_len)) { + memset(sym, '\0', sizeof(*sym) + max_name_len); + sym->SizeOfStruct = sizeof(*sym); + sym->MaxNameLength = max_name_len; + DWORD64 displacement; + + SymGetSymFromAddr64(process, address, &displacement, sym); + } + + std::string name() { return std::string(sym->Name); } + std::string undecorated_name() { + if (*sym->Name == '\0') + return ""; + std::vector und_name(max_name_len); + UnDecorateSymbolName(sym->Name, &und_name[0], max_name_len, UNDNAME_COMPLETE); + return std::string(&und_name[0], strlen(&und_name[0])); + } +}; + +class get_mod_info { + HANDLE process; + +public: + get_mod_info(HANDLE h) : + process(h) {} + + module_data operator()(HMODULE module) { + module_data ret; + char temp[4096]; + MODULEINFO mi; + + GetModuleInformation(process, module, &mi, sizeof(mi)); + ret.base_address = mi.lpBaseOfDll; + ret.load_size = mi.SizeOfImage; + + GetModuleFileNameEx(process, module, temp, sizeof(temp)); + ret.image_name = temp; + GetModuleBaseName(process, module, temp, sizeof(temp)); + ret.module_name = temp; + std::vector img(ret.image_name.begin(), ret.image_name.end()); + std::vector mod(ret.module_name.begin(), ret.module_name.end()); + SymLoadModule64(process, 0, &img[0], &mod[0], (DWORD64)ret.base_address, ret.load_size); + return ret; + } +}; + +DWORD CrashHandlerException(EXCEPTION_POINTERS *ep) { + HANDLE process = GetCurrentProcess(); + HANDLE hThread = GetCurrentThread(); + DWORD offset_from_symbol = 0; + IMAGEHLP_LINE64 line = { 0 }; + std::vector modules; + DWORD cbNeeded; + std::vector module_handles(1); + + if (OS::get_singleton() == NULL || OS::get_singleton()->is_disable_crash_handler() || IsDebuggerPresent()) { + return EXCEPTION_CONTINUE_SEARCH; + } + + fprintf(stderr, "%s: Program crashed\n", __FUNCTION__); + + if (OS::get_singleton()->get_main_loop()) + OS::get_singleton()->get_main_loop()->notification(MainLoop::NOTIFICATION_CRASH); + + // Load the symbols: + if (!SymInitialize(process, NULL, false)) + return EXCEPTION_CONTINUE_SEARCH; + + SymSetOptions(SymGetOptions() | SYMOPT_LOAD_LINES | SYMOPT_UNDNAME); + EnumProcessModules(process, &module_handles[0], module_handles.size() * sizeof(HMODULE), &cbNeeded); + module_handles.resize(cbNeeded / sizeof(HMODULE)); + EnumProcessModules(process, &module_handles[0], module_handles.size() * sizeof(HMODULE), &cbNeeded); + std::transform(module_handles.begin(), module_handles.end(), std::back_inserter(modules), get_mod_info(process)); + void *base = modules[0].base_address; + + // Setup stuff: + CONTEXT *context = ep->ContextRecord; + STACKFRAME64 frame; + bool skip_first = false; + + frame.AddrPC.Mode = AddrModeFlat; + frame.AddrStack.Mode = AddrModeFlat; + frame.AddrFrame.Mode = AddrModeFlat; + +#ifdef _M_X64 + frame.AddrPC.Offset = context->Rip; + frame.AddrStack.Offset = context->Rsp; + frame.AddrFrame.Offset = context->Rbp; +#else + frame.AddrPC.Offset = context->Eip; + frame.AddrStack.Offset = context->Esp; + frame.AddrFrame.Offset = context->Ebp; + + // Skip the first one to avoid a duplicate on 32-bit mode + skip_first = true; +#endif + + line.SizeOfStruct = sizeof(line); + IMAGE_NT_HEADERS *h = ImageNtHeader(base); + DWORD image_type = h->FileHeader.Machine; + int n = 0; + String msg = GLOBAL_GET("debug/settings/crash_handler/message"); + + fprintf(stderr, "Dumping the backtrace. %ls\n", msg.c_str()); + + do { + if (skip_first) { + skip_first = false; + } else { + if (frame.AddrPC.Offset != 0) { + std::string fnName = symbol(process, frame.AddrPC.Offset).undecorated_name(); + + if (SymGetLineFromAddr64(process, frame.AddrPC.Offset, &offset_from_symbol, &line)) + fprintf(stderr, "[%d] %s (%s:%d)\n", n, fnName.c_str(), line.FileName, line.LineNumber); + else + fprintf(stderr, "[%d] %s\n", n, fnName.c_str()); + } else + fprintf(stderr, "[%d] ???\n", n); + + n++; + } + + if (!StackWalk64(image_type, process, hThread, &frame, context, NULL, SymFunctionTableAccess64, SymGetModuleBase64, NULL)) + break; + } while (frame.AddrReturn.Offset != 0 && n < 256); + + fprintf(stderr, "-- END OF BACKTRACE --\n"); + + SymCleanup(process); + + // Pass the exception to the OS + return EXCEPTION_CONTINUE_SEARCH; +} +#endif + +CrashHandler::CrashHandler() { + disabled = false; +} + +CrashHandler::~CrashHandler() { +} + +void CrashHandler::disable() { + if (disabled) + return; + + disabled = true; +} + +void CrashHandler::initialize() { +} diff --git a/platform/windows/crash_handler_windows.h b/platform/windows/crash_handler_windows.h new file mode 100644 index 0000000000..eba72beb7e --- /dev/null +++ b/platform/windows/crash_handler_windows.h @@ -0,0 +1,57 @@ +/*************************************************************************/ +/* crash_handler_windows.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef CRASH_HANDLER_WINDOWS_H +#define CRASH_HANDLER_WINDOWS_H + +#include + +// Crash handler exception only enabled with MSVC +#if defined(DEBUG_ENABLED) && defined(MSVC) +#define CRASH_HANDLER_EXCEPTION 1 + +extern DWORD CrashHandlerException(EXCEPTION_POINTERS *ep); +#endif + +class CrashHandler { + + bool disabled; + +public: + void initialize(); + + void disable(); + bool is_disabled() const { return disabled; }; + + CrashHandler(); + ~CrashHandler(); +}; + +#endif // CRASH_HANDLER_WINDOWS_H diff --git a/platform/windows/ctxgl_procaddr.cpp b/platform/windows/ctxgl_procaddr.cpp deleted file mode 100644 index ecff8f7a4d..0000000000 --- a/platform/windows/ctxgl_procaddr.cpp +++ /dev/null @@ -1,188 +0,0 @@ -/*************************************************************************/ -/* ctxgl_procaddr.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#ifdef OPENGL_ENABLED -#include "ctxgl_procaddr.h" -#include -#include - -static PROC _gl_procs[] = { - (PROC)glCullFace, - (PROC)glFrontFace, - (PROC)glHint, - (PROC)glLineWidth, - (PROC)glPointSize, - (PROC)glPolygonMode, - (PROC)glScissor, - (PROC)glTexParameterf, - (PROC)glTexParameterfv, - (PROC)glTexParameteri, - (PROC)glTexParameteriv, - (PROC)glTexImage1D, - (PROC)glTexImage2D, - (PROC)glDrawBuffer, - (PROC)glClear, - (PROC)glClearColor, - (PROC)glClearStencil, - (PROC)glClearDepth, - (PROC)glStencilMask, - (PROC)glColorMask, - (PROC)glDepthMask, - (PROC)glDisable, - (PROC)glEnable, - (PROC)glFinish, - (PROC)glFlush, - (PROC)glBlendFunc, - (PROC)glLogicOp, - (PROC)glStencilFunc, - (PROC)glStencilOp, - (PROC)glDepthFunc, - (PROC)glPixelStoref, - (PROC)glPixelStorei, - (PROC)glReadBuffer, - (PROC)glReadPixels, - (PROC)glGetBooleanv, - (PROC)glGetDoublev, - (PROC)glGetError, - (PROC)glGetFloatv, - (PROC)glGetIntegerv, - (PROC)glGetString, - (PROC)glGetTexImage, - (PROC)glGetTexParameterfv, - (PROC)glGetTexParameteriv, - (PROC)glGetTexLevelParameterfv, - (PROC)glGetTexLevelParameteriv, - (PROC)glIsEnabled, - (PROC)glDepthRange, - (PROC)glViewport, - /* not detected in ATI */ - (PROC)glDrawArrays, - (PROC)glDrawElements, - (PROC)glGetPointerv, - (PROC)glPolygonOffset, - (PROC)glCopyTexImage1D, - (PROC)glCopyTexImage2D, - (PROC)glCopyTexSubImage1D, - (PROC)glCopyTexSubImage2D, - (PROC)glTexSubImage1D, - (PROC)glTexSubImage2D, - (PROC)glBindTexture, - (PROC)glDeleteTextures, - (PROC)glGenTextures, - (PROC)glIsTexture, - - 0 -}; - -static const char *_gl_proc_names[] = { - "glCullFace", - "glFrontFace", - "glHint", - "glLineWidth", - "glPointSize", - "glPolygonMode", - "glScissor", - "glTexParameterf", - "glTexParameterfv", - "glTexParameteri", - "glTexParameteriv", - "glTexImage1D", - "glTexImage2D", - "glDrawBuffer", - "glClear", - "glClearColor", - "glClearStencil", - "glClearDepth", - "glStencilMask", - "glColorMask", - "glDepthMask", - "glDisable", - "glEnable", - "glFinish", - "glFlush", - "glBlendFunc", - "glLogicOp", - "glStencilFunc", - "glStencilOp", - "glDepthFunc", - "glPixelStoref", - "glPixelStorei", - "glReadBuffer", - "glReadPixels", - "glGetBooleanv", - "glGetDoublev", - "glGetError", - "glGetFloatv", - "glGetIntegerv", - "glGetString", - "glGetTexImage", - "glGetTexParameterfv", - "glGetTexParameteriv", - "glGetTexLevelParameterfv", - "glGetTexLevelParameteriv", - "glIsEnabled", - "glDepthRange", - "glViewport", - /* not detected in ati */ - "glDrawArrays", - "glDrawElements", - "glGetPointerv", - "glPolygonOffset", - "glCopyTexImage1D", - "glCopyTexImage2D", - "glCopyTexSubImage1D", - "glCopyTexSubImage2D", - "glTexSubImage1D", - "glTexSubImage2D", - "glBindTexture", - "glDeleteTextures", - "glGenTextures", - "glIsTexture", - - 0 -}; - -PROC get_gl_proc_address(const char *p_address) { - - PROC proc = wglGetProcAddress((const CHAR *)p_address); - if (!proc) { - - int i = 0; - while (_gl_procs[i]) { - - if (strcmp(p_address, _gl_proc_names[i]) == 0) { - return _gl_procs[i]; - } - i++; - } - } - return proc; -} -#endif diff --git a/platform/windows/ctxgl_procaddr.h b/platform/windows/ctxgl_procaddr.h deleted file mode 100644 index cc40804ae6..0000000000 --- a/platform/windows/ctxgl_procaddr.h +++ /dev/null @@ -1,39 +0,0 @@ -/*************************************************************************/ -/* ctxgl_procaddr.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#ifndef CTXGL_PROCADDR_H -#define CTXGL_PROCADDR_H - -#ifdef OPENGL_ENABLED -#include - -PROC get_gl_proc_address(const char *p_address); -#endif -#endif // CTXGL_PROCADDR_H diff --git a/platform/windows/godot_win.cpp b/platform/windows/godot_win.cpp deleted file mode 100644 index 0f5065d816..0000000000 --- a/platform/windows/godot_win.cpp +++ /dev/null @@ -1,198 +0,0 @@ -/*************************************************************************/ -/* godot_win.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#include "main/main.h" -#include "os_windows.h" -#include -#include - -PCHAR * -CommandLineToArgvA( - PCHAR CmdLine, - int *_argc) { - PCHAR *argv; - PCHAR _argv; - ULONG len; - ULONG argc; - CHAR a; - ULONG i, j; - - BOOLEAN in_QM; - BOOLEAN in_TEXT; - BOOLEAN in_SPACE; - - len = strlen(CmdLine); - i = ((len + 2) / 2) * sizeof(PVOID) + sizeof(PVOID); - - argv = (PCHAR *)GlobalAlloc(GMEM_FIXED, - i + (len + 2) * sizeof(CHAR)); - - _argv = (PCHAR)(((PUCHAR)argv) + i); - - argc = 0; - argv[argc] = _argv; - in_QM = FALSE; - in_TEXT = FALSE; - in_SPACE = TRUE; - i = 0; - j = 0; - - while ((a = CmdLine[i])) { - if (in_QM) { - if (a == '\"') { - in_QM = FALSE; - } else { - _argv[j] = a; - j++; - } - } else { - switch (a) { - case '\"': - in_QM = TRUE; - in_TEXT = TRUE; - if (in_SPACE) { - argv[argc] = _argv + j; - argc++; - } - in_SPACE = FALSE; - break; - case ' ': - case '\t': - case '\n': - case '\r': - if (in_TEXT) { - _argv[j] = '\0'; - j++; - } - in_TEXT = FALSE; - in_SPACE = TRUE; - break; - default: - in_TEXT = TRUE; - if (in_SPACE) { - argv[argc] = _argv + j; - argc++; - } - _argv[j] = a; - j++; - in_SPACE = FALSE; - break; - } - } - i++; - } - _argv[j] = '\0'; - argv[argc] = NULL; - - (*_argc) = argc; - return argv; -} - -char *wc_to_utf8(const wchar_t *wc) { - int ulen = WideCharToMultiByte(CP_UTF8, 0, wc, -1, NULL, 0, NULL, NULL); - char *ubuf = new char[ulen + 1]; - WideCharToMultiByte(CP_UTF8, 0, wc, -1, ubuf, ulen, NULL, NULL); - ubuf[ulen] = 0; - return ubuf; -} - -int widechar_main(int argc, wchar_t **argv) { - - OS_Windows os(NULL); - - setlocale(LC_CTYPE, ""); - - char **argv_utf8 = new char *[argc]; - - for (int i = 0; i < argc; ++i) { - argv_utf8[i] = wc_to_utf8(argv[i]); - } - - Error err = Main::setup(argv_utf8[0], argc - 1, &argv_utf8[1]); - - if (err != OK) { - for (int i = 0; i < argc; ++i) { - delete[] argv_utf8[i]; - } - delete[] argv_utf8; - return 255; - } - - if (Main::start()) - os.run(); - Main::cleanup(); - - for (int i = 0; i < argc; ++i) { - delete[] argv_utf8[i]; - } - delete[] argv_utf8; - - return os.get_exit_code(); -}; - -int _main() { - LPWSTR *wc_argv; - int argc; - int result; - - wc_argv = CommandLineToArgvW(GetCommandLineW(), &argc); - - if (NULL == wc_argv) { - wprintf(L"CommandLineToArgvW failed\n"); - return 0; - } - - result = widechar_main(argc, wc_argv); - - LocalFree(wc_argv); - return result; -} - -int main(int _argc, char **_argv) { - // _argc and _argv are ignored - // we are going to use the WideChar version of them instead - -#ifdef CRASH_HANDLER_EXCEPTION - __try { - return _main(); - } __except (CrashHandlerException(GetExceptionInformation())) { - return 1; - } -#else - return _main(); -#endif -} - -HINSTANCE godot_hinstance = NULL; - -int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { - godot_hinstance = hInstance; - return main(0, NULL); -} diff --git a/platform/windows/godot_windows.cpp b/platform/windows/godot_windows.cpp new file mode 100644 index 0000000000..0b52682c7c --- /dev/null +++ b/platform/windows/godot_windows.cpp @@ -0,0 +1,199 @@ +/*************************************************************************/ +/* godot_windows.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "main/main.h" +#include "os_windows.h" + +#include +#include + +PCHAR * +CommandLineToArgvA( + PCHAR CmdLine, + int *_argc) { + PCHAR *argv; + PCHAR _argv; + ULONG len; + ULONG argc; + CHAR a; + ULONG i, j; + + BOOLEAN in_QM; + BOOLEAN in_TEXT; + BOOLEAN in_SPACE; + + len = strlen(CmdLine); + i = ((len + 2) / 2) * sizeof(PVOID) + sizeof(PVOID); + + argv = (PCHAR *)GlobalAlloc(GMEM_FIXED, + i + (len + 2) * sizeof(CHAR)); + + _argv = (PCHAR)(((PUCHAR)argv) + i); + + argc = 0; + argv[argc] = _argv; + in_QM = FALSE; + in_TEXT = FALSE; + in_SPACE = TRUE; + i = 0; + j = 0; + + while ((a = CmdLine[i])) { + if (in_QM) { + if (a == '\"') { + in_QM = FALSE; + } else { + _argv[j] = a; + j++; + } + } else { + switch (a) { + case '\"': + in_QM = TRUE; + in_TEXT = TRUE; + if (in_SPACE) { + argv[argc] = _argv + j; + argc++; + } + in_SPACE = FALSE; + break; + case ' ': + case '\t': + case '\n': + case '\r': + if (in_TEXT) { + _argv[j] = '\0'; + j++; + } + in_TEXT = FALSE; + in_SPACE = TRUE; + break; + default: + in_TEXT = TRUE; + if (in_SPACE) { + argv[argc] = _argv + j; + argc++; + } + _argv[j] = a; + j++; + in_SPACE = FALSE; + break; + } + } + i++; + } + _argv[j] = '\0'; + argv[argc] = NULL; + + (*_argc) = argc; + return argv; +} + +char *wc_to_utf8(const wchar_t *wc) { + int ulen = WideCharToMultiByte(CP_UTF8, 0, wc, -1, NULL, 0, NULL, NULL); + char *ubuf = new char[ulen + 1]; + WideCharToMultiByte(CP_UTF8, 0, wc, -1, ubuf, ulen, NULL, NULL); + ubuf[ulen] = 0; + return ubuf; +} + +int widechar_main(int argc, wchar_t **argv) { + + OS_Windows os(NULL); + + setlocale(LC_CTYPE, ""); + + char **argv_utf8 = new char *[argc]; + + for (int i = 0; i < argc; ++i) { + argv_utf8[i] = wc_to_utf8(argv[i]); + } + + Error err = Main::setup(argv_utf8[0], argc - 1, &argv_utf8[1]); + + if (err != OK) { + for (int i = 0; i < argc; ++i) { + delete[] argv_utf8[i]; + } + delete[] argv_utf8; + return 255; + } + + if (Main::start()) + os.run(); + Main::cleanup(); + + for (int i = 0; i < argc; ++i) { + delete[] argv_utf8[i]; + } + delete[] argv_utf8; + + return os.get_exit_code(); +}; + +int _main() { + LPWSTR *wc_argv; + int argc; + int result; + + wc_argv = CommandLineToArgvW(GetCommandLineW(), &argc); + + if (NULL == wc_argv) { + wprintf(L"CommandLineToArgvW failed\n"); + return 0; + } + + result = widechar_main(argc, wc_argv); + + LocalFree(wc_argv); + return result; +} + +int main(int _argc, char **_argv) { + // _argc and _argv are ignored + // we are going to use the WideChar version of them instead + +#ifdef CRASH_HANDLER_EXCEPTION + __try { + return _main(); + } __except (CrashHandlerException(GetExceptionInformation())) { + return 1; + } +#else + return _main(); +#endif +} + +HINSTANCE godot_hinstance = NULL; + +int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { + godot_hinstance = hInstance; + return main(0, NULL); +} diff --git a/platform/windows/joypad.cpp b/platform/windows/joypad.cpp deleted file mode 100644 index 5fafc7c8c0..0000000000 --- a/platform/windows/joypad.cpp +++ /dev/null @@ -1,558 +0,0 @@ -/*************************************************************************/ -/* joypad.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#include "joypad.h" - -#include -#include - -#ifndef __GNUC__ -#define __builtin_bswap32 _byteswap_ulong -#endif - -DWORD WINAPI _xinput_get_state(DWORD dwUserIndex, XINPUT_STATE *pState) { - return ERROR_DEVICE_NOT_CONNECTED; -} -DWORD WINAPI _xinput_set_state(DWORD dwUserIndex, XINPUT_VIBRATION *pVibration) { - return ERROR_DEVICE_NOT_CONNECTED; -} - -JoypadWindows::JoypadWindows() { -} - -JoypadWindows::JoypadWindows(InputDefault *_input, HWND *hwnd) { - - input = _input; - hWnd = hwnd; - joypad_count = 0; - dinput = NULL; - xinput_dll = NULL; - xinput_get_state = NULL; - xinput_set_state = NULL; - - load_xinput(); - - for (int i = 0; i < JOYPADS_MAX; i++) - attached_joypads[i] = false; - - HRESULT result; - result = DirectInput8Create(GetModuleHandle(NULL), DIRECTINPUT_VERSION, IID_IDirectInput8, (void **)&dinput, NULL); - if (FAILED(result)) { - printf("failed init DINPUT: %ld\n", result); - } - probe_joypads(); -} - -JoypadWindows::~JoypadWindows() { - - close_joypad(); - dinput->Release(); - unload_xinput(); -} - -bool JoypadWindows::have_device(const GUID &p_guid) { - - for (int i = 0; i < JOYPADS_MAX; i++) { - - if (d_joypads[i].guid == p_guid) { - - d_joypads[i].confirmed = true; - return true; - } - } - return false; -} - -// adapted from SDL2, works a lot better than the MSDN version -bool JoypadWindows::is_xinput_device(const GUID *p_guid) { - - static GUID IID_ValveStreamingGamepad = { MAKELONG(0x28DE, 0x11FF), 0x0000, 0x0000, { 0x00, 0x00, 0x50, 0x49, 0x44, 0x56, 0x49, 0x44 } }; - static GUID IID_X360WiredGamepad = { MAKELONG(0x045E, 0x02A1), 0x0000, 0x0000, { 0x00, 0x00, 0x50, 0x49, 0x44, 0x56, 0x49, 0x44 } }; - static GUID IID_X360WirelessGamepad = { MAKELONG(0x045E, 0x028E), 0x0000, 0x0000, { 0x00, 0x00, 0x50, 0x49, 0x44, 0x56, 0x49, 0x44 } }; - - if (p_guid == &IID_ValveStreamingGamepad || p_guid == &IID_X360WiredGamepad || p_guid == &IID_X360WirelessGamepad) - return true; - - PRAWINPUTDEVICELIST dev_list = NULL; - unsigned int dev_list_count = 0; - - if (GetRawInputDeviceList(NULL, &dev_list_count, sizeof(RAWINPUTDEVICELIST)) == -1) { - return false; - } - dev_list = (PRAWINPUTDEVICELIST)malloc(sizeof(RAWINPUTDEVICELIST) * dev_list_count); - if (!dev_list) return false; - - if (GetRawInputDeviceList(dev_list, &dev_list_count, sizeof(RAWINPUTDEVICELIST)) == -1) { - free(dev_list); - return false; - } - for (int i = 0; i < dev_list_count; i++) { - - RID_DEVICE_INFO rdi; - char dev_name[128]; - UINT rdiSize = sizeof(rdi); - UINT nameSize = sizeof(dev_name); - - rdi.cbSize = rdiSize; - if ((dev_list[i].dwType == RIM_TYPEHID) && - (GetRawInputDeviceInfoA(dev_list[i].hDevice, RIDI_DEVICEINFO, &rdi, &rdiSize) != (UINT)-1) && - (MAKELONG(rdi.hid.dwVendorId, rdi.hid.dwProductId) == (LONG)p_guid->Data1) && - (GetRawInputDeviceInfoA(dev_list[i].hDevice, RIDI_DEVICENAME, &dev_name, &nameSize) != (UINT)-1) && - (strstr(dev_name, "IG_") != NULL)) { - - free(dev_list); - return true; - } - } - free(dev_list); - return false; -} - -bool JoypadWindows::setup_dinput_joypad(const DIDEVICEINSTANCE *instance) { - - HRESULT hr; - int num = input->get_unused_joy_id(); - - if (have_device(instance->guidInstance) || num == -1) - return false; - - d_joypads[joypad_count] = dinput_gamepad(); - dinput_gamepad *joy = &d_joypads[joypad_count]; - - const DWORD devtype = (instance->dwDevType & 0xFF); - - if ((devtype != DI8DEVTYPE_JOYSTICK) && (devtype != DI8DEVTYPE_GAMEPAD) && (devtype != DI8DEVTYPE_1STPERSON)) { - return false; - } - - hr = dinput->CreateDevice(instance->guidInstance, &joy->di_joy, NULL); - - if (FAILED(hr)) { - return false; - } - - const GUID &guid = instance->guidProduct; - char uid[128]; - sprintf_s(uid, "%08lx%04hx%04hx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx", - __builtin_bswap32(guid.Data1), guid.Data2, guid.Data3, - guid.Data4[0], guid.Data4[1], guid.Data4[2], guid.Data4[3], - guid.Data4[4], guid.Data4[5], guid.Data4[6], guid.Data4[7]); - - id_to_change = joypad_count; - - joy->di_joy->SetDataFormat(&c_dfDIJoystick2); - joy->di_joy->SetCooperativeLevel(*hWnd, DISCL_FOREGROUND); - joy->di_joy->EnumObjects(objectsCallback, this, 0); - joy->joy_axis.sort(); - - joy->guid = instance->guidInstance; - input->joy_connection_changed(num, true, instance->tszProductName, uid); - joy->attached = true; - joy->id = num; - attached_joypads[num] = true; - joy->confirmed = true; - joypad_count++; - return true; -} - -void JoypadWindows::setup_joypad_object(const DIDEVICEOBJECTINSTANCE *ob, int p_joy_id) { - - if (ob->dwType & DIDFT_AXIS) { - - HRESULT res; - DIPROPRANGE prop_range; - DIPROPDWORD dilong; - DWORD ofs; - if (ob->guidType == GUID_XAxis) - ofs = DIJOFS_X; - else if (ob->guidType == GUID_YAxis) - ofs = DIJOFS_Y; - else if (ob->guidType == GUID_ZAxis) - ofs = DIJOFS_Z; - else if (ob->guidType == GUID_RxAxis) - ofs = DIJOFS_RX; - else if (ob->guidType == GUID_RyAxis) - ofs = DIJOFS_RY; - else if (ob->guidType == GUID_RzAxis) - ofs = DIJOFS_RZ; - else if (ob->guidType == GUID_Slider) - ofs = DIJOFS_SLIDER(0); - else - return; - prop_range.diph.dwSize = sizeof(DIPROPRANGE); - prop_range.diph.dwHeaderSize = sizeof(DIPROPHEADER); - prop_range.diph.dwObj = ob->dwType; - prop_range.diph.dwHow = DIPH_BYID; - prop_range.lMin = -MAX_JOY_AXIS; - prop_range.lMax = +MAX_JOY_AXIS; - - dinput_gamepad &joy = d_joypads[p_joy_id]; - - res = IDirectInputDevice8_SetProperty(joy.di_joy, DIPROP_RANGE, &prop_range.diph); - if (FAILED(res)) - return; - - dilong.diph.dwSize = sizeof(dilong); - dilong.diph.dwHeaderSize = sizeof(dilong.diph); - dilong.diph.dwObj = ob->dwType; - dilong.diph.dwHow = DIPH_BYID; - dilong.dwData = 0; - - res = IDirectInputDevice8_SetProperty(joy.di_joy, DIPROP_DEADZONE, &dilong.diph); - if (FAILED(res)) - return; - - joy.joy_axis.push_back(ofs); - } -} - -BOOL CALLBACK JoypadWindows::enumCallback(const DIDEVICEINSTANCE *p_instance, void *p_context) { - - JoypadWindows *self = (JoypadWindows *)p_context; - if (self->is_xinput_device(&p_instance->guidProduct)) { - return DIENUM_CONTINUE; - } - self->setup_dinput_joypad(p_instance); - return DIENUM_CONTINUE; -} - -BOOL CALLBACK JoypadWindows::objectsCallback(const DIDEVICEOBJECTINSTANCE *instance, void *context) { - - JoypadWindows *self = (JoypadWindows *)context; - self->setup_joypad_object(instance, self->id_to_change); - - return DIENUM_CONTINUE; -} - -void JoypadWindows::close_joypad(int id) { - - if (id == -1) { - - for (int i = 0; i < JOYPADS_MAX; i++) { - - close_joypad(i); - } - return; - } - - if (!d_joypads[id].attached) return; - - d_joypads[id].di_joy->Unacquire(); - d_joypads[id].di_joy->Release(); - d_joypads[id].attached = false; - attached_joypads[d_joypads[id].id] = false; - d_joypads[id].guid.Data1 = d_joypads[id].guid.Data2 = d_joypads[id].guid.Data3 = 0; - input->joy_connection_changed(d_joypads[id].id, false, ""); - joypad_count--; -} - -void JoypadWindows::probe_joypads() { - - DWORD dwResult; - for (DWORD i = 0; i < XUSER_MAX_COUNT; i++) { - - ZeroMemory(&x_joypads[i].state, sizeof(XINPUT_STATE)); - - dwResult = xinput_get_state(i, &x_joypads[i].state); - if (dwResult == ERROR_SUCCESS) { - - int id = input->get_unused_joy_id(); - if (id != -1 && !x_joypads[i].attached) { - - x_joypads[i].attached = true; - x_joypads[i].id = id; - x_joypads[i].ff_timestamp = 0; - x_joypads[i].ff_end_timestamp = 0; - x_joypads[i].vibrating = false; - attached_joypads[id] = true; - input->joy_connection_changed(id, true, "XInput Gamepad", "__XINPUT_DEVICE__"); - } - } else if (x_joypads[i].attached) { - - x_joypads[i].attached = false; - attached_joypads[x_joypads[i].id] = false; - input->joy_connection_changed(x_joypads[i].id, false, ""); - } - } - - for (int i = 0; i < joypad_count; i++) { - - d_joypads[i].confirmed = false; - } - - dinput->EnumDevices(DI8DEVCLASS_GAMECTRL, enumCallback, this, DIEDFL_ATTACHEDONLY); - - for (int i = 0; i < joypad_count; i++) { - - if (!d_joypads[i].confirmed) { - - close_joypad(i); - } - } -} - -void JoypadWindows::process_joypads() { - - HRESULT hr; - - for (int i = 0; i < XUSER_MAX_COUNT; i++) { - - xinput_gamepad &joy = x_joypads[i]; - if (!joy.attached) { - continue; - } - ZeroMemory(&joy.state, sizeof(XINPUT_STATE)); - - xinput_get_state(i, &joy.state); - if (joy.state.dwPacketNumber != joy.last_packet) { - - int button_mask = XINPUT_GAMEPAD_DPAD_UP; - for (int i = 0; i <= 16; i++) { - - input->joy_button(joy.id, i, joy.state.Gamepad.wButtons & button_mask); - button_mask = button_mask * 2; - } - - input->joy_axis(joy.id, JOY_AXIS_0, axis_correct(joy.state.Gamepad.sThumbLX, true)); - input->joy_axis(joy.id, JOY_AXIS_1, axis_correct(joy.state.Gamepad.sThumbLY, true, false, true)); - input->joy_axis(joy.id, JOY_AXIS_2, axis_correct(joy.state.Gamepad.sThumbRX, true)); - input->joy_axis(joy.id, JOY_AXIS_3, axis_correct(joy.state.Gamepad.sThumbRY, true, false, true)); - input->joy_axis(joy.id, JOY_AXIS_4, axis_correct(joy.state.Gamepad.bLeftTrigger, true, true)); - input->joy_axis(joy.id, JOY_AXIS_5, axis_correct(joy.state.Gamepad.bRightTrigger, true, true)); - joy.last_packet = joy.state.dwPacketNumber; - } - uint64_t timestamp = input->get_joy_vibration_timestamp(joy.id); - if (timestamp > joy.ff_timestamp) { - Vector2 strength = input->get_joy_vibration_strength(joy.id); - float duration = input->get_joy_vibration_duration(joy.id); - if (strength.x == 0 && strength.y == 0) { - joypad_vibration_stop_xinput(i, timestamp); - } else { - joypad_vibration_start_xinput(i, strength.x, strength.y, duration, timestamp); - } - } else if (joy.vibrating && joy.ff_end_timestamp != 0) { - uint64_t current_time = OS::get_singleton()->get_ticks_usec(); - if (current_time >= joy.ff_end_timestamp) - joypad_vibration_stop_xinput(i, current_time); - } - } - - for (int i = 0; i < JOYPADS_MAX; i++) { - - dinput_gamepad *joy = &d_joypads[i]; - - if (!joy->attached) - continue; - - DIJOYSTATE2 js; - hr = joy->di_joy->Poll(); - if (hr == DIERR_INPUTLOST || hr == DIERR_NOTACQUIRED) { - IDirectInputDevice8_Acquire(joy->di_joy); - joy->di_joy->Poll(); - } - - hr = joy->di_joy->GetDeviceState(sizeof(DIJOYSTATE2), &js); - if (FAILED(hr)) { - continue; - } - - post_hat(joy->id, js.rgdwPOV[0]); - - for (int j = 0; j < 128; j++) { - - if (js.rgbButtons[j] & 0x80) { - - if (!joy->last_buttons[j]) { - - input->joy_button(joy->id, j, true); - joy->last_buttons[j] = true; - } - } else { - - if (joy->last_buttons[j]) { - - input->joy_button(joy->id, j, false); - joy->last_buttons[j] = false; - } - } - } - - // on mingw, these constants are not constants - int count = 6; - int axes[] = { DIJOFS_X, DIJOFS_Y, DIJOFS_Z, DIJOFS_RX, DIJOFS_RY, DIJOFS_RZ }; - int values[] = { js.lX, js.lY, js.lZ, js.lRx, js.lRy, js.lRz }; - - for (int j = 0; j < joy->joy_axis.size(); j++) { - - for (int k = 0; k < count; k++) { - if (joy->joy_axis[j] == axes[k]) { - input->joy_axis(joy->id, j, axis_correct(values[k])); - break; - }; - }; - }; - } - return; -} - -void JoypadWindows::post_hat(int p_device, DWORD p_dpad) { - - int dpad_val = 0; - - if (p_dpad == -1) { - dpad_val = InputDefault::HAT_MASK_CENTER; - } - if (p_dpad == 0) { - - dpad_val = InputDefault::HAT_MASK_UP; - - } else if (p_dpad == 4500) { - - dpad_val = (InputDefault::HAT_MASK_UP | InputDefault::HAT_MASK_RIGHT); - - } else if (p_dpad == 9000) { - - dpad_val = InputDefault::HAT_MASK_RIGHT; - - } else if (p_dpad == 13500) { - - dpad_val = (InputDefault::HAT_MASK_RIGHT | InputDefault::HAT_MASK_DOWN); - - } else if (p_dpad == 18000) { - - dpad_val = InputDefault::HAT_MASK_DOWN; - - } else if (p_dpad == 22500) { - - dpad_val = (InputDefault::HAT_MASK_DOWN | InputDefault::HAT_MASK_LEFT); - - } else if (p_dpad == 27000) { - - dpad_val = InputDefault::HAT_MASK_LEFT; - - } else if (p_dpad == 31500) { - - dpad_val = (InputDefault::HAT_MASK_LEFT | InputDefault::HAT_MASK_UP); - } - input->joy_hat(p_device, dpad_val); -}; - -InputDefault::JoyAxis JoypadWindows::axis_correct(int p_val, bool p_xinput, bool p_trigger, bool p_negate) const { - - InputDefault::JoyAxis jx; - if (Math::abs(p_val) < MIN_JOY_AXIS) { - jx.min = p_trigger ? 0 : -1; - jx.value = 0.0f; - return jx; - } - if (p_xinput) { - - if (p_trigger) { - jx.min = 0; - jx.value = (float)p_val / MAX_TRIGGER; - return jx; - } - jx.min = -1; - if (p_val < 0) { - jx.value = (float)p_val / MAX_JOY_AXIS; - } else { - jx.value = (float)p_val / (MAX_JOY_AXIS - 1); - } - if (p_negate) { - jx.value = -jx.value; - } - return jx; - } - jx.min = -1; - jx.value = (float)p_val / MAX_JOY_AXIS; - return jx; -} - -void JoypadWindows::joypad_vibration_start_xinput(int p_device, float p_weak_magnitude, float p_strong_magnitude, float p_duration, uint64_t p_timestamp) { - xinput_gamepad &joy = x_joypads[p_device]; - if (joy.attached) { - XINPUT_VIBRATION effect; - effect.wLeftMotorSpeed = (65535 * p_strong_magnitude); - effect.wRightMotorSpeed = (65535 * p_weak_magnitude); - if (xinput_set_state(p_device, &effect) == ERROR_SUCCESS) { - joy.ff_timestamp = p_timestamp; - joy.ff_end_timestamp = p_duration == 0 ? 0 : p_timestamp + (uint64_t)(p_duration * 1000000.0); - joy.vibrating = true; - } - } -} - -void JoypadWindows::joypad_vibration_stop_xinput(int p_device, uint64_t p_timestamp) { - xinput_gamepad &joy = x_joypads[p_device]; - if (joy.attached) { - XINPUT_VIBRATION effect; - effect.wLeftMotorSpeed = 0; - effect.wRightMotorSpeed = 0; - if (xinput_set_state(p_device, &effect) == ERROR_SUCCESS) { - joy.ff_timestamp = p_timestamp; - joy.vibrating = false; - } - } -} - -void JoypadWindows::load_xinput() { - - xinput_get_state = &_xinput_get_state; - xinput_set_state = &_xinput_set_state; - xinput_dll = LoadLibrary("XInput1_4.dll"); - if (!xinput_dll) { - xinput_dll = LoadLibrary("XInput1_3.dll"); - if (!xinput_dll) { - xinput_dll = LoadLibrary("XInput9_1_0.dll"); - } - } - - if (!xinput_dll) { - print_verbose("Could not find XInput, using DirectInput only"); - return; - } - - XInputGetState_t func = (XInputGetState_t)GetProcAddress((HMODULE)xinput_dll, "XInputGetState"); - XInputSetState_t set_func = (XInputSetState_t)GetProcAddress((HMODULE)xinput_dll, "XInputSetState"); - if (!func || !set_func) { - unload_xinput(); - return; - } - xinput_get_state = func; - xinput_set_state = set_func; -} - -void JoypadWindows::unload_xinput() { - - if (xinput_dll) { - - FreeLibrary((HMODULE)xinput_dll); - } -} diff --git a/platform/windows/joypad.h b/platform/windows/joypad.h deleted file mode 100644 index 3a6c0cef9f..0000000000 --- a/platform/windows/joypad.h +++ /dev/null @@ -1,148 +0,0 @@ -/*************************************************************************/ -/* joypad.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#ifndef JOYPAD_H -#define JOYPAD_H - -#include "os_windows.h" -#define DIRECTINPUT_VERSION 0x0800 -#include -#include // on unix the file is called "xinput.h", on windows I'm sure it won't mind - -#ifndef SAFE_RELEASE // when Windows Media Device M? is not present -#define SAFE_RELEASE(x) \ - if (x != NULL) { \ - x->Release(); \ - x = NULL; \ - } -#endif - -#ifndef XUSER_MAX_COUNT -#define XUSER_MAX_COUNT 4 -#endif - -class JoypadWindows { -public: - JoypadWindows(); - JoypadWindows(InputDefault *_input, HWND *hwnd); - ~JoypadWindows(); - - void probe_joypads(); - void process_joypads(); - -private: - enum { - JOYPADS_MAX = 16, - JOY_AXIS_COUNT = 6, - MIN_JOY_AXIS = 10, - MAX_JOY_AXIS = 32768, - MAX_JOY_BUTTONS = 128, - KEY_EVENT_BUFFER_SIZE = 512, - MAX_TRIGGER = 255 - }; - - struct dinput_gamepad { - - int id; - bool attached; - bool confirmed; - bool last_buttons[MAX_JOY_BUTTONS]; - DWORD last_pad; - - LPDIRECTINPUTDEVICE8 di_joy; - List joy_axis; - GUID guid; - - dinput_gamepad() { - id = -1; - last_pad = -1; - attached = false; - confirmed = false; - - for (int i = 0; i < MAX_JOY_BUTTONS; i++) - last_buttons[i] = false; - } - }; - - struct xinput_gamepad { - - int id; - bool attached; - bool vibrating; - DWORD last_packet; - XINPUT_STATE state; - uint64_t ff_timestamp; - uint64_t ff_end_timestamp; - - xinput_gamepad() { - attached = false; - vibrating = false; - ff_timestamp = 0; - ff_end_timestamp = 0; - last_packet = 0; - } - }; - - typedef DWORD(WINAPI *XInputGetState_t)(DWORD dwUserIndex, XINPUT_STATE *pState); - typedef DWORD(WINAPI *XInputSetState_t)(DWORD dwUserIndex, XINPUT_VIBRATION *pVibration); - - HWND *hWnd; - HANDLE xinput_dll; - LPDIRECTINPUT8 dinput; - InputDefault *input; - - int id_to_change; - int joypad_count; - bool attached_joypads[JOYPADS_MAX]; - dinput_gamepad d_joypads[JOYPADS_MAX]; - xinput_gamepad x_joypads[XUSER_MAX_COUNT]; - - static BOOL CALLBACK enumCallback(const DIDEVICEINSTANCE *p_instance, void *p_context); - static BOOL CALLBACK objectsCallback(const DIDEVICEOBJECTINSTANCE *instance, void *context); - - void setup_joypad_object(const DIDEVICEOBJECTINSTANCE *ob, int p_joy_id); - void close_joypad(int id = -1); - void load_xinput(); - void unload_xinput(); - - void post_hat(int p_device, DWORD p_dpad); - - bool have_device(const GUID &p_guid); - bool is_xinput_device(const GUID *p_guid); - bool setup_dinput_joypad(const DIDEVICEINSTANCE *instance); - void joypad_vibration_start_xinput(int p_device, float p_weak_magnitude, float p_strong_magnitude, float p_duration, uint64_t p_timestamp); - void joypad_vibration_stop_xinput(int p_device, uint64_t p_timestamp); - - InputDefault::JoyAxis axis_correct(int p_val, bool p_xinput = false, bool p_trigger = false, bool p_negate = false) const; - XInputGetState_t xinput_get_state; - XInputSetState_t xinput_set_state; -}; - -#endif diff --git a/platform/windows/joypad_windows.cpp b/platform/windows/joypad_windows.cpp new file mode 100644 index 0000000000..5a399cdf90 --- /dev/null +++ b/platform/windows/joypad_windows.cpp @@ -0,0 +1,558 @@ +/*************************************************************************/ +/* joypad_windows.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "joypad_windows.h" + +#include +#include + +#ifndef __GNUC__ +#define __builtin_bswap32 _byteswap_ulong +#endif + +DWORD WINAPI _xinput_get_state(DWORD dwUserIndex, XINPUT_STATE *pState) { + return ERROR_DEVICE_NOT_CONNECTED; +} +DWORD WINAPI _xinput_set_state(DWORD dwUserIndex, XINPUT_VIBRATION *pVibration) { + return ERROR_DEVICE_NOT_CONNECTED; +} + +JoypadWindows::JoypadWindows() { +} + +JoypadWindows::JoypadWindows(InputDefault *_input, HWND *hwnd) { + + input = _input; + hWnd = hwnd; + joypad_count = 0; + dinput = NULL; + xinput_dll = NULL; + xinput_get_state = NULL; + xinput_set_state = NULL; + + load_xinput(); + + for (int i = 0; i < JOYPADS_MAX; i++) + attached_joypads[i] = false; + + HRESULT result; + result = DirectInput8Create(GetModuleHandle(NULL), DIRECTINPUT_VERSION, IID_IDirectInput8, (void **)&dinput, NULL); + if (FAILED(result)) { + printf("failed init DINPUT: %ld\n", result); + } + probe_joypads(); +} + +JoypadWindows::~JoypadWindows() { + + close_joypad(); + dinput->Release(); + unload_xinput(); +} + +bool JoypadWindows::have_device(const GUID &p_guid) { + + for (int i = 0; i < JOYPADS_MAX; i++) { + + if (d_joypads[i].guid == p_guid) { + + d_joypads[i].confirmed = true; + return true; + } + } + return false; +} + +// adapted from SDL2, works a lot better than the MSDN version +bool JoypadWindows::is_xinput_device(const GUID *p_guid) { + + static GUID IID_ValveStreamingGamepad = { MAKELONG(0x28DE, 0x11FF), 0x0000, 0x0000, { 0x00, 0x00, 0x50, 0x49, 0x44, 0x56, 0x49, 0x44 } }; + static GUID IID_X360WiredGamepad = { MAKELONG(0x045E, 0x02A1), 0x0000, 0x0000, { 0x00, 0x00, 0x50, 0x49, 0x44, 0x56, 0x49, 0x44 } }; + static GUID IID_X360WirelessGamepad = { MAKELONG(0x045E, 0x028E), 0x0000, 0x0000, { 0x00, 0x00, 0x50, 0x49, 0x44, 0x56, 0x49, 0x44 } }; + + if (p_guid == &IID_ValveStreamingGamepad || p_guid == &IID_X360WiredGamepad || p_guid == &IID_X360WirelessGamepad) + return true; + + PRAWINPUTDEVICELIST dev_list = NULL; + unsigned int dev_list_count = 0; + + if (GetRawInputDeviceList(NULL, &dev_list_count, sizeof(RAWINPUTDEVICELIST)) == -1) { + return false; + } + dev_list = (PRAWINPUTDEVICELIST)malloc(sizeof(RAWINPUTDEVICELIST) * dev_list_count); + if (!dev_list) return false; + + if (GetRawInputDeviceList(dev_list, &dev_list_count, sizeof(RAWINPUTDEVICELIST)) == -1) { + free(dev_list); + return false; + } + for (int i = 0; i < dev_list_count; i++) { + + RID_DEVICE_INFO rdi; + char dev_name[128]; + UINT rdiSize = sizeof(rdi); + UINT nameSize = sizeof(dev_name); + + rdi.cbSize = rdiSize; + if ((dev_list[i].dwType == RIM_TYPEHID) && + (GetRawInputDeviceInfoA(dev_list[i].hDevice, RIDI_DEVICEINFO, &rdi, &rdiSize) != (UINT)-1) && + (MAKELONG(rdi.hid.dwVendorId, rdi.hid.dwProductId) == (LONG)p_guid->Data1) && + (GetRawInputDeviceInfoA(dev_list[i].hDevice, RIDI_DEVICENAME, &dev_name, &nameSize) != (UINT)-1) && + (strstr(dev_name, "IG_") != NULL)) { + + free(dev_list); + return true; + } + } + free(dev_list); + return false; +} + +bool JoypadWindows::setup_dinput_joypad(const DIDEVICEINSTANCE *instance) { + + HRESULT hr; + int num = input->get_unused_joy_id(); + + if (have_device(instance->guidInstance) || num == -1) + return false; + + d_joypads[joypad_count] = dinput_gamepad(); + dinput_gamepad *joy = &d_joypads[joypad_count]; + + const DWORD devtype = (instance->dwDevType & 0xFF); + + if ((devtype != DI8DEVTYPE_JOYSTICK) && (devtype != DI8DEVTYPE_GAMEPAD) && (devtype != DI8DEVTYPE_1STPERSON)) { + return false; + } + + hr = dinput->CreateDevice(instance->guidInstance, &joy->di_joy, NULL); + + if (FAILED(hr)) { + return false; + } + + const GUID &guid = instance->guidProduct; + char uid[128]; + sprintf_s(uid, "%08lx%04hx%04hx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx", + __builtin_bswap32(guid.Data1), guid.Data2, guid.Data3, + guid.Data4[0], guid.Data4[1], guid.Data4[2], guid.Data4[3], + guid.Data4[4], guid.Data4[5], guid.Data4[6], guid.Data4[7]); + + id_to_change = joypad_count; + + joy->di_joy->SetDataFormat(&c_dfDIJoystick2); + joy->di_joy->SetCooperativeLevel(*hWnd, DISCL_FOREGROUND); + joy->di_joy->EnumObjects(objectsCallback, this, 0); + joy->joy_axis.sort(); + + joy->guid = instance->guidInstance; + input->joy_connection_changed(num, true, instance->tszProductName, uid); + joy->attached = true; + joy->id = num; + attached_joypads[num] = true; + joy->confirmed = true; + joypad_count++; + return true; +} + +void JoypadWindows::setup_joypad_object(const DIDEVICEOBJECTINSTANCE *ob, int p_joy_id) { + + if (ob->dwType & DIDFT_AXIS) { + + HRESULT res; + DIPROPRANGE prop_range; + DIPROPDWORD dilong; + DWORD ofs; + if (ob->guidType == GUID_XAxis) + ofs = DIJOFS_X; + else if (ob->guidType == GUID_YAxis) + ofs = DIJOFS_Y; + else if (ob->guidType == GUID_ZAxis) + ofs = DIJOFS_Z; + else if (ob->guidType == GUID_RxAxis) + ofs = DIJOFS_RX; + else if (ob->guidType == GUID_RyAxis) + ofs = DIJOFS_RY; + else if (ob->guidType == GUID_RzAxis) + ofs = DIJOFS_RZ; + else if (ob->guidType == GUID_Slider) + ofs = DIJOFS_SLIDER(0); + else + return; + prop_range.diph.dwSize = sizeof(DIPROPRANGE); + prop_range.diph.dwHeaderSize = sizeof(DIPROPHEADER); + prop_range.diph.dwObj = ob->dwType; + prop_range.diph.dwHow = DIPH_BYID; + prop_range.lMin = -MAX_JOY_AXIS; + prop_range.lMax = +MAX_JOY_AXIS; + + dinput_gamepad &joy = d_joypads[p_joy_id]; + + res = IDirectInputDevice8_SetProperty(joy.di_joy, DIPROP_RANGE, &prop_range.diph); + if (FAILED(res)) + return; + + dilong.diph.dwSize = sizeof(dilong); + dilong.diph.dwHeaderSize = sizeof(dilong.diph); + dilong.diph.dwObj = ob->dwType; + dilong.diph.dwHow = DIPH_BYID; + dilong.dwData = 0; + + res = IDirectInputDevice8_SetProperty(joy.di_joy, DIPROP_DEADZONE, &dilong.diph); + if (FAILED(res)) + return; + + joy.joy_axis.push_back(ofs); + } +} + +BOOL CALLBACK JoypadWindows::enumCallback(const DIDEVICEINSTANCE *p_instance, void *p_context) { + + JoypadWindows *self = (JoypadWindows *)p_context; + if (self->is_xinput_device(&p_instance->guidProduct)) { + return DIENUM_CONTINUE; + } + self->setup_dinput_joypad(p_instance); + return DIENUM_CONTINUE; +} + +BOOL CALLBACK JoypadWindows::objectsCallback(const DIDEVICEOBJECTINSTANCE *instance, void *context) { + + JoypadWindows *self = (JoypadWindows *)context; + self->setup_joypad_object(instance, self->id_to_change); + + return DIENUM_CONTINUE; +} + +void JoypadWindows::close_joypad(int id) { + + if (id == -1) { + + for (int i = 0; i < JOYPADS_MAX; i++) { + + close_joypad(i); + } + return; + } + + if (!d_joypads[id].attached) return; + + d_joypads[id].di_joy->Unacquire(); + d_joypads[id].di_joy->Release(); + d_joypads[id].attached = false; + attached_joypads[d_joypads[id].id] = false; + d_joypads[id].guid.Data1 = d_joypads[id].guid.Data2 = d_joypads[id].guid.Data3 = 0; + input->joy_connection_changed(d_joypads[id].id, false, ""); + joypad_count--; +} + +void JoypadWindows::probe_joypads() { + + DWORD dwResult; + for (DWORD i = 0; i < XUSER_MAX_COUNT; i++) { + + ZeroMemory(&x_joypads[i].state, sizeof(XINPUT_STATE)); + + dwResult = xinput_get_state(i, &x_joypads[i].state); + if (dwResult == ERROR_SUCCESS) { + + int id = input->get_unused_joy_id(); + if (id != -1 && !x_joypads[i].attached) { + + x_joypads[i].attached = true; + x_joypads[i].id = id; + x_joypads[i].ff_timestamp = 0; + x_joypads[i].ff_end_timestamp = 0; + x_joypads[i].vibrating = false; + attached_joypads[id] = true; + input->joy_connection_changed(id, true, "XInput Gamepad", "__XINPUT_DEVICE__"); + } + } else if (x_joypads[i].attached) { + + x_joypads[i].attached = false; + attached_joypads[x_joypads[i].id] = false; + input->joy_connection_changed(x_joypads[i].id, false, ""); + } + } + + for (int i = 0; i < joypad_count; i++) { + + d_joypads[i].confirmed = false; + } + + dinput->EnumDevices(DI8DEVCLASS_GAMECTRL, enumCallback, this, DIEDFL_ATTACHEDONLY); + + for (int i = 0; i < joypad_count; i++) { + + if (!d_joypads[i].confirmed) { + + close_joypad(i); + } + } +} + +void JoypadWindows::process_joypads() { + + HRESULT hr; + + for (int i = 0; i < XUSER_MAX_COUNT; i++) { + + xinput_gamepad &joy = x_joypads[i]; + if (!joy.attached) { + continue; + } + ZeroMemory(&joy.state, sizeof(XINPUT_STATE)); + + xinput_get_state(i, &joy.state); + if (joy.state.dwPacketNumber != joy.last_packet) { + + int button_mask = XINPUT_GAMEPAD_DPAD_UP; + for (int i = 0; i <= 16; i++) { + + input->joy_button(joy.id, i, joy.state.Gamepad.wButtons & button_mask); + button_mask = button_mask * 2; + } + + input->joy_axis(joy.id, JOY_AXIS_0, axis_correct(joy.state.Gamepad.sThumbLX, true)); + input->joy_axis(joy.id, JOY_AXIS_1, axis_correct(joy.state.Gamepad.sThumbLY, true, false, true)); + input->joy_axis(joy.id, JOY_AXIS_2, axis_correct(joy.state.Gamepad.sThumbRX, true)); + input->joy_axis(joy.id, JOY_AXIS_3, axis_correct(joy.state.Gamepad.sThumbRY, true, false, true)); + input->joy_axis(joy.id, JOY_AXIS_4, axis_correct(joy.state.Gamepad.bLeftTrigger, true, true)); + input->joy_axis(joy.id, JOY_AXIS_5, axis_correct(joy.state.Gamepad.bRightTrigger, true, true)); + joy.last_packet = joy.state.dwPacketNumber; + } + uint64_t timestamp = input->get_joy_vibration_timestamp(joy.id); + if (timestamp > joy.ff_timestamp) { + Vector2 strength = input->get_joy_vibration_strength(joy.id); + float duration = input->get_joy_vibration_duration(joy.id); + if (strength.x == 0 && strength.y == 0) { + joypad_vibration_stop_xinput(i, timestamp); + } else { + joypad_vibration_start_xinput(i, strength.x, strength.y, duration, timestamp); + } + } else if (joy.vibrating && joy.ff_end_timestamp != 0) { + uint64_t current_time = OS::get_singleton()->get_ticks_usec(); + if (current_time >= joy.ff_end_timestamp) + joypad_vibration_stop_xinput(i, current_time); + } + } + + for (int i = 0; i < JOYPADS_MAX; i++) { + + dinput_gamepad *joy = &d_joypads[i]; + + if (!joy->attached) + continue; + + DIJOYSTATE2 js; + hr = joy->di_joy->Poll(); + if (hr == DIERR_INPUTLOST || hr == DIERR_NOTACQUIRED) { + IDirectInputDevice8_Acquire(joy->di_joy); + joy->di_joy->Poll(); + } + + hr = joy->di_joy->GetDeviceState(sizeof(DIJOYSTATE2), &js); + if (FAILED(hr)) { + continue; + } + + post_hat(joy->id, js.rgdwPOV[0]); + + for (int j = 0; j < 128; j++) { + + if (js.rgbButtons[j] & 0x80) { + + if (!joy->last_buttons[j]) { + + input->joy_button(joy->id, j, true); + joy->last_buttons[j] = true; + } + } else { + + if (joy->last_buttons[j]) { + + input->joy_button(joy->id, j, false); + joy->last_buttons[j] = false; + } + } + } + + // on mingw, these constants are not constants + int count = 6; + int axes[] = { DIJOFS_X, DIJOFS_Y, DIJOFS_Z, DIJOFS_RX, DIJOFS_RY, DIJOFS_RZ }; + int values[] = { js.lX, js.lY, js.lZ, js.lRx, js.lRy, js.lRz }; + + for (int j = 0; j < joy->joy_axis.size(); j++) { + + for (int k = 0; k < count; k++) { + if (joy->joy_axis[j] == axes[k]) { + input->joy_axis(joy->id, j, axis_correct(values[k])); + break; + }; + }; + }; + } + return; +} + +void JoypadWindows::post_hat(int p_device, DWORD p_dpad) { + + int dpad_val = 0; + + if (p_dpad == -1) { + dpad_val = InputDefault::HAT_MASK_CENTER; + } + if (p_dpad == 0) { + + dpad_val = InputDefault::HAT_MASK_UP; + + } else if (p_dpad == 4500) { + + dpad_val = (InputDefault::HAT_MASK_UP | InputDefault::HAT_MASK_RIGHT); + + } else if (p_dpad == 9000) { + + dpad_val = InputDefault::HAT_MASK_RIGHT; + + } else if (p_dpad == 13500) { + + dpad_val = (InputDefault::HAT_MASK_RIGHT | InputDefault::HAT_MASK_DOWN); + + } else if (p_dpad == 18000) { + + dpad_val = InputDefault::HAT_MASK_DOWN; + + } else if (p_dpad == 22500) { + + dpad_val = (InputDefault::HAT_MASK_DOWN | InputDefault::HAT_MASK_LEFT); + + } else if (p_dpad == 27000) { + + dpad_val = InputDefault::HAT_MASK_LEFT; + + } else if (p_dpad == 31500) { + + dpad_val = (InputDefault::HAT_MASK_LEFT | InputDefault::HAT_MASK_UP); + } + input->joy_hat(p_device, dpad_val); +}; + +InputDefault::JoyAxis JoypadWindows::axis_correct(int p_val, bool p_xinput, bool p_trigger, bool p_negate) const { + + InputDefault::JoyAxis jx; + if (Math::abs(p_val) < MIN_JOY_AXIS) { + jx.min = p_trigger ? 0 : -1; + jx.value = 0.0f; + return jx; + } + if (p_xinput) { + + if (p_trigger) { + jx.min = 0; + jx.value = (float)p_val / MAX_TRIGGER; + return jx; + } + jx.min = -1; + if (p_val < 0) { + jx.value = (float)p_val / MAX_JOY_AXIS; + } else { + jx.value = (float)p_val / (MAX_JOY_AXIS - 1); + } + if (p_negate) { + jx.value = -jx.value; + } + return jx; + } + jx.min = -1; + jx.value = (float)p_val / MAX_JOY_AXIS; + return jx; +} + +void JoypadWindows::joypad_vibration_start_xinput(int p_device, float p_weak_magnitude, float p_strong_magnitude, float p_duration, uint64_t p_timestamp) { + xinput_gamepad &joy = x_joypads[p_device]; + if (joy.attached) { + XINPUT_VIBRATION effect; + effect.wLeftMotorSpeed = (65535 * p_strong_magnitude); + effect.wRightMotorSpeed = (65535 * p_weak_magnitude); + if (xinput_set_state(p_device, &effect) == ERROR_SUCCESS) { + joy.ff_timestamp = p_timestamp; + joy.ff_end_timestamp = p_duration == 0 ? 0 : p_timestamp + (uint64_t)(p_duration * 1000000.0); + joy.vibrating = true; + } + } +} + +void JoypadWindows::joypad_vibration_stop_xinput(int p_device, uint64_t p_timestamp) { + xinput_gamepad &joy = x_joypads[p_device]; + if (joy.attached) { + XINPUT_VIBRATION effect; + effect.wLeftMotorSpeed = 0; + effect.wRightMotorSpeed = 0; + if (xinput_set_state(p_device, &effect) == ERROR_SUCCESS) { + joy.ff_timestamp = p_timestamp; + joy.vibrating = false; + } + } +} + +void JoypadWindows::load_xinput() { + + xinput_get_state = &_xinput_get_state; + xinput_set_state = &_xinput_set_state; + xinput_dll = LoadLibrary("XInput1_4.dll"); + if (!xinput_dll) { + xinput_dll = LoadLibrary("XInput1_3.dll"); + if (!xinput_dll) { + xinput_dll = LoadLibrary("XInput9_1_0.dll"); + } + } + + if (!xinput_dll) { + print_verbose("Could not find XInput, using DirectInput only"); + return; + } + + XInputGetState_t func = (XInputGetState_t)GetProcAddress((HMODULE)xinput_dll, "XInputGetState"); + XInputSetState_t set_func = (XInputSetState_t)GetProcAddress((HMODULE)xinput_dll, "XInputSetState"); + if (!func || !set_func) { + unload_xinput(); + return; + } + xinput_get_state = func; + xinput_set_state = set_func; +} + +void JoypadWindows::unload_xinput() { + + if (xinput_dll) { + + FreeLibrary((HMODULE)xinput_dll); + } +} diff --git a/platform/windows/joypad_windows.h b/platform/windows/joypad_windows.h new file mode 100644 index 0000000000..4af5d9bd6a --- /dev/null +++ b/platform/windows/joypad_windows.h @@ -0,0 +1,149 @@ +/*************************************************************************/ +/* joypad_windows.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef JOYPAD_WINDOWS_H +#define JOYPAD_WINDOWS_H + +#include "os_windows.h" + +#define DIRECTINPUT_VERSION 0x0800 +#include +#include // on unix the file is called "xinput.h", on windows I'm sure it won't mind + +#ifndef SAFE_RELEASE // when Windows Media Device M? is not present +#define SAFE_RELEASE(x) \ + if (x != NULL) { \ + x->Release(); \ + x = NULL; \ + } +#endif + +#ifndef XUSER_MAX_COUNT +#define XUSER_MAX_COUNT 4 +#endif + +class JoypadWindows { +public: + JoypadWindows(); + JoypadWindows(InputDefault *_input, HWND *hwnd); + ~JoypadWindows(); + + void probe_joypads(); + void process_joypads(); + +private: + enum { + JOYPADS_MAX = 16, + JOY_AXIS_COUNT = 6, + MIN_JOY_AXIS = 10, + MAX_JOY_AXIS = 32768, + MAX_JOY_BUTTONS = 128, + KEY_EVENT_BUFFER_SIZE = 512, + MAX_TRIGGER = 255 + }; + + struct dinput_gamepad { + + int id; + bool attached; + bool confirmed; + bool last_buttons[MAX_JOY_BUTTONS]; + DWORD last_pad; + + LPDIRECTINPUTDEVICE8 di_joy; + List joy_axis; + GUID guid; + + dinput_gamepad() { + id = -1; + last_pad = -1; + attached = false; + confirmed = false; + + for (int i = 0; i < MAX_JOY_BUTTONS; i++) + last_buttons[i] = false; + } + }; + + struct xinput_gamepad { + + int id; + bool attached; + bool vibrating; + DWORD last_packet; + XINPUT_STATE state; + uint64_t ff_timestamp; + uint64_t ff_end_timestamp; + + xinput_gamepad() { + attached = false; + vibrating = false; + ff_timestamp = 0; + ff_end_timestamp = 0; + last_packet = 0; + } + }; + + typedef DWORD(WINAPI *XInputGetState_t)(DWORD dwUserIndex, XINPUT_STATE *pState); + typedef DWORD(WINAPI *XInputSetState_t)(DWORD dwUserIndex, XINPUT_VIBRATION *pVibration); + + HWND *hWnd; + HANDLE xinput_dll; + LPDIRECTINPUT8 dinput; + InputDefault *input; + + int id_to_change; + int joypad_count; + bool attached_joypads[JOYPADS_MAX]; + dinput_gamepad d_joypads[JOYPADS_MAX]; + xinput_gamepad x_joypads[XUSER_MAX_COUNT]; + + static BOOL CALLBACK enumCallback(const DIDEVICEINSTANCE *p_instance, void *p_context); + static BOOL CALLBACK objectsCallback(const DIDEVICEOBJECTINSTANCE *instance, void *context); + + void setup_joypad_object(const DIDEVICEOBJECTINSTANCE *ob, int p_joy_id); + void close_joypad(int id = -1); + void load_xinput(); + void unload_xinput(); + + void post_hat(int p_device, DWORD p_dpad); + + bool have_device(const GUID &p_guid); + bool is_xinput_device(const GUID *p_guid); + bool setup_dinput_joypad(const DIDEVICEINSTANCE *instance); + void joypad_vibration_start_xinput(int p_device, float p_weak_magnitude, float p_strong_magnitude, float p_duration, uint64_t p_timestamp); + void joypad_vibration_stop_xinput(int p_device, uint64_t p_timestamp); + + InputDefault::JoyAxis axis_correct(int p_val, bool p_xinput = false, bool p_trigger = false, bool p_negate = false) const; + XInputGetState_t xinput_get_state; + XInputSetState_t xinput_set_state; +}; + +#endif // JOYPAD_WINDOWS_H diff --git a/platform/windows/key_mapping_win.cpp b/platform/windows/key_mapping_win.cpp deleted file mode 100644 index f9b01e5532..0000000000 --- a/platform/windows/key_mapping_win.cpp +++ /dev/null @@ -1,253 +0,0 @@ -/*************************************************************************/ -/* key_mapping_win.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#include "key_mapping_win.h" - -#include - -struct _WinTranslatePair { - - unsigned int keysym; - unsigned int keycode; -}; - -static _WinTranslatePair _vk_to_keycode[] = { - - { KEY_BACKSPACE, VK_BACK }, // (0x08) // backspace - { KEY_TAB, VK_TAB }, //(0x09) - - //VK_CLEAR (0x0C) - - { KEY_ENTER, VK_RETURN }, //(0x0D) - - { KEY_SHIFT, VK_SHIFT }, //(0x10) - - { KEY_CONTROL, VK_CONTROL }, //(0x11) - - { KEY_ALT, VK_MENU }, //(0x12) - - { KEY_PAUSE, VK_PAUSE }, //(0x13) - - { KEY_CAPSLOCK, VK_CAPITAL }, //(0x14) - - { KEY_ESCAPE, VK_ESCAPE }, //(0x1B) - - { KEY_SPACE, VK_SPACE }, //(0x20) - - { KEY_PAGEUP, VK_PRIOR }, //(0x21) - - { KEY_PAGEDOWN, VK_NEXT }, //(0x22) - - { KEY_END, VK_END }, //(0x23) - - { KEY_HOME, VK_HOME }, //(0x24) - - { KEY_LEFT, VK_LEFT }, //(0x25) - - { KEY_UP, VK_UP }, //(0x26) - - { KEY_RIGHT, VK_RIGHT }, //(0x27) - - { KEY_DOWN, VK_DOWN }, // (0x28) - - //VK_SELECT (0x29) - - { KEY_PRINT, VK_PRINT }, // (0x2A) - - //VK_EXECUTE (0x2B) - - { KEY_PRINT, VK_SNAPSHOT }, // (0x2C) - - { KEY_INSERT, VK_INSERT }, // (0x2D) - - { KEY_DELETE, VK_DELETE }, // (0x2E) - - { KEY_HELP, VK_HELP }, // (0x2F) - - { KEY_0, (0x30) }, ////0 key - { KEY_1, (0x31) }, ////1 key - { KEY_2, (0x32) }, ////2 key - { KEY_3, (0x33) }, ////3 key - { KEY_4, (0x34) }, ////4 key - { KEY_5, (0x35) }, ////5 key - { KEY_6, (0x36) }, ////6 key - { KEY_7, (0x37) }, ////7 key - { KEY_8, (0x38) }, ////8 key - { KEY_9, (0x39) }, ////9 key - { KEY_A, (0x41) }, ////A key - { KEY_B, (0x42) }, ////B key - { KEY_C, (0x43) }, ////C key - { KEY_D, (0x44) }, ////D key - { KEY_E, (0x45) }, ////E key - { KEY_F, (0x46) }, ////F key - { KEY_G, (0x47) }, ////G key - { KEY_H, (0x48) }, ////H key - { KEY_I, (0x49) }, ////I key - { KEY_J, (0x4A) }, ////J key - { KEY_K, (0x4B) }, ////K key - { KEY_L, (0x4C) }, ////L key - { KEY_M, (0x4D) }, ////M key - { KEY_N, (0x4E) }, ////N key - { KEY_O, (0x4F) }, ////O key - { KEY_P, (0x50) }, ////P key - { KEY_Q, (0x51) }, ////Q key - { KEY_R, (0x52) }, ////R key - { KEY_S, (0x53) }, ////S key - { KEY_T, (0x54) }, ////T key - { KEY_U, (0x55) }, ////U key - { KEY_V, (0x56) }, ////V key - { KEY_W, (0x57) }, ////W key - { KEY_X, (0x58) }, ////X key - { KEY_Y, (0x59) }, ////Y key - { KEY_Z, (0x5A) }, ////Z key - - { KEY_MASK_META, VK_LWIN }, //(0x5B) - { KEY_MASK_META, VK_RWIN }, //(0x5C) - //VK_APPS (0x5D) - { KEY_STANDBY, VK_SLEEP }, //(0x5F) - { KEY_KP_0, VK_NUMPAD0 }, //(0x60) - { KEY_KP_1, VK_NUMPAD1 }, //(0x61) - { KEY_KP_2, VK_NUMPAD2 }, //(0x62) - { KEY_KP_3, VK_NUMPAD3 }, //(0x63) - { KEY_KP_4, VK_NUMPAD4 }, //(0x64) - { KEY_KP_5, VK_NUMPAD5 }, //(0x65) - { KEY_KP_6, VK_NUMPAD6 }, //(0x66) - { KEY_KP_7, VK_NUMPAD7 }, //(0x67) - { KEY_KP_8, VK_NUMPAD8 }, //(0x68) - { KEY_KP_9, VK_NUMPAD9 }, //(0x69) - { KEY_KP_MULTIPLY, VK_MULTIPLY }, // (0x6A) - { KEY_KP_ADD, VK_ADD }, // (0x6B) - //VK_SEPARATOR (0x6C) - { KEY_KP_SUBTRACT, VK_SUBTRACT }, // (0x6D) - { KEY_KP_PERIOD, VK_DECIMAL }, // (0x6E) - { KEY_KP_DIVIDE, VK_DIVIDE }, // (0x6F) - { KEY_F1, VK_F1 }, // (0x70) - { KEY_F2, VK_F2 }, // (0x71) - { KEY_F3, VK_F3 }, // (0x72) - { KEY_F4, VK_F4 }, // (0x73) - { KEY_F5, VK_F5 }, // (0x74) - { KEY_F6, VK_F6 }, // (0x75) - { KEY_F7, VK_F7 }, // (0x76) - { KEY_F8, VK_F8 }, // (0x77) - { KEY_F9, VK_F9 }, // (0x78) - { KEY_F10, VK_F10 }, // (0x79) - { KEY_F11, VK_F11 }, // (0x7A) - { KEY_F12, VK_F12 }, // (0x7B) - { KEY_F13, VK_F13 }, // (0x7C) - { KEY_F14, VK_F14 }, // (0x7D) - { KEY_F15, VK_F15 }, // (0x7E) - { KEY_F16, VK_F16 }, // (0x7F) - { KEY_NUMLOCK, VK_NUMLOCK }, // (0x90) - { KEY_SCROLLLOCK, VK_SCROLL }, // (0x91) - { KEY_SHIFT, VK_LSHIFT }, // (0xA0) - { KEY_SHIFT, VK_RSHIFT }, // (0xA1) - { KEY_CONTROL, VK_LCONTROL }, // (0xA2) - { KEY_CONTROL, VK_RCONTROL }, // (0xA3) - { KEY_MENU, VK_LMENU }, // (0xA4) - { KEY_MENU, VK_RMENU }, // (0xA5) - - { KEY_BACK, VK_BROWSER_BACK }, // (0xA6) - - { KEY_FORWARD, VK_BROWSER_FORWARD }, // (0xA7) - - { KEY_REFRESH, VK_BROWSER_REFRESH }, // (0xA8) - - { KEY_STOP, VK_BROWSER_STOP }, // (0xA9) - - { KEY_SEARCH, VK_BROWSER_SEARCH }, // (0xAA) - - { KEY_FAVORITES, VK_BROWSER_FAVORITES }, // (0xAB) - - { KEY_HOMEPAGE, VK_BROWSER_HOME }, // (0xAC) - - { KEY_VOLUMEMUTE, VK_VOLUME_MUTE }, // (0xAD) - - { KEY_VOLUMEDOWN, VK_VOLUME_DOWN }, // (0xAE) - - { KEY_VOLUMEUP, VK_VOLUME_UP }, // (0xAF) - - { KEY_MEDIANEXT, VK_MEDIA_NEXT_TRACK }, // (0xB0) - - { KEY_MEDIAPREVIOUS, VK_MEDIA_PREV_TRACK }, // (0xB1) - - { KEY_MEDIASTOP, VK_MEDIA_STOP }, // (0xB2) - - //VK_MEDIA_PLAY_PAUSE (0xB3) - - { KEY_LAUNCHMAIL, VK_LAUNCH_MAIL }, // (0xB4) - - { KEY_LAUNCHMEDIA, VK_LAUNCH_MEDIA_SELECT }, // (0xB5) - - { KEY_LAUNCH0, VK_LAUNCH_APP1 }, // (0xB6) - - { KEY_LAUNCH1, VK_LAUNCH_APP2 }, // (0xB7) - - { KEY_SEMICOLON, VK_OEM_1 }, // (0xBA) - - { KEY_EQUAL, VK_OEM_PLUS }, // (0xBB) // Windows 2000/XP: For any country/region, the '+' key - { KEY_COMMA, VK_OEM_COMMA }, // (0xBC) // Windows 2000/XP: For any country/region, the ',' key - { KEY_MINUS, VK_OEM_MINUS }, // (0xBD) // Windows 2000/XP: For any country/region, the '-' key - { KEY_PERIOD, VK_OEM_PERIOD }, // (0xBE) // Windows 2000/XP: For any country/region, the '.' key - { KEY_SLASH, VK_OEM_2 }, // (0xBF) //Windows 2000/XP: For the US standard keyboard, the '/?' key - - { KEY_QUOTELEFT, VK_OEM_3 }, // (0xC0) - { KEY_BRACELEFT, VK_OEM_4 }, // (0xDB) - { KEY_BACKSLASH, VK_OEM_5 }, // (0xDC) - { KEY_BRACERIGHT, VK_OEM_6 }, // (0xDD) - { KEY_APOSTROPHE, VK_OEM_7 }, // (0xDE) - /* -{VK_OEM_8 (0xDF) -{VK_OEM_102 (0xE2) // Windows 2000/XP: Either the angle bracket key or the backslash key on the RT 102-key keyboard -*/ - //{ KEY_PLAY, VK_PLAY},// (0xFA) - - { KEY_UNKNOWN, 0 } -}; - -/* -VK_ZOOM (0xFB) -VK_NONAME (0xFC) -VK_PA1 (0xFD) -VK_OEM_CLEAR (0xFE) -*/ - -unsigned int KeyMappingWindows::get_keysym(unsigned int p_code) { - - for (int i = 0; _vk_to_keycode[i].keysym != KEY_UNKNOWN; i++) { - - if (_vk_to_keycode[i].keycode == p_code) { - //printf("outcode: %x\n",_vk_to_keycode[i].keysym); - - return _vk_to_keycode[i].keysym; - } - } - - return KEY_UNKNOWN; -} diff --git a/platform/windows/key_mapping_win.h b/platform/windows/key_mapping_win.h deleted file mode 100644 index e4f8a61d04..0000000000 --- a/platform/windows/key_mapping_win.h +++ /dev/null @@ -1,48 +0,0 @@ -/*************************************************************************/ -/* key_mapping_win.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#ifndef KEY_MAPPING_WINDOWS_H -#define KEY_MAPPING_WINDOWS_H - -#include "core/os/keyboard.h" - -#include - -#include - -class KeyMappingWindows { - - KeyMappingWindows(){}; - -public: - static unsigned int get_keysym(unsigned int p_code); -}; - -#endif diff --git a/platform/windows/key_mapping_windows.cpp b/platform/windows/key_mapping_windows.cpp new file mode 100644 index 0000000000..01bbb072bb --- /dev/null +++ b/platform/windows/key_mapping_windows.cpp @@ -0,0 +1,253 @@ +/*************************************************************************/ +/* key_mapping_windows.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "key_mapping_windows.h" + +#include + +struct _WinTranslatePair { + + unsigned int keysym; + unsigned int keycode; +}; + +static _WinTranslatePair _vk_to_keycode[] = { + + { KEY_BACKSPACE, VK_BACK }, // (0x08) // backspace + { KEY_TAB, VK_TAB }, //(0x09) + + //VK_CLEAR (0x0C) + + { KEY_ENTER, VK_RETURN }, //(0x0D) + + { KEY_SHIFT, VK_SHIFT }, //(0x10) + + { KEY_CONTROL, VK_CONTROL }, //(0x11) + + { KEY_ALT, VK_MENU }, //(0x12) + + { KEY_PAUSE, VK_PAUSE }, //(0x13) + + { KEY_CAPSLOCK, VK_CAPITAL }, //(0x14) + + { KEY_ESCAPE, VK_ESCAPE }, //(0x1B) + + { KEY_SPACE, VK_SPACE }, //(0x20) + + { KEY_PAGEUP, VK_PRIOR }, //(0x21) + + { KEY_PAGEDOWN, VK_NEXT }, //(0x22) + + { KEY_END, VK_END }, //(0x23) + + { KEY_HOME, VK_HOME }, //(0x24) + + { KEY_LEFT, VK_LEFT }, //(0x25) + + { KEY_UP, VK_UP }, //(0x26) + + { KEY_RIGHT, VK_RIGHT }, //(0x27) + + { KEY_DOWN, VK_DOWN }, // (0x28) + + //VK_SELECT (0x29) + + { KEY_PRINT, VK_PRINT }, // (0x2A) + + //VK_EXECUTE (0x2B) + + { KEY_PRINT, VK_SNAPSHOT }, // (0x2C) + + { KEY_INSERT, VK_INSERT }, // (0x2D) + + { KEY_DELETE, VK_DELETE }, // (0x2E) + + { KEY_HELP, VK_HELP }, // (0x2F) + + { KEY_0, (0x30) }, ////0 key + { KEY_1, (0x31) }, ////1 key + { KEY_2, (0x32) }, ////2 key + { KEY_3, (0x33) }, ////3 key + { KEY_4, (0x34) }, ////4 key + { KEY_5, (0x35) }, ////5 key + { KEY_6, (0x36) }, ////6 key + { KEY_7, (0x37) }, ////7 key + { KEY_8, (0x38) }, ////8 key + { KEY_9, (0x39) }, ////9 key + { KEY_A, (0x41) }, ////A key + { KEY_B, (0x42) }, ////B key + { KEY_C, (0x43) }, ////C key + { KEY_D, (0x44) }, ////D key + { KEY_E, (0x45) }, ////E key + { KEY_F, (0x46) }, ////F key + { KEY_G, (0x47) }, ////G key + { KEY_H, (0x48) }, ////H key + { KEY_I, (0x49) }, ////I key + { KEY_J, (0x4A) }, ////J key + { KEY_K, (0x4B) }, ////K key + { KEY_L, (0x4C) }, ////L key + { KEY_M, (0x4D) }, ////M key + { KEY_N, (0x4E) }, ////N key + { KEY_O, (0x4F) }, ////O key + { KEY_P, (0x50) }, ////P key + { KEY_Q, (0x51) }, ////Q key + { KEY_R, (0x52) }, ////R key + { KEY_S, (0x53) }, ////S key + { KEY_T, (0x54) }, ////T key + { KEY_U, (0x55) }, ////U key + { KEY_V, (0x56) }, ////V key + { KEY_W, (0x57) }, ////W key + { KEY_X, (0x58) }, ////X key + { KEY_Y, (0x59) }, ////Y key + { KEY_Z, (0x5A) }, ////Z key + + { KEY_MASK_META, VK_LWIN }, //(0x5B) + { KEY_MASK_META, VK_RWIN }, //(0x5C) + //VK_APPS (0x5D) + { KEY_STANDBY, VK_SLEEP }, //(0x5F) + { KEY_KP_0, VK_NUMPAD0 }, //(0x60) + { KEY_KP_1, VK_NUMPAD1 }, //(0x61) + { KEY_KP_2, VK_NUMPAD2 }, //(0x62) + { KEY_KP_3, VK_NUMPAD3 }, //(0x63) + { KEY_KP_4, VK_NUMPAD4 }, //(0x64) + { KEY_KP_5, VK_NUMPAD5 }, //(0x65) + { KEY_KP_6, VK_NUMPAD6 }, //(0x66) + { KEY_KP_7, VK_NUMPAD7 }, //(0x67) + { KEY_KP_8, VK_NUMPAD8 }, //(0x68) + { KEY_KP_9, VK_NUMPAD9 }, //(0x69) + { KEY_KP_MULTIPLY, VK_MULTIPLY }, // (0x6A) + { KEY_KP_ADD, VK_ADD }, // (0x6B) + //VK_SEPARATOR (0x6C) + { KEY_KP_SUBTRACT, VK_SUBTRACT }, // (0x6D) + { KEY_KP_PERIOD, VK_DECIMAL }, // (0x6E) + { KEY_KP_DIVIDE, VK_DIVIDE }, // (0x6F) + { KEY_F1, VK_F1 }, // (0x70) + { KEY_F2, VK_F2 }, // (0x71) + { KEY_F3, VK_F3 }, // (0x72) + { KEY_F4, VK_F4 }, // (0x73) + { KEY_F5, VK_F5 }, // (0x74) + { KEY_F6, VK_F6 }, // (0x75) + { KEY_F7, VK_F7 }, // (0x76) + { KEY_F8, VK_F8 }, // (0x77) + { KEY_F9, VK_F9 }, // (0x78) + { KEY_F10, VK_F10 }, // (0x79) + { KEY_F11, VK_F11 }, // (0x7A) + { KEY_F12, VK_F12 }, // (0x7B) + { KEY_F13, VK_F13 }, // (0x7C) + { KEY_F14, VK_F14 }, // (0x7D) + { KEY_F15, VK_F15 }, // (0x7E) + { KEY_F16, VK_F16 }, // (0x7F) + { KEY_NUMLOCK, VK_NUMLOCK }, // (0x90) + { KEY_SCROLLLOCK, VK_SCROLL }, // (0x91) + { KEY_SHIFT, VK_LSHIFT }, // (0xA0) + { KEY_SHIFT, VK_RSHIFT }, // (0xA1) + { KEY_CONTROL, VK_LCONTROL }, // (0xA2) + { KEY_CONTROL, VK_RCONTROL }, // (0xA3) + { KEY_MENU, VK_LMENU }, // (0xA4) + { KEY_MENU, VK_RMENU }, // (0xA5) + + { KEY_BACK, VK_BROWSER_BACK }, // (0xA6) + + { KEY_FORWARD, VK_BROWSER_FORWARD }, // (0xA7) + + { KEY_REFRESH, VK_BROWSER_REFRESH }, // (0xA8) + + { KEY_STOP, VK_BROWSER_STOP }, // (0xA9) + + { KEY_SEARCH, VK_BROWSER_SEARCH }, // (0xAA) + + { KEY_FAVORITES, VK_BROWSER_FAVORITES }, // (0xAB) + + { KEY_HOMEPAGE, VK_BROWSER_HOME }, // (0xAC) + + { KEY_VOLUMEMUTE, VK_VOLUME_MUTE }, // (0xAD) + + { KEY_VOLUMEDOWN, VK_VOLUME_DOWN }, // (0xAE) + + { KEY_VOLUMEUP, VK_VOLUME_UP }, // (0xAF) + + { KEY_MEDIANEXT, VK_MEDIA_NEXT_TRACK }, // (0xB0) + + { KEY_MEDIAPREVIOUS, VK_MEDIA_PREV_TRACK }, // (0xB1) + + { KEY_MEDIASTOP, VK_MEDIA_STOP }, // (0xB2) + + //VK_MEDIA_PLAY_PAUSE (0xB3) + + { KEY_LAUNCHMAIL, VK_LAUNCH_MAIL }, // (0xB4) + + { KEY_LAUNCHMEDIA, VK_LAUNCH_MEDIA_SELECT }, // (0xB5) + + { KEY_LAUNCH0, VK_LAUNCH_APP1 }, // (0xB6) + + { KEY_LAUNCH1, VK_LAUNCH_APP2 }, // (0xB7) + + { KEY_SEMICOLON, VK_OEM_1 }, // (0xBA) + + { KEY_EQUAL, VK_OEM_PLUS }, // (0xBB) // Windows 2000/XP: For any country/region, the '+' key + { KEY_COMMA, VK_OEM_COMMA }, // (0xBC) // Windows 2000/XP: For any country/region, the ',' key + { KEY_MINUS, VK_OEM_MINUS }, // (0xBD) // Windows 2000/XP: For any country/region, the '-' key + { KEY_PERIOD, VK_OEM_PERIOD }, // (0xBE) // Windows 2000/XP: For any country/region, the '.' key + { KEY_SLASH, VK_OEM_2 }, // (0xBF) //Windows 2000/XP: For the US standard keyboard, the '/?' key + + { KEY_QUOTELEFT, VK_OEM_3 }, // (0xC0) + { KEY_BRACELEFT, VK_OEM_4 }, // (0xDB) + { KEY_BACKSLASH, VK_OEM_5 }, // (0xDC) + { KEY_BRACERIGHT, VK_OEM_6 }, // (0xDD) + { KEY_APOSTROPHE, VK_OEM_7 }, // (0xDE) + /* +{VK_OEM_8 (0xDF) +{VK_OEM_102 (0xE2) // Windows 2000/XP: Either the angle bracket key or the backslash key on the RT 102-key keyboard +*/ + //{ KEY_PLAY, VK_PLAY},// (0xFA) + + { KEY_UNKNOWN, 0 } +}; + +/* +VK_ZOOM (0xFB) +VK_NONAME (0xFC) +VK_PA1 (0xFD) +VK_OEM_CLEAR (0xFE) +*/ + +unsigned int KeyMappingWindows::get_keysym(unsigned int p_code) { + + for (int i = 0; _vk_to_keycode[i].keysym != KEY_UNKNOWN; i++) { + + if (_vk_to_keycode[i].keycode == p_code) { + //printf("outcode: %x\n",_vk_to_keycode[i].keysym); + + return _vk_to_keycode[i].keysym; + } + } + + return KEY_UNKNOWN; +} diff --git a/platform/windows/key_mapping_windows.h b/platform/windows/key_mapping_windows.h new file mode 100644 index 0000000000..dbb8c20f1e --- /dev/null +++ b/platform/windows/key_mapping_windows.h @@ -0,0 +1,48 @@ +/*************************************************************************/ +/* key_mapping_windows.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef KEY_MAPPING_WINDOWS_H +#define KEY_MAPPING_WINDOWS_H + +#include "core/os/keyboard.h" + +#include + +#include + +class KeyMappingWindows { + + KeyMappingWindows(){}; + +public: + static unsigned int get_keysym(unsigned int p_code); +}; + +#endif // KEY_MAPPING_WINDOWS_H diff --git a/platform/windows/os_windows.cpp b/platform/windows/os_windows.cpp index 9ae1be9afd..3de33da8f5 100644 --- a/platform/windows/os_windows.cpp +++ b/platform/windows/os_windows.cpp @@ -43,15 +43,15 @@ #include "drivers/windows/rw_lock_windows.h" #include "drivers/windows/semaphore_windows.h" #include "drivers/windows/thread_windows.h" -#include "joypad.h" +#include "joypad_windows.h" #include "lang_table.h" #include "main/main.h" #include "servers/audio_server.h" #include "servers/visual/visual_server_raster.h" #include "servers/visual/visual_server_wrap_mt.h" #include "windows_terminal_logger.h" -#include +#include #include #include #include @@ -1273,7 +1273,7 @@ Error OS_Windows::initialize(const VideoMode &p_desired, int p_video_driver, int gl_context = NULL; while (!gl_context) { - gl_context = memnew(ContextGL_Win(hWnd, gles3_context)); + gl_context = memnew(ContextGL_Windows(hWnd, gles3_context)); if (gl_context->initialize() != OK) { memdelete(gl_context); diff --git a/platform/windows/os_windows.h b/platform/windows/os_windows.h index ba84c2098e..8ca58b534a 100644 --- a/platform/windows/os_windows.h +++ b/platform/windows/os_windows.h @@ -31,16 +31,16 @@ #ifndef OS_WINDOWS_H #define OS_WINDOWS_H -#include "context_gl_win.h" +#include "context_gl_windows.h" #include "core/os/input.h" #include "core/os/os.h" #include "core/project_settings.h" -#include "crash_handler_win.h" +#include "crash_handler_windows.h" #include "drivers/rtaudio/audio_driver_rtaudio.h" #include "drivers/unix/ip_unix.h" #include "drivers/wasapi/audio_driver_wasapi.h" #include "drivers/winmidi/midi_driver_winmidi.h" -#include "key_mapping_win.h" +#include "key_mapping_windows.h" #include "main/input_default.h" #include "power_windows.h" #include "servers/audio_server.h" @@ -87,7 +87,7 @@ class OS_Windows : public OS { int old_x, old_y; Point2i center; #if defined(OPENGL_ENABLED) - ContextGL_Win *gl_context; + ContextGL_Windows *gl_context; #endif VisualServer *visual_server; int pressrc; diff --git a/platform/windows/power_windows.h b/platform/windows/power_windows.h index 4d83d75e00..ef75ce6271 100644 --- a/platform/windows/power_windows.h +++ b/platform/windows/power_windows.h @@ -28,8 +28,8 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef PLATFORM_WINDOWS_POWER_WINDOWS_H_ -#define PLATFORM_WINDOWS_POWER_WINDOWS_H_ +#ifndef POWER_WINDOWS_H +#define POWER_WINDOWS_H #include "core/os/dir_access.h" #include "core/os/file_access.h" @@ -55,4 +55,4 @@ public: int get_power_percent_left(); }; -#endif /* PLATFORM_WINDOWS_POWER_WINDOWS_H_ */ +#endif // POWER_WINDOWS_H diff --git a/platform/x11/crash_handler_x11.cpp b/platform/x11/crash_handler_x11.cpp index 8737a2b92b..1e7f393bdd 100644 --- a/platform/x11/crash_handler_x11.cpp +++ b/platform/x11/crash_handler_x11.cpp @@ -28,15 +28,16 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifdef DEBUG_ENABLED -#define CRASH_HANDLER_ENABLED 1 -#endif - #include "crash_handler_x11.h" + #include "core/os/os.h" #include "core/project_settings.h" #include "main/main.h" +#ifdef DEBUG_ENABLED +#define CRASH_HANDLER_ENABLED 1 +#endif + #ifdef CRASH_HANDLER_ENABLED #include #include diff --git a/platform/x11/crash_handler_x11.h b/platform/x11/crash_handler_x11.h index 6efdd33d9d..d0664aef85 100644 --- a/platform/x11/crash_handler_x11.h +++ b/platform/x11/crash_handler_x11.h @@ -45,4 +45,4 @@ public: ~CrashHandler(); }; -#endif +#endif // CRASH_HANDLER_X11_H diff --git a/platform/x11/power_x11.h b/platform/x11/power_x11.h index 56fbd602f4..469e3910f4 100644 --- a/platform/x11/power_x11.h +++ b/platform/x11/power_x11.h @@ -28,8 +28,8 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef X11_POWER_H_ -#define X11_POWER_H_ +#ifndef POWER_X11_H +#define POWER_X11_H #include "core/os/dir_access.h" #include "core/os/file_access.h" @@ -63,4 +63,4 @@ public: int get_power_percent_left(); }; -#endif /* X11_POWER_H_ */ +#endif // POWER_X11_H -- cgit v1.2.3 From c5dcbeb160b37d8ffd70061d76eb980756fe36b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Verschelde?= Date: Tue, 12 Feb 2019 17:18:13 +0100 Subject: Scene: Ensure classes match their header filename Also drop some unused files. Renamed: - `scene/2d/navigation2d.h` -> `navigation_2d.h` - `scene/2d/screen_button.h` -> `touch_screen_button.h` - `scene/3d/scenario_fx.h` -> `world_environment.h` - `scene/audio/audio_player.h` -> `audio_stream_player.h` - `scene/resources/bit_mask.h` -> `bit_map.h` - `scene/resources/color_ramp.h` -> `gradient.h` - `scene/resources/shape_line_2d.h` -> `line_shape_2d.h` - `scene/resources/scene_format_text.h` -> `resource_format_text.h` - `scene/resources/sky_box.h` -> `sky.h` Dropped: - `scene/resources/bounds.h` --- editor/editor_export.cpp | 2 +- editor/import/resource_importer_bitmask.cpp | 2 +- editor/import/resource_importer_scene.cpp | 2 +- editor/plugins/audio_stream_editor_plugin.h | 2 +- editor/plugins/canvas_item_editor_plugin.cpp | 2 +- .../plugins/collision_shape_2d_editor_plugin.cpp | 2 +- editor/plugins/editor_preview_plugins.cpp | 2 +- modules/gdnative/nativescript/nativescript.cpp | 2 +- scene/2d/collision_shape_2d.cpp | 2 +- scene/2d/line_builder.h | 2 +- scene/2d/navigation2d.cpp | 739 -------- scene/2d/navigation2d.h | 174 -- scene/2d/navigation_2d.cpp | 739 ++++++++ scene/2d/navigation_2d.h | 174 ++ scene/2d/navigation_polygon.cpp | 2 +- scene/2d/screen_button.cpp | 423 ----- scene/2d/screen_button.h | 115 -- scene/2d/tile_map.h | 2 +- scene/2d/touch_screen_button.cpp | 424 +++++ scene/2d/touch_screen_button.h | 115 ++ scene/3d/SCsub | 2 +- scene/3d/reflection_probe.h | 2 +- scene/3d/scenario_fx.cpp | 112 -- scene/3d/scenario_fx.h | 59 - scene/3d/world_environment.cpp | 112 ++ scene/3d/world_environment.h | 59 + scene/audio/audio_player.cpp | 395 ----- scene/audio/audio_player.h | 113 -- scene/audio/audio_stream_player.cpp | 395 +++++ scene/audio/audio_stream_player.h | 114 ++ scene/gui/gradient_edit.h | 2 +- scene/gui/link_button.h | 2 +- scene/gui/texture_button.h | 2 +- scene/main/scene_tree.h | 1 - scene/main/viewport.cpp | 2 +- scene/register_scene_types.cpp | 18 +- scene/resources/bit_map.cpp | 625 +++++++ scene/resources/bit_map.h | 75 + scene/resources/bit_mask.cpp | 625 ------- scene/resources/bit_mask.h | 75 - scene/resources/bounds.cpp | 52 - scene/resources/bounds.h | 52 - scene/resources/color_ramp.cpp | 175 -- scene/resources/color_ramp.h | 129 -- scene/resources/environment.h | 2 +- scene/resources/gradient.cpp | 176 ++ scene/resources/gradient.h | 129 ++ scene/resources/line_shape_2d.cpp | 121 ++ scene/resources/line_shape_2d.h | 62 + scene/resources/resource_format_text.cpp | 1756 ++++++++++++++++++++ scene/resources/resource_format_text.h | 183 ++ scene/resources/scene_format_text.cpp | 1755 ------------------- scene/resources/scene_format_text.h | 183 -- scene/resources/shape_line_2d.cpp | 120 -- scene/resources/shape_line_2d.h | 62 - scene/resources/sky.cpp | 577 +++++++ scene/resources/sky.h | 200 +++ scene/resources/sky_box.cpp | 576 ------- scene/resources/sky_box.h | 199 --- scene/resources/texture.cpp | 2 +- scene/resources/texture.h | 2 +- 61 files changed, 6066 insertions(+), 6164 deletions(-) delete mode 100644 scene/2d/navigation2d.cpp delete mode 100644 scene/2d/navigation2d.h create mode 100644 scene/2d/navigation_2d.cpp create mode 100644 scene/2d/navigation_2d.h delete mode 100644 scene/2d/screen_button.cpp delete mode 100644 scene/2d/screen_button.h create mode 100644 scene/2d/touch_screen_button.cpp create mode 100644 scene/2d/touch_screen_button.h delete mode 100644 scene/3d/scenario_fx.cpp delete mode 100644 scene/3d/scenario_fx.h create mode 100644 scene/3d/world_environment.cpp create mode 100644 scene/3d/world_environment.h delete mode 100644 scene/audio/audio_player.cpp delete mode 100644 scene/audio/audio_player.h create mode 100644 scene/audio/audio_stream_player.cpp create mode 100644 scene/audio/audio_stream_player.h create mode 100644 scene/resources/bit_map.cpp create mode 100644 scene/resources/bit_map.h delete mode 100644 scene/resources/bit_mask.cpp delete mode 100644 scene/resources/bit_mask.h delete mode 100644 scene/resources/bounds.cpp delete mode 100644 scene/resources/bounds.h delete mode 100644 scene/resources/color_ramp.cpp delete mode 100644 scene/resources/color_ramp.h create mode 100644 scene/resources/gradient.cpp create mode 100644 scene/resources/gradient.h create mode 100644 scene/resources/line_shape_2d.cpp create mode 100644 scene/resources/line_shape_2d.h create mode 100644 scene/resources/resource_format_text.cpp create mode 100644 scene/resources/resource_format_text.h delete mode 100644 scene/resources/scene_format_text.cpp delete mode 100644 scene/resources/scene_format_text.h delete mode 100644 scene/resources/shape_line_2d.cpp delete mode 100644 scene/resources/shape_line_2d.h create mode 100644 scene/resources/sky.cpp create mode 100644 scene/resources/sky.h delete mode 100644 scene/resources/sky_box.cpp delete mode 100644 scene/resources/sky_box.h diff --git a/editor/editor_export.cpp b/editor/editor_export.cpp index 7c99318dca..4e8b2c82f1 100644 --- a/editor/editor_export.cpp +++ b/editor/editor_export.cpp @@ -42,7 +42,7 @@ #include "editor/plugins/script_editor_plugin.h" #include "editor_node.h" #include "editor_settings.h" -#include "scene/resources/scene_format_text.h" +#include "scene/resources/resource_format_text.h" #include "thirdparty/misc/md5.h" static int _get_pad(int p_alignment, int p_n) { diff --git a/editor/import/resource_importer_bitmask.cpp b/editor/import/resource_importer_bitmask.cpp index 431396d584..b568cbda9b 100644 --- a/editor/import/resource_importer_bitmask.cpp +++ b/editor/import/resource_importer_bitmask.cpp @@ -34,7 +34,7 @@ #include "core/io/image_loader.h" #include "editor/editor_file_system.h" #include "editor/editor_node.h" -#include "scene/resources/bit_mask.h" +#include "scene/resources/bit_map.h" #include "scene/resources/texture.h" String ResourceImporterBitMap::get_importer_name() const { diff --git a/editor/import/resource_importer_scene.cpp b/editor/import/resource_importer_scene.cpp index f230fa1b8b..2616ba6e87 100644 --- a/editor/import/resource_importer_scene.cpp +++ b/editor/import/resource_importer_scene.cpp @@ -46,7 +46,7 @@ #include "scene/resources/box_shape.h" #include "scene/resources/plane_shape.h" #include "scene/resources/ray_shape.h" -#include "scene/resources/scene_format_text.h" +#include "scene/resources/resource_format_text.h" #include "scene/resources/sphere_shape.h" uint32_t EditorSceneImporter::get_import_flags() const { diff --git a/editor/plugins/audio_stream_editor_plugin.h b/editor/plugins/audio_stream_editor_plugin.h index e60bf6a38f..12e4faef94 100644 --- a/editor/plugins/audio_stream_editor_plugin.h +++ b/editor/plugins/audio_stream_editor_plugin.h @@ -33,7 +33,7 @@ #include "editor/editor_node.h" #include "editor/editor_plugin.h" -#include "scene/audio/audio_player.h" +#include "scene/audio/audio_stream_player.h" #include "scene/gui/color_rect.h" #include "scene/resources/texture.h" diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp index 98d639a2d3..873bdd9e7f 100644 --- a/editor/plugins/canvas_item_editor_plugin.cpp +++ b/editor/plugins/canvas_item_editor_plugin.cpp @@ -42,9 +42,9 @@ #include "scene/2d/light_2d.h" #include "scene/2d/particles_2d.h" #include "scene/2d/polygon_2d.h" -#include "scene/2d/screen_button.h" #include "scene/2d/skeleton_2d.h" #include "scene/2d/sprite.h" +#include "scene/2d/touch_screen_button.h" #include "scene/gui/grid_container.h" #include "scene/gui/nine_patch_rect.h" #include "scene/main/canvas_layer.h" diff --git a/editor/plugins/collision_shape_2d_editor_plugin.cpp b/editor/plugins/collision_shape_2d_editor_plugin.cpp index fc572f54e1..10023d88bf 100644 --- a/editor/plugins/collision_shape_2d_editor_plugin.cpp +++ b/editor/plugins/collision_shape_2d_editor_plugin.cpp @@ -35,9 +35,9 @@ #include "scene/resources/circle_shape_2d.h" #include "scene/resources/concave_polygon_shape_2d.h" #include "scene/resources/convex_polygon_shape_2d.h" +#include "scene/resources/line_shape_2d.h" #include "scene/resources/rectangle_shape_2d.h" #include "scene/resources/segment_shape_2d.h" -#include "scene/resources/shape_line_2d.h" Variant CollisionShape2DEditor::get_handle_value(int idx) const { diff --git a/editor/plugins/editor_preview_plugins.cpp b/editor/plugins/editor_preview_plugins.cpp index 0c0cc9d635..071a0287e6 100644 --- a/editor/plugins/editor_preview_plugins.cpp +++ b/editor/plugins/editor_preview_plugins.cpp @@ -36,7 +36,7 @@ #include "editor/editor_node.h" #include "editor/editor_scale.h" #include "editor/editor_settings.h" -#include "scene/resources/bit_mask.h" +#include "scene/resources/bit_map.h" #include "scene/resources/dynamic_font.h" #include "scene/resources/material.h" #include "scene/resources/mesh.h" diff --git a/modules/gdnative/nativescript/nativescript.cpp b/modules/gdnative/nativescript/nativescript.cpp index 0370060937..9fd0a2e8ec 100644 --- a/modules/gdnative/nativescript/nativescript.cpp +++ b/modules/gdnative/nativescript/nativescript.cpp @@ -39,7 +39,7 @@ #include "core/project_settings.h" #include "scene/main/scene_tree.h" -#include "scene/resources/scene_format_text.h" +#include "scene/resources/resource_format_text.h" #include diff --git a/scene/2d/collision_shape_2d.cpp b/scene/2d/collision_shape_2d.cpp index c756f49bbd..5440a1d8c3 100644 --- a/scene/2d/collision_shape_2d.cpp +++ b/scene/2d/collision_shape_2d.cpp @@ -36,9 +36,9 @@ #include "scene/resources/circle_shape_2d.h" #include "scene/resources/concave_polygon_shape_2d.h" #include "scene/resources/convex_polygon_shape_2d.h" +#include "scene/resources/line_shape_2d.h" #include "scene/resources/rectangle_shape_2d.h" #include "scene/resources/segment_shape_2d.h" -#include "scene/resources/shape_line_2d.h" void CollisionShape2D::_shape_changed() { diff --git a/scene/2d/line_builder.h b/scene/2d/line_builder.h index 2ca28d09c4..b961385e33 100644 --- a/scene/2d/line_builder.h +++ b/scene/2d/line_builder.h @@ -34,7 +34,7 @@ #include "core/color.h" #include "core/math/vector2.h" #include "line_2d.h" -#include "scene/resources/color_ramp.h" +#include "scene/resources/gradient.h" class LineBuilder { public: diff --git a/scene/2d/navigation2d.cpp b/scene/2d/navigation2d.cpp deleted file mode 100644 index 1c0e924433..0000000000 --- a/scene/2d/navigation2d.cpp +++ /dev/null @@ -1,739 +0,0 @@ -/*************************************************************************/ -/* navigation2d.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#include "navigation2d.h" - -#define USE_ENTRY_POINT - -void Navigation2D::_navpoly_link(int p_id) { - - ERR_FAIL_COND(!navpoly_map.has(p_id)); - NavMesh &nm = navpoly_map[p_id]; - ERR_FAIL_COND(nm.linked); - - PoolVector vertices = nm.navpoly->get_vertices(); - int len = vertices.size(); - if (len == 0) - return; - - PoolVector::Read r = vertices.read(); - - for (int i = 0; i < nm.navpoly->get_polygon_count(); i++) { - - //build - - List::Element *P = nm.polygons.push_back(Polygon()); - Polygon &p = P->get(); - p.owner = &nm; - - Vector poly = nm.navpoly->get_polygon(i); - int plen = poly.size(); - const int *indices = poly.ptr(); - bool valid = true; - p.edges.resize(plen); - - Vector2 center; - float sum = 0; - - for (int j = 0; j < plen; j++) { - - int idx = indices[j]; - if (idx < 0 || idx >= len) { - valid = false; - break; - } - - Polygon::Edge e; - Vector2 ep = nm.xform.xform(r[idx]); - center += ep; - e.point = _get_point(ep); - p.edges.write[j] = e; - - int idxn = indices[(j + 1) % plen]; - if (idxn < 0 || idxn >= len) { - valid = false; - break; - } - - Vector2 epn = nm.xform.xform(r[idxn]); - - sum += (epn.x - ep.x) * (epn.y + ep.y); - } - - p.clockwise = sum > 0; - - if (!valid) { - nm.polygons.pop_back(); - ERR_CONTINUE(!valid); - continue; - } - - p.center = center / plen; - - //connect - - for (int j = 0; j < plen; j++) { - - int next = (j + 1) % plen; - EdgeKey ek(p.edges[j].point, p.edges[next].point); - - Map::Element *C = connections.find(ek); - if (!C) { - - Connection c; - c.A = &p; - c.A_edge = j; - c.B = NULL; - c.B_edge = -1; - connections[ek] = c; - } else { - - if (C->get().B != NULL) { - ConnectionPending pending; - pending.polygon = &p; - pending.edge = j; - p.edges.write[j].P = C->get().pending.push_back(pending); - continue; - } - - C->get().B = &p; - C->get().B_edge = j; - C->get().A->edges.write[C->get().A_edge].C = &p; - C->get().A->edges.write[C->get().A_edge].C_edge = j; - p.edges.write[j].C = C->get().A; - p.edges.write[j].C_edge = C->get().A_edge; - //connection successful. - } - } - } - - nm.linked = true; -} - -void Navigation2D::_navpoly_unlink(int p_id) { - - ERR_FAIL_COND(!navpoly_map.has(p_id)); - NavMesh &nm = navpoly_map[p_id]; - ERR_FAIL_COND(!nm.linked); - - for (List::Element *E = nm.polygons.front(); E; E = E->next()) { - - Polygon &p = E->get(); - - int ec = p.edges.size(); - Polygon::Edge *edges = p.edges.ptrw(); - - for (int i = 0; i < ec; i++) { - int next = (i + 1) % ec; - - EdgeKey ek(edges[i].point, edges[next].point); - Map::Element *C = connections.find(ek); - ERR_CONTINUE(!C); - - if (edges[i].P) { - C->get().pending.erase(edges[i].P); - edges[i].P = NULL; - - } else if (C->get().B) { - //disconnect - - C->get().B->edges.write[C->get().B_edge].C = NULL; - C->get().B->edges.write[C->get().B_edge].C_edge = -1; - C->get().A->edges.write[C->get().A_edge].C = NULL; - C->get().A->edges.write[C->get().A_edge].C_edge = -1; - - if (C->get().A == &E->get()) { - - C->get().A = C->get().B; - C->get().A_edge = C->get().B_edge; - } - C->get().B = NULL; - C->get().B_edge = -1; - - if (C->get().pending.size()) { - //reconnect if something is pending - ConnectionPending cp = C->get().pending.front()->get(); - C->get().pending.pop_front(); - - C->get().B = cp.polygon; - C->get().B_edge = cp.edge; - C->get().A->edges.write[C->get().A_edge].C = cp.polygon; - C->get().A->edges.write[C->get().A_edge].C_edge = cp.edge; - cp.polygon->edges.write[cp.edge].C = C->get().A; - cp.polygon->edges.write[cp.edge].C_edge = C->get().A_edge; - cp.polygon->edges.write[cp.edge].P = NULL; - } - - } else { - connections.erase(C); - //erase - } - } - } - - nm.polygons.clear(); - - nm.linked = false; -} - -int Navigation2D::navpoly_add(const Ref &p_mesh, const Transform2D &p_xform, Object *p_owner) { - - int id = last_id++; - NavMesh nm; - nm.linked = false; - nm.navpoly = p_mesh; - nm.xform = p_xform; - nm.owner = p_owner; - navpoly_map[id] = nm; - - _navpoly_link(id); - - return id; -} - -void Navigation2D::navpoly_set_transform(int p_id, const Transform2D &p_xform) { - - ERR_FAIL_COND(!navpoly_map.has(p_id)); - NavMesh &nm = navpoly_map[p_id]; - if (nm.xform == p_xform) - return; //bleh - _navpoly_unlink(p_id); - nm.xform = p_xform; - _navpoly_link(p_id); -} -void Navigation2D::navpoly_remove(int p_id) { - - ERR_FAIL_COND(!navpoly_map.has(p_id)); - _navpoly_unlink(p_id); - navpoly_map.erase(p_id); -} - -Vector Navigation2D::get_simple_path(const Vector2 &p_start, const Vector2 &p_end, bool p_optimize) { - - Polygon *begin_poly = NULL; - Polygon *end_poly = NULL; - Vector2 begin_point; - Vector2 end_point; - float begin_d = 1e20; - float end_d = 1e20; - - //look for point inside triangle - - for (Map::Element *E = navpoly_map.front(); E; E = E->next()) { - - if (!E->get().linked) - continue; - for (List::Element *F = E->get().polygons.front(); F; F = F->next()) { - - Polygon &p = F->get(); - if (begin_d || end_d) { - for (int i = 2; i < p.edges.size(); i++) { - - if (begin_d > 0) { - - if (Geometry::is_point_in_triangle(p_start, _get_vertex(p.edges[0].point), _get_vertex(p.edges[i - 1].point), _get_vertex(p.edges[i].point))) { - - begin_poly = &p; - begin_point = p_start; - begin_d = 0; - if (end_d == 0) - break; - } - } - - if (end_d > 0) { - - if (Geometry::is_point_in_triangle(p_end, _get_vertex(p.edges[0].point), _get_vertex(p.edges[i - 1].point), _get_vertex(p.edges[i].point))) { - - end_poly = &p; - end_point = p_end; - end_d = 0; - if (begin_d == 0) - break; - } - } - } - } - - p.prev_edge = -1; - } - } - - //start or end not inside triangle.. look for closest segment :| - if (begin_d || end_d) { - for (Map::Element *E = navpoly_map.front(); E; E = E->next()) { - - if (!E->get().linked) - continue; - for (List::Element *F = E->get().polygons.front(); F; F = F->next()) { - - Polygon &p = F->get(); - int es = p.edges.size(); - for (int i = 0; i < es; i++) { - - Vector2 edge[2] = { - _get_vertex(p.edges[i].point), - _get_vertex(p.edges[(i + 1) % es].point) - }; - - if (begin_d > 0) { - Vector2 spoint = Geometry::get_closest_point_to_segment_2d(p_start, edge); - float d = spoint.distance_to(p_start); - if (d < begin_d) { - begin_poly = &p; - begin_point = spoint; - begin_d = d; - } - } - - if (end_d > 0) { - Vector2 spoint = Geometry::get_closest_point_to_segment_2d(p_end, edge); - float d = spoint.distance_to(p_end); - if (d < end_d) { - end_poly = &p; - end_point = spoint; - end_d = d; - } - } - } - } - } - } - - if (!begin_poly || !end_poly) { - - return Vector(); //no path - } - - if (begin_poly == end_poly) { - - Vector path; - path.resize(2); - path.write[0] = begin_point; - path.write[1] = end_point; - return path; - } - - bool found_route = false; - - List open_list; - - begin_poly->entry = p_start; - - for (int i = 0; i < begin_poly->edges.size(); i++) { - - if (begin_poly->edges[i].C) { - - begin_poly->edges[i].C->prev_edge = begin_poly->edges[i].C_edge; -#ifdef USE_ENTRY_POINT - Vector2 edge[2] = { - _get_vertex(begin_poly->edges[i].point), - _get_vertex(begin_poly->edges[(i + 1) % begin_poly->edges.size()].point) - }; - - Vector2 entry = Geometry::get_closest_point_to_segment_2d(begin_poly->entry, edge); - begin_poly->edges[i].C->distance = begin_poly->entry.distance_to(entry); - begin_poly->edges[i].C->entry = entry; -#else - begin_poly->edges[i].C->distance = begin_poly->center.distance_to(begin_poly->edges[i].C->center); -#endif - open_list.push_back(begin_poly->edges[i].C); - - if (begin_poly->edges[i].C == end_poly) { - found_route = true; - } - } - } - - while (!found_route) { - - if (open_list.size() == 0) { - break; - } - //check open list - - List::Element *least_cost_poly = NULL; - float least_cost = 1e30; - - //this could be faster (cache previous results) - for (List::Element *E = open_list.front(); E; E = E->next()) { - - Polygon *p = E->get(); - - float cost = p->distance; - -#ifdef USE_ENTRY_POINT - int es = p->edges.size(); - - float shortest_distance = 1e30; - - for (int i = 0; i < es; i++) { - Polygon::Edge &e = p->edges.write[i]; - - if (!e.C) - continue; - - Vector2 edge[2] = { - _get_vertex(p->edges[i].point), - _get_vertex(p->edges[(i + 1) % es].point) - }; - - Vector2 edge_point = Geometry::get_closest_point_to_segment_2d(p->entry, edge); - float dist = p->entry.distance_to(edge_point); - if (dist < shortest_distance) - shortest_distance = dist; - } - - cost += shortest_distance; -#else - cost += p->center.distance_to(end_point); -#endif - if (cost < least_cost) { - least_cost_poly = E; - least_cost = cost; - } - } - - Polygon *p = least_cost_poly->get(); - //open the neighbours for search - int es = p->edges.size(); - - for (int i = 0; i < es; i++) { - - Polygon::Edge &e = p->edges.write[i]; - - if (!e.C) - continue; - -#ifdef USE_ENTRY_POINT - Vector2 edge[2] = { - _get_vertex(p->edges[i].point), - _get_vertex(p->edges[(i + 1) % es].point) - }; - - Vector2 edge_entry = Geometry::get_closest_point_to_segment_2d(p->entry, edge); - float distance = p->entry.distance_to(edge_entry) + p->distance; - -#else - - float distance = p->center.distance_to(e.C->center) + p->distance; - -#endif - - if (e.C->prev_edge != -1) { - //oh this was visited already, can we win the cost? - - if (e.C->distance > distance) { - - e.C->prev_edge = e.C_edge; - e.C->distance = distance; -#ifdef USE_ENTRY_POINT - e.C->entry = edge_entry; -#endif - } - } else { - //add to open neighbours - - e.C->prev_edge = e.C_edge; - e.C->distance = distance; -#ifdef USE_ENTRY_POINT - e.C->entry = edge_entry; -#endif - - open_list.push_back(e.C); - - if (e.C == end_poly) { - //oh my reached end! stop algorithm - found_route = true; - break; - } - } - } - - if (found_route) - break; - - open_list.erase(least_cost_poly); - } - - if (found_route) { - - Vector path; - - if (p_optimize) { - //string pulling - - Vector2 apex_point = end_point; - Vector2 portal_left = apex_point; - Vector2 portal_right = apex_point; - Polygon *left_poly = end_poly; - Polygon *right_poly = end_poly; - Polygon *p = end_poly; - - while (p) { - - Vector2 left; - Vector2 right; - -//#define CLOCK_TANGENT(m_a,m_b,m_c) ( ((m_a)-(m_c)).cross((m_a)-(m_b)) ) -#define CLOCK_TANGENT(m_a, m_b, m_c) ((((m_a).x - (m_c).x) * ((m_b).y - (m_c).y) - ((m_b).x - (m_c).x) * ((m_a).y - (m_c).y))) - - if (p == begin_poly) { - left = begin_point; - right = begin_point; - } else { - int prev = p->prev_edge; - int prev_n = (p->prev_edge + 1) % p->edges.size(); - left = _get_vertex(p->edges[prev].point); - right = _get_vertex(p->edges[prev_n].point); - - if (p->clockwise) { - SWAP(left, right); - } - /*if (CLOCK_TANGENT(apex_point,left,(left+right)*0.5) < 0){ - SWAP(left,right); - }*/ - } - - bool skip = false; - - /* - print_line("-----\nAPEX: "+(apex_point-end_point)); - print_line("LEFT:"); - print_line("\tPortal: "+(portal_left-end_point)); - print_line("\tPoint: "+(left-end_point)); - print_line("\tLeft Tangent: "+rtos(CLOCK_TANGENT(apex_point,portal_left,left))); - print_line("\tLeft Distance: "+rtos(portal_left.distance_squared_to(apex_point))); - print_line("\tLeft Test: "+rtos(CLOCK_TANGENT(apex_point,left,portal_right))); - print_line("RIGHT:"); - print_line("\tPortal: "+(portal_right-end_point)); - print_line("\tPoint: "+(right-end_point)); - print_line("\tRight Tangent: "+rtos(CLOCK_TANGENT(apex_point,portal_right,right))); - print_line("\tRight Distance: "+rtos(portal_right.distance_squared_to(apex_point))); - print_line("\tRight Test: "+rtos(CLOCK_TANGENT(apex_point,right,portal_left))); - */ - - if (CLOCK_TANGENT(apex_point, portal_left, left) >= 0) { - //process - if (portal_left.distance_squared_to(apex_point) < CMP_EPSILON || CLOCK_TANGENT(apex_point, left, portal_right) > 0) { - left_poly = p; - portal_left = left; - } else { - - apex_point = portal_right; - p = right_poly; - left_poly = p; - portal_left = apex_point; - portal_right = apex_point; - if (!path.size() || path[path.size() - 1].distance_to(apex_point) > CMP_EPSILON) - path.push_back(apex_point); - skip = true; - } - } - - if (!skip && CLOCK_TANGENT(apex_point, portal_right, right) <= 0) { - //process - if (portal_right.distance_squared_to(apex_point) < CMP_EPSILON || CLOCK_TANGENT(apex_point, right, portal_left) < 0) { - right_poly = p; - portal_right = right; - } else { - - apex_point = portal_left; - p = left_poly; - right_poly = p; - portal_right = apex_point; - portal_left = apex_point; - if (!path.size() || path[path.size() - 1].distance_to(apex_point) > CMP_EPSILON) - path.push_back(apex_point); - } - } - - if (p != begin_poly) - p = p->edges[p->prev_edge].C; - else - p = NULL; - } - - } else { - //midpoints - Polygon *p = end_poly; - - while (true) { - int prev = p->prev_edge; - int prev_n = (p->prev_edge + 1) % p->edges.size(); - Vector2 point = (_get_vertex(p->edges[prev].point) + _get_vertex(p->edges[prev_n].point)) * 0.5; - path.push_back(point); - p = p->edges[prev].C; - if (p == begin_poly) - break; - } - } - - if (!path.size() || path[path.size() - 1].distance_squared_to(begin_point) > CMP_EPSILON) { - path.push_back(begin_point); // Add the begin point - } else { - path.write[path.size() - 1] = begin_point; // Replace first midpoint by the exact begin point - } - - path.invert(); - - if (path.size() <= 1 || path[path.size() - 1].distance_squared_to(end_point) > CMP_EPSILON) { - path.push_back(end_point); // Add the end point - } else { - path.write[path.size() - 1] = end_point; // Replace last midpoint by the exact end point - } - - return path; - } - - return Vector(); -} - -Vector2 Navigation2D::get_closest_point(const Vector2 &p_point) { - - Vector2 closest_point = Vector2(); - float closest_point_d = 1e20; - - for (Map::Element *E = navpoly_map.front(); E; E = E->next()) { - - if (!E->get().linked) - continue; - for (List::Element *F = E->get().polygons.front(); F; F = F->next()) { - - Polygon &p = F->get(); - for (int i = 2; i < p.edges.size(); i++) { - - if (Geometry::is_point_in_triangle(p_point, _get_vertex(p.edges[0].point), _get_vertex(p.edges[i - 1].point), _get_vertex(p.edges[i].point))) { - - return p_point; //inside triangle, nothing else to discuss - } - } - } - } - - for (Map::Element *E = navpoly_map.front(); E; E = E->next()) { - - if (!E->get().linked) - continue; - for (List::Element *F = E->get().polygons.front(); F; F = F->next()) { - - Polygon &p = F->get(); - int es = p.edges.size(); - for (int i = 0; i < es; i++) { - - Vector2 edge[2] = { - _get_vertex(p.edges[i].point), - _get_vertex(p.edges[(i + 1) % es].point) - }; - - Vector2 spoint = Geometry::get_closest_point_to_segment_2d(p_point, edge); - float d = spoint.distance_squared_to(p_point); - if (d < closest_point_d) { - - closest_point = spoint; - closest_point_d = d; - } - } - } - } - - return closest_point; -} - -Object *Navigation2D::get_closest_point_owner(const Vector2 &p_point) { - - Object *owner = NULL; - Vector2 closest_point = Vector2(); - float closest_point_d = 1e20; - - for (Map::Element *E = navpoly_map.front(); E; E = E->next()) { - - if (!E->get().linked) - continue; - for (List::Element *F = E->get().polygons.front(); F; F = F->next()) { - - Polygon &p = F->get(); - for (int i = 2; i < p.edges.size(); i++) { - - if (Geometry::is_point_in_triangle(p_point, _get_vertex(p.edges[0].point), _get_vertex(p.edges[i - 1].point), _get_vertex(p.edges[i].point))) { - - return E->get().owner; - } - } - } - } - - for (Map::Element *E = navpoly_map.front(); E; E = E->next()) { - - if (!E->get().linked) - continue; - for (List::Element *F = E->get().polygons.front(); F; F = F->next()) { - - Polygon &p = F->get(); - int es = p.edges.size(); - for (int i = 0; i < es; i++) { - - Vector2 edge[2] = { - _get_vertex(p.edges[i].point), - _get_vertex(p.edges[(i + 1) % es].point) - }; - - Vector2 spoint = Geometry::get_closest_point_to_segment_2d(p_point, edge); - float d = spoint.distance_squared_to(p_point); - if (d < closest_point_d) { - - closest_point = spoint; - closest_point_d = d; - owner = E->get().owner; - } - } - } - } - - return owner; -} - -void Navigation2D::_bind_methods() { - - ClassDB::bind_method(D_METHOD("navpoly_add", "mesh", "xform", "owner"), &Navigation2D::navpoly_add, DEFVAL(Variant())); - ClassDB::bind_method(D_METHOD("navpoly_set_transform", "id", "xform"), &Navigation2D::navpoly_set_transform); - ClassDB::bind_method(D_METHOD("navpoly_remove", "id"), &Navigation2D::navpoly_remove); - - ClassDB::bind_method(D_METHOD("get_simple_path", "start", "end", "optimize"), &Navigation2D::get_simple_path, DEFVAL(true)); - ClassDB::bind_method(D_METHOD("get_closest_point", "to_point"), &Navigation2D::get_closest_point); - ClassDB::bind_method(D_METHOD("get_closest_point_owner", "to_point"), &Navigation2D::get_closest_point_owner); -} - -Navigation2D::Navigation2D() { - - ERR_FAIL_COND(sizeof(Point) != 8); - cell_size = 1; // one pixel - last_id = 1; -} diff --git a/scene/2d/navigation2d.h b/scene/2d/navigation2d.h deleted file mode 100644 index fc1762221c..0000000000 --- a/scene/2d/navigation2d.h +++ /dev/null @@ -1,174 +0,0 @@ -/*************************************************************************/ -/* navigation2d.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#ifndef NAVIGATION_2D_H -#define NAVIGATION_2D_H - -#include "scene/2d/navigation_polygon.h" -#include "scene/2d/node_2d.h" - -class Navigation2D : public Node2D { - - GDCLASS(Navigation2D, Node2D); - - union Point { - - struct { - int64_t x : 32; - int64_t y : 32; - }; - - uint64_t key; - bool operator<(const Point &p_key) const { return key < p_key.key; } - }; - - struct EdgeKey { - - Point a; - Point b; - - bool operator<(const EdgeKey &p_key) const { - return (a.key == p_key.a.key) ? (b.key < p_key.b.key) : (a.key < p_key.a.key); - }; - - EdgeKey(const Point &p_a = Point(), const Point &p_b = Point()) : - a(p_a), - b(p_b) { - if (a.key > b.key) { - SWAP(a, b); - } - } - }; - - struct NavMesh; - struct Polygon; - - struct ConnectionPending { - - Polygon *polygon; - int edge; - }; - - struct Polygon { - - struct Edge { - Point point; - Polygon *C; //connection - int C_edge; - List::Element *P; - Edge() { - C = NULL; - C_edge = -1; - P = NULL; - } - }; - - Vector edges; - - Vector2 center; - Vector2 entry; - - float distance; - int prev_edge; - - bool clockwise; - - NavMesh *owner; - }; - - struct Connection { - - Polygon *A; - int A_edge; - Polygon *B; - int B_edge; - - List pending; - - Connection() { - A = NULL; - B = NULL; - A_edge = -1; - B_edge = -1; - } - }; - - Map connections; - - struct NavMesh { - - Object *owner; - Transform2D xform; - bool linked; - Ref navpoly; - List polygons; - }; - - _FORCE_INLINE_ Point _get_point(const Vector2 &p_pos) const { - - int x = int(Math::floor(p_pos.x / cell_size)); - int y = int(Math::floor(p_pos.y / cell_size)); - - Point p; - p.key = 0; - p.x = x; - p.y = y; - return p; - } - - _FORCE_INLINE_ Vector2 _get_vertex(const Point &p_point) const { - - return Vector2(p_point.x, p_point.y) * cell_size; - } - - void _navpoly_link(int p_id); - void _navpoly_unlink(int p_id); - - float cell_size; - Map navpoly_map; - int last_id; - -protected: - static void _bind_methods(); - -public: - //API should be as dynamic as possible - int navpoly_add(const Ref &p_mesh, const Transform2D &p_xform, Object *p_owner = NULL); - void navpoly_set_transform(int p_id, const Transform2D &p_xform); - void navpoly_remove(int p_id); - - Vector get_simple_path(const Vector2 &p_start, const Vector2 &p_end, bool p_optimize = true); - Vector2 get_closest_point(const Vector2 &p_point); - Object *get_closest_point_owner(const Vector2 &p_point); - - Navigation2D(); -}; - -#endif // Navigation2D2D_H diff --git a/scene/2d/navigation_2d.cpp b/scene/2d/navigation_2d.cpp new file mode 100644 index 0000000000..57e0a5b118 --- /dev/null +++ b/scene/2d/navigation_2d.cpp @@ -0,0 +1,739 @@ +/*************************************************************************/ +/* navigation_2d.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "navigation_2d.h" + +#define USE_ENTRY_POINT + +void Navigation2D::_navpoly_link(int p_id) { + + ERR_FAIL_COND(!navpoly_map.has(p_id)); + NavMesh &nm = navpoly_map[p_id]; + ERR_FAIL_COND(nm.linked); + + PoolVector vertices = nm.navpoly->get_vertices(); + int len = vertices.size(); + if (len == 0) + return; + + PoolVector::Read r = vertices.read(); + + for (int i = 0; i < nm.navpoly->get_polygon_count(); i++) { + + //build + + List::Element *P = nm.polygons.push_back(Polygon()); + Polygon &p = P->get(); + p.owner = &nm; + + Vector poly = nm.navpoly->get_polygon(i); + int plen = poly.size(); + const int *indices = poly.ptr(); + bool valid = true; + p.edges.resize(plen); + + Vector2 center; + float sum = 0; + + for (int j = 0; j < plen; j++) { + + int idx = indices[j]; + if (idx < 0 || idx >= len) { + valid = false; + break; + } + + Polygon::Edge e; + Vector2 ep = nm.xform.xform(r[idx]); + center += ep; + e.point = _get_point(ep); + p.edges.write[j] = e; + + int idxn = indices[(j + 1) % plen]; + if (idxn < 0 || idxn >= len) { + valid = false; + break; + } + + Vector2 epn = nm.xform.xform(r[idxn]); + + sum += (epn.x - ep.x) * (epn.y + ep.y); + } + + p.clockwise = sum > 0; + + if (!valid) { + nm.polygons.pop_back(); + ERR_CONTINUE(!valid); + continue; + } + + p.center = center / plen; + + //connect + + for (int j = 0; j < plen; j++) { + + int next = (j + 1) % plen; + EdgeKey ek(p.edges[j].point, p.edges[next].point); + + Map::Element *C = connections.find(ek); + if (!C) { + + Connection c; + c.A = &p; + c.A_edge = j; + c.B = NULL; + c.B_edge = -1; + connections[ek] = c; + } else { + + if (C->get().B != NULL) { + ConnectionPending pending; + pending.polygon = &p; + pending.edge = j; + p.edges.write[j].P = C->get().pending.push_back(pending); + continue; + } + + C->get().B = &p; + C->get().B_edge = j; + C->get().A->edges.write[C->get().A_edge].C = &p; + C->get().A->edges.write[C->get().A_edge].C_edge = j; + p.edges.write[j].C = C->get().A; + p.edges.write[j].C_edge = C->get().A_edge; + //connection successful. + } + } + } + + nm.linked = true; +} + +void Navigation2D::_navpoly_unlink(int p_id) { + + ERR_FAIL_COND(!navpoly_map.has(p_id)); + NavMesh &nm = navpoly_map[p_id]; + ERR_FAIL_COND(!nm.linked); + + for (List::Element *E = nm.polygons.front(); E; E = E->next()) { + + Polygon &p = E->get(); + + int ec = p.edges.size(); + Polygon::Edge *edges = p.edges.ptrw(); + + for (int i = 0; i < ec; i++) { + int next = (i + 1) % ec; + + EdgeKey ek(edges[i].point, edges[next].point); + Map::Element *C = connections.find(ek); + ERR_CONTINUE(!C); + + if (edges[i].P) { + C->get().pending.erase(edges[i].P); + edges[i].P = NULL; + + } else if (C->get().B) { + //disconnect + + C->get().B->edges.write[C->get().B_edge].C = NULL; + C->get().B->edges.write[C->get().B_edge].C_edge = -1; + C->get().A->edges.write[C->get().A_edge].C = NULL; + C->get().A->edges.write[C->get().A_edge].C_edge = -1; + + if (C->get().A == &E->get()) { + + C->get().A = C->get().B; + C->get().A_edge = C->get().B_edge; + } + C->get().B = NULL; + C->get().B_edge = -1; + + if (C->get().pending.size()) { + //reconnect if something is pending + ConnectionPending cp = C->get().pending.front()->get(); + C->get().pending.pop_front(); + + C->get().B = cp.polygon; + C->get().B_edge = cp.edge; + C->get().A->edges.write[C->get().A_edge].C = cp.polygon; + C->get().A->edges.write[C->get().A_edge].C_edge = cp.edge; + cp.polygon->edges.write[cp.edge].C = C->get().A; + cp.polygon->edges.write[cp.edge].C_edge = C->get().A_edge; + cp.polygon->edges.write[cp.edge].P = NULL; + } + + } else { + connections.erase(C); + //erase + } + } + } + + nm.polygons.clear(); + + nm.linked = false; +} + +int Navigation2D::navpoly_add(const Ref &p_mesh, const Transform2D &p_xform, Object *p_owner) { + + int id = last_id++; + NavMesh nm; + nm.linked = false; + nm.navpoly = p_mesh; + nm.xform = p_xform; + nm.owner = p_owner; + navpoly_map[id] = nm; + + _navpoly_link(id); + + return id; +} + +void Navigation2D::navpoly_set_transform(int p_id, const Transform2D &p_xform) { + + ERR_FAIL_COND(!navpoly_map.has(p_id)); + NavMesh &nm = navpoly_map[p_id]; + if (nm.xform == p_xform) + return; //bleh + _navpoly_unlink(p_id); + nm.xform = p_xform; + _navpoly_link(p_id); +} +void Navigation2D::navpoly_remove(int p_id) { + + ERR_FAIL_COND(!navpoly_map.has(p_id)); + _navpoly_unlink(p_id); + navpoly_map.erase(p_id); +} + +Vector Navigation2D::get_simple_path(const Vector2 &p_start, const Vector2 &p_end, bool p_optimize) { + + Polygon *begin_poly = NULL; + Polygon *end_poly = NULL; + Vector2 begin_point; + Vector2 end_point; + float begin_d = 1e20; + float end_d = 1e20; + + //look for point inside triangle + + for (Map::Element *E = navpoly_map.front(); E; E = E->next()) { + + if (!E->get().linked) + continue; + for (List::Element *F = E->get().polygons.front(); F; F = F->next()) { + + Polygon &p = F->get(); + if (begin_d || end_d) { + for (int i = 2; i < p.edges.size(); i++) { + + if (begin_d > 0) { + + if (Geometry::is_point_in_triangle(p_start, _get_vertex(p.edges[0].point), _get_vertex(p.edges[i - 1].point), _get_vertex(p.edges[i].point))) { + + begin_poly = &p; + begin_point = p_start; + begin_d = 0; + if (end_d == 0) + break; + } + } + + if (end_d > 0) { + + if (Geometry::is_point_in_triangle(p_end, _get_vertex(p.edges[0].point), _get_vertex(p.edges[i - 1].point), _get_vertex(p.edges[i].point))) { + + end_poly = &p; + end_point = p_end; + end_d = 0; + if (begin_d == 0) + break; + } + } + } + } + + p.prev_edge = -1; + } + } + + //start or end not inside triangle.. look for closest segment :| + if (begin_d || end_d) { + for (Map::Element *E = navpoly_map.front(); E; E = E->next()) { + + if (!E->get().linked) + continue; + for (List::Element *F = E->get().polygons.front(); F; F = F->next()) { + + Polygon &p = F->get(); + int es = p.edges.size(); + for (int i = 0; i < es; i++) { + + Vector2 edge[2] = { + _get_vertex(p.edges[i].point), + _get_vertex(p.edges[(i + 1) % es].point) + }; + + if (begin_d > 0) { + Vector2 spoint = Geometry::get_closest_point_to_segment_2d(p_start, edge); + float d = spoint.distance_to(p_start); + if (d < begin_d) { + begin_poly = &p; + begin_point = spoint; + begin_d = d; + } + } + + if (end_d > 0) { + Vector2 spoint = Geometry::get_closest_point_to_segment_2d(p_end, edge); + float d = spoint.distance_to(p_end); + if (d < end_d) { + end_poly = &p; + end_point = spoint; + end_d = d; + } + } + } + } + } + } + + if (!begin_poly || !end_poly) { + + return Vector(); //no path + } + + if (begin_poly == end_poly) { + + Vector path; + path.resize(2); + path.write[0] = begin_point; + path.write[1] = end_point; + return path; + } + + bool found_route = false; + + List open_list; + + begin_poly->entry = p_start; + + for (int i = 0; i < begin_poly->edges.size(); i++) { + + if (begin_poly->edges[i].C) { + + begin_poly->edges[i].C->prev_edge = begin_poly->edges[i].C_edge; +#ifdef USE_ENTRY_POINT + Vector2 edge[2] = { + _get_vertex(begin_poly->edges[i].point), + _get_vertex(begin_poly->edges[(i + 1) % begin_poly->edges.size()].point) + }; + + Vector2 entry = Geometry::get_closest_point_to_segment_2d(begin_poly->entry, edge); + begin_poly->edges[i].C->distance = begin_poly->entry.distance_to(entry); + begin_poly->edges[i].C->entry = entry; +#else + begin_poly->edges[i].C->distance = begin_poly->center.distance_to(begin_poly->edges[i].C->center); +#endif + open_list.push_back(begin_poly->edges[i].C); + + if (begin_poly->edges[i].C == end_poly) { + found_route = true; + } + } + } + + while (!found_route) { + + if (open_list.size() == 0) { + break; + } + //check open list + + List::Element *least_cost_poly = NULL; + float least_cost = 1e30; + + //this could be faster (cache previous results) + for (List::Element *E = open_list.front(); E; E = E->next()) { + + Polygon *p = E->get(); + + float cost = p->distance; + +#ifdef USE_ENTRY_POINT + int es = p->edges.size(); + + float shortest_distance = 1e30; + + for (int i = 0; i < es; i++) { + Polygon::Edge &e = p->edges.write[i]; + + if (!e.C) + continue; + + Vector2 edge[2] = { + _get_vertex(p->edges[i].point), + _get_vertex(p->edges[(i + 1) % es].point) + }; + + Vector2 edge_point = Geometry::get_closest_point_to_segment_2d(p->entry, edge); + float dist = p->entry.distance_to(edge_point); + if (dist < shortest_distance) + shortest_distance = dist; + } + + cost += shortest_distance; +#else + cost += p->center.distance_to(end_point); +#endif + if (cost < least_cost) { + least_cost_poly = E; + least_cost = cost; + } + } + + Polygon *p = least_cost_poly->get(); + //open the neighbours for search + int es = p->edges.size(); + + for (int i = 0; i < es; i++) { + + Polygon::Edge &e = p->edges.write[i]; + + if (!e.C) + continue; + +#ifdef USE_ENTRY_POINT + Vector2 edge[2] = { + _get_vertex(p->edges[i].point), + _get_vertex(p->edges[(i + 1) % es].point) + }; + + Vector2 edge_entry = Geometry::get_closest_point_to_segment_2d(p->entry, edge); + float distance = p->entry.distance_to(edge_entry) + p->distance; + +#else + + float distance = p->center.distance_to(e.C->center) + p->distance; + +#endif + + if (e.C->prev_edge != -1) { + //oh this was visited already, can we win the cost? + + if (e.C->distance > distance) { + + e.C->prev_edge = e.C_edge; + e.C->distance = distance; +#ifdef USE_ENTRY_POINT + e.C->entry = edge_entry; +#endif + } + } else { + //add to open neighbours + + e.C->prev_edge = e.C_edge; + e.C->distance = distance; +#ifdef USE_ENTRY_POINT + e.C->entry = edge_entry; +#endif + + open_list.push_back(e.C); + + if (e.C == end_poly) { + //oh my reached end! stop algorithm + found_route = true; + break; + } + } + } + + if (found_route) + break; + + open_list.erase(least_cost_poly); + } + + if (found_route) { + + Vector path; + + if (p_optimize) { + //string pulling + + Vector2 apex_point = end_point; + Vector2 portal_left = apex_point; + Vector2 portal_right = apex_point; + Polygon *left_poly = end_poly; + Polygon *right_poly = end_poly; + Polygon *p = end_poly; + + while (p) { + + Vector2 left; + Vector2 right; + +//#define CLOCK_TANGENT(m_a,m_b,m_c) ( ((m_a)-(m_c)).cross((m_a)-(m_b)) ) +#define CLOCK_TANGENT(m_a, m_b, m_c) ((((m_a).x - (m_c).x) * ((m_b).y - (m_c).y) - ((m_b).x - (m_c).x) * ((m_a).y - (m_c).y))) + + if (p == begin_poly) { + left = begin_point; + right = begin_point; + } else { + int prev = p->prev_edge; + int prev_n = (p->prev_edge + 1) % p->edges.size(); + left = _get_vertex(p->edges[prev].point); + right = _get_vertex(p->edges[prev_n].point); + + if (p->clockwise) { + SWAP(left, right); + } + /*if (CLOCK_TANGENT(apex_point,left,(left+right)*0.5) < 0){ + SWAP(left,right); + }*/ + } + + bool skip = false; + + /* + print_line("-----\nAPEX: "+(apex_point-end_point)); + print_line("LEFT:"); + print_line("\tPortal: "+(portal_left-end_point)); + print_line("\tPoint: "+(left-end_point)); + print_line("\tLeft Tangent: "+rtos(CLOCK_TANGENT(apex_point,portal_left,left))); + print_line("\tLeft Distance: "+rtos(portal_left.distance_squared_to(apex_point))); + print_line("\tLeft Test: "+rtos(CLOCK_TANGENT(apex_point,left,portal_right))); + print_line("RIGHT:"); + print_line("\tPortal: "+(portal_right-end_point)); + print_line("\tPoint: "+(right-end_point)); + print_line("\tRight Tangent: "+rtos(CLOCK_TANGENT(apex_point,portal_right,right))); + print_line("\tRight Distance: "+rtos(portal_right.distance_squared_to(apex_point))); + print_line("\tRight Test: "+rtos(CLOCK_TANGENT(apex_point,right,portal_left))); + */ + + if (CLOCK_TANGENT(apex_point, portal_left, left) >= 0) { + //process + if (portal_left.distance_squared_to(apex_point) < CMP_EPSILON || CLOCK_TANGENT(apex_point, left, portal_right) > 0) { + left_poly = p; + portal_left = left; + } else { + + apex_point = portal_right; + p = right_poly; + left_poly = p; + portal_left = apex_point; + portal_right = apex_point; + if (!path.size() || path[path.size() - 1].distance_to(apex_point) > CMP_EPSILON) + path.push_back(apex_point); + skip = true; + } + } + + if (!skip && CLOCK_TANGENT(apex_point, portal_right, right) <= 0) { + //process + if (portal_right.distance_squared_to(apex_point) < CMP_EPSILON || CLOCK_TANGENT(apex_point, right, portal_left) < 0) { + right_poly = p; + portal_right = right; + } else { + + apex_point = portal_left; + p = left_poly; + right_poly = p; + portal_right = apex_point; + portal_left = apex_point; + if (!path.size() || path[path.size() - 1].distance_to(apex_point) > CMP_EPSILON) + path.push_back(apex_point); + } + } + + if (p != begin_poly) + p = p->edges[p->prev_edge].C; + else + p = NULL; + } + + } else { + //midpoints + Polygon *p = end_poly; + + while (true) { + int prev = p->prev_edge; + int prev_n = (p->prev_edge + 1) % p->edges.size(); + Vector2 point = (_get_vertex(p->edges[prev].point) + _get_vertex(p->edges[prev_n].point)) * 0.5; + path.push_back(point); + p = p->edges[prev].C; + if (p == begin_poly) + break; + } + } + + if (!path.size() || path[path.size() - 1].distance_squared_to(begin_point) > CMP_EPSILON) { + path.push_back(begin_point); // Add the begin point + } else { + path.write[path.size() - 1] = begin_point; // Replace first midpoint by the exact begin point + } + + path.invert(); + + if (path.size() <= 1 || path[path.size() - 1].distance_squared_to(end_point) > CMP_EPSILON) { + path.push_back(end_point); // Add the end point + } else { + path.write[path.size() - 1] = end_point; // Replace last midpoint by the exact end point + } + + return path; + } + + return Vector(); +} + +Vector2 Navigation2D::get_closest_point(const Vector2 &p_point) { + + Vector2 closest_point = Vector2(); + float closest_point_d = 1e20; + + for (Map::Element *E = navpoly_map.front(); E; E = E->next()) { + + if (!E->get().linked) + continue; + for (List::Element *F = E->get().polygons.front(); F; F = F->next()) { + + Polygon &p = F->get(); + for (int i = 2; i < p.edges.size(); i++) { + + if (Geometry::is_point_in_triangle(p_point, _get_vertex(p.edges[0].point), _get_vertex(p.edges[i - 1].point), _get_vertex(p.edges[i].point))) { + + return p_point; //inside triangle, nothing else to discuss + } + } + } + } + + for (Map::Element *E = navpoly_map.front(); E; E = E->next()) { + + if (!E->get().linked) + continue; + for (List::Element *F = E->get().polygons.front(); F; F = F->next()) { + + Polygon &p = F->get(); + int es = p.edges.size(); + for (int i = 0; i < es; i++) { + + Vector2 edge[2] = { + _get_vertex(p.edges[i].point), + _get_vertex(p.edges[(i + 1) % es].point) + }; + + Vector2 spoint = Geometry::get_closest_point_to_segment_2d(p_point, edge); + float d = spoint.distance_squared_to(p_point); + if (d < closest_point_d) { + + closest_point = spoint; + closest_point_d = d; + } + } + } + } + + return closest_point; +} + +Object *Navigation2D::get_closest_point_owner(const Vector2 &p_point) { + + Object *owner = NULL; + Vector2 closest_point = Vector2(); + float closest_point_d = 1e20; + + for (Map::Element *E = navpoly_map.front(); E; E = E->next()) { + + if (!E->get().linked) + continue; + for (List::Element *F = E->get().polygons.front(); F; F = F->next()) { + + Polygon &p = F->get(); + for (int i = 2; i < p.edges.size(); i++) { + + if (Geometry::is_point_in_triangle(p_point, _get_vertex(p.edges[0].point), _get_vertex(p.edges[i - 1].point), _get_vertex(p.edges[i].point))) { + + return E->get().owner; + } + } + } + } + + for (Map::Element *E = navpoly_map.front(); E; E = E->next()) { + + if (!E->get().linked) + continue; + for (List::Element *F = E->get().polygons.front(); F; F = F->next()) { + + Polygon &p = F->get(); + int es = p.edges.size(); + for (int i = 0; i < es; i++) { + + Vector2 edge[2] = { + _get_vertex(p.edges[i].point), + _get_vertex(p.edges[(i + 1) % es].point) + }; + + Vector2 spoint = Geometry::get_closest_point_to_segment_2d(p_point, edge); + float d = spoint.distance_squared_to(p_point); + if (d < closest_point_d) { + + closest_point = spoint; + closest_point_d = d; + owner = E->get().owner; + } + } + } + } + + return owner; +} + +void Navigation2D::_bind_methods() { + + ClassDB::bind_method(D_METHOD("navpoly_add", "mesh", "xform", "owner"), &Navigation2D::navpoly_add, DEFVAL(Variant())); + ClassDB::bind_method(D_METHOD("navpoly_set_transform", "id", "xform"), &Navigation2D::navpoly_set_transform); + ClassDB::bind_method(D_METHOD("navpoly_remove", "id"), &Navigation2D::navpoly_remove); + + ClassDB::bind_method(D_METHOD("get_simple_path", "start", "end", "optimize"), &Navigation2D::get_simple_path, DEFVAL(true)); + ClassDB::bind_method(D_METHOD("get_closest_point", "to_point"), &Navigation2D::get_closest_point); + ClassDB::bind_method(D_METHOD("get_closest_point_owner", "to_point"), &Navigation2D::get_closest_point_owner); +} + +Navigation2D::Navigation2D() { + + ERR_FAIL_COND(sizeof(Point) != 8); + cell_size = 1; // one pixel + last_id = 1; +} diff --git a/scene/2d/navigation_2d.h b/scene/2d/navigation_2d.h new file mode 100644 index 0000000000..b4d659ff5c --- /dev/null +++ b/scene/2d/navigation_2d.h @@ -0,0 +1,174 @@ +/*************************************************************************/ +/* navigation_2d.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef NAVIGATION_2D_H +#define NAVIGATION_2D_H + +#include "scene/2d/navigation_polygon.h" +#include "scene/2d/node_2d.h" + +class Navigation2D : public Node2D { + + GDCLASS(Navigation2D, Node2D); + + union Point { + + struct { + int64_t x : 32; + int64_t y : 32; + }; + + uint64_t key; + bool operator<(const Point &p_key) const { return key < p_key.key; } + }; + + struct EdgeKey { + + Point a; + Point b; + + bool operator<(const EdgeKey &p_key) const { + return (a.key == p_key.a.key) ? (b.key < p_key.b.key) : (a.key < p_key.a.key); + }; + + EdgeKey(const Point &p_a = Point(), const Point &p_b = Point()) : + a(p_a), + b(p_b) { + if (a.key > b.key) { + SWAP(a, b); + } + } + }; + + struct NavMesh; + struct Polygon; + + struct ConnectionPending { + + Polygon *polygon; + int edge; + }; + + struct Polygon { + + struct Edge { + Point point; + Polygon *C; //connection + int C_edge; + List::Element *P; + Edge() { + C = NULL; + C_edge = -1; + P = NULL; + } + }; + + Vector edges; + + Vector2 center; + Vector2 entry; + + float distance; + int prev_edge; + + bool clockwise; + + NavMesh *owner; + }; + + struct Connection { + + Polygon *A; + int A_edge; + Polygon *B; + int B_edge; + + List pending; + + Connection() { + A = NULL; + B = NULL; + A_edge = -1; + B_edge = -1; + } + }; + + Map connections; + + struct NavMesh { + + Object *owner; + Transform2D xform; + bool linked; + Ref navpoly; + List polygons; + }; + + _FORCE_INLINE_ Point _get_point(const Vector2 &p_pos) const { + + int x = int(Math::floor(p_pos.x / cell_size)); + int y = int(Math::floor(p_pos.y / cell_size)); + + Point p; + p.key = 0; + p.x = x; + p.y = y; + return p; + } + + _FORCE_INLINE_ Vector2 _get_vertex(const Point &p_point) const { + + return Vector2(p_point.x, p_point.y) * cell_size; + } + + void _navpoly_link(int p_id); + void _navpoly_unlink(int p_id); + + float cell_size; + Map navpoly_map; + int last_id; + +protected: + static void _bind_methods(); + +public: + //API should be as dynamic as possible + int navpoly_add(const Ref &p_mesh, const Transform2D &p_xform, Object *p_owner = NULL); + void navpoly_set_transform(int p_id, const Transform2D &p_xform); + void navpoly_remove(int p_id); + + Vector get_simple_path(const Vector2 &p_start, const Vector2 &p_end, bool p_optimize = true); + Vector2 get_closest_point(const Vector2 &p_point); + Object *get_closest_point_owner(const Vector2 &p_point); + + Navigation2D(); +}; + +#endif // NAVIGATION_2D_H diff --git a/scene/2d/navigation_polygon.cpp b/scene/2d/navigation_polygon.cpp index 50618c6baa..0f6af358bd 100644 --- a/scene/2d/navigation_polygon.cpp +++ b/scene/2d/navigation_polygon.cpp @@ -32,7 +32,7 @@ #include "core/core_string_names.h" #include "core/engine.h" -#include "navigation2d.h" +#include "navigation_2d.h" #include "thirdparty/misc/triangulator.h" diff --git a/scene/2d/screen_button.cpp b/scene/2d/screen_button.cpp deleted file mode 100644 index fb1558a404..0000000000 --- a/scene/2d/screen_button.cpp +++ /dev/null @@ -1,423 +0,0 @@ -/*************************************************************************/ -/* screen_button.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#include "screen_button.h" -#include "core/input_map.h" -#include "core/os/input.h" -#include "core/os/os.h" - -void TouchScreenButton::set_texture(const Ref &p_texture) { - - texture = p_texture; - update(); -} - -Ref TouchScreenButton::get_texture() const { - - return texture; -} - -void TouchScreenButton::set_texture_pressed(const Ref &p_texture_pressed) { - - texture_pressed = p_texture_pressed; - update(); -} - -Ref TouchScreenButton::get_texture_pressed() const { - - return texture_pressed; -} - -void TouchScreenButton::set_bitmask(const Ref &p_bitmask) { - - bitmask = p_bitmask; -} - -Ref TouchScreenButton::get_bitmask() const { - - return bitmask; -} - -void TouchScreenButton::set_shape(const Ref &p_shape) { - - if (shape.is_valid()) - shape->disconnect("changed", this, "update"); - - shape = p_shape; - - if (shape.is_valid()) - shape->connect("changed", this, "update"); - - update(); -} - -Ref TouchScreenButton::get_shape() const { - - return shape; -} - -void TouchScreenButton::set_shape_centered(bool p_shape_centered) { - - shape_centered = p_shape_centered; - update(); -} - -bool TouchScreenButton::is_shape_visible() const { - - return shape_visible; -} - -void TouchScreenButton::set_shape_visible(bool p_shape_visible) { - - shape_visible = p_shape_visible; - update(); -} - -bool TouchScreenButton::is_shape_centered() const { - - return shape_centered; -} - -void TouchScreenButton::_notification(int p_what) { - - switch (p_what) { - - case NOTIFICATION_DRAW: { - - if (!is_inside_tree()) - return; - if (!Engine::get_singleton()->is_editor_hint() && !OS::get_singleton()->has_touchscreen_ui_hint() && visibility == VISIBILITY_TOUCHSCREEN_ONLY) - return; - - if (finger_pressed != -1) { - - if (texture_pressed.is_valid()) - draw_texture(texture_pressed, Point2()); - else if (texture.is_valid()) - draw_texture(texture, Point2()); - - } else { - if (texture.is_valid()) - draw_texture(texture, Point2()); - } - - if (!shape_visible) - return; - if (!Engine::get_singleton()->is_editor_hint() && !get_tree()->is_debugging_collisions_hint()) - return; - if (shape.is_valid()) { - Color draw_col = get_tree()->get_debug_collisions_color(); - Vector2 pos = shape_centered ? _edit_get_rect().size * 0.5f : Vector2(); - draw_set_transform_matrix(get_canvas_transform().translated(pos)); - shape->draw(get_canvas_item(), draw_col); - } - - } break; - case NOTIFICATION_ENTER_TREE: { - - if (!Engine::get_singleton()->is_editor_hint() && !OS::get_singleton()->has_touchscreen_ui_hint() && visibility == VISIBILITY_TOUCHSCREEN_ONLY) - return; - update(); - - if (!Engine::get_singleton()->is_editor_hint()) - set_process_input(is_visible_in_tree()); - - } break; - case NOTIFICATION_EXIT_TREE: { - if (is_pressed()) - _release(true); - } break; - case NOTIFICATION_VISIBILITY_CHANGED: { - if (Engine::get_singleton()->is_editor_hint()) - break; - if (is_visible_in_tree()) { - set_process_input(true); - } else { - set_process_input(false); - if (is_pressed()) - _release(); - } - } break; - case NOTIFICATION_PAUSED: { - if (is_pressed()) - _release(); - } break; - } -} - -bool TouchScreenButton::is_pressed() const { - - return finger_pressed != -1; -} - -void TouchScreenButton::set_action(const String &p_action) { - - action = p_action; -} - -String TouchScreenButton::get_action() const { - - return action; -} - -void TouchScreenButton::_input(const Ref &p_event) { - - if (!get_tree()) - return; - - if (p_event->get_device() != 0) - return; - - ERR_FAIL_COND(!is_visible_in_tree()); - - const InputEventScreenTouch *st = Object::cast_to(*p_event); - - if (passby_press) { - - const InputEventScreenDrag *sd = Object::cast_to(*p_event); - - if (st && !st->is_pressed() && finger_pressed == st->get_index()) { - - _release(); - } - - if ((st && st->is_pressed()) || sd) { - - int index = st ? st->get_index() : sd->get_index(); - Point2 coord = st ? st->get_position() : sd->get_position(); - - if (finger_pressed == -1 || index == finger_pressed) { - - if (_is_point_inside(coord)) { - if (finger_pressed == -1) { - _press(index); - } - } else { - if (finger_pressed != -1) { - _release(); - } - } - } - } - - } else { - - if (st) { - - if (st->is_pressed()) { - - const bool can_press = finger_pressed == -1; - if (!can_press) - return; //already fingering - - if (_is_point_inside(st->get_position())) { - _press(st->get_index()); - } - } else { - if (st->get_index() == finger_pressed) { - _release(); - } - } - } - } -} - -bool TouchScreenButton::_is_point_inside(const Point2 &p_point) { - - Point2 coord = (get_global_transform_with_canvas()).affine_inverse().xform(p_point); - Rect2 item_rect = _edit_get_rect(); - - bool touched = false; - bool check_rect = true; - - if (shape.is_valid()) { - - check_rect = false; - Transform2D xform = shape_centered ? Transform2D().translated(item_rect.size * 0.5f) : Transform2D(); - touched = shape->collide(xform, unit_rect, Transform2D(0, coord + Vector2(0.5, 0.5))); - } - - if (bitmask.is_valid()) { - - check_rect = false; - if (!touched && Rect2(Point2(), bitmask->get_size()).has_point(coord)) { - - if (bitmask->get_bit(coord)) - touched = true; - } - } - - if (!touched && check_rect) { - if (texture.is_valid()) - touched = item_rect.has_point(coord); - } - - return touched; -} - -void TouchScreenButton::_press(int p_finger_pressed) { - - finger_pressed = p_finger_pressed; - - if (action != StringName()) { - - Input::get_singleton()->action_press(action); - Ref iea; - iea.instance(); - iea->set_action(action); - iea->set_pressed(true); - get_tree()->input_event(iea); - } - - emit_signal("pressed"); - update(); -} - -void TouchScreenButton::_release(bool p_exiting_tree) { - - finger_pressed = -1; - - if (action != StringName()) { - - Input::get_singleton()->action_release(action); - if (!p_exiting_tree) { - - Ref iea; - iea.instance(); - iea->set_action(action); - iea->set_pressed(false); - get_tree()->input_event(iea); - } - } - - if (!p_exiting_tree) { - emit_signal("released"); - update(); - } -} - -Rect2 TouchScreenButton::_edit_get_rect() const { - if (texture.is_null()) - return CanvasItem::_edit_get_rect(); - - return Rect2(Size2(), texture->get_size()); -} - -bool TouchScreenButton::_edit_use_rect() const { - return !texture.is_null(); -} - -Rect2 TouchScreenButton::get_anchorable_rect() const { - if (texture.is_null()) - return CanvasItem::get_anchorable_rect(); - - return Rect2(Size2(), texture->get_size()); -} - -void TouchScreenButton::set_visibility_mode(VisibilityMode p_mode) { - visibility = p_mode; - update(); -} - -TouchScreenButton::VisibilityMode TouchScreenButton::get_visibility_mode() const { - - return visibility; -} - -void TouchScreenButton::set_passby_press(bool p_enable) { - - passby_press = p_enable; -} - -bool TouchScreenButton::is_passby_press_enabled() const { - - return passby_press; -} - -void TouchScreenButton::_bind_methods() { - - ClassDB::bind_method(D_METHOD("set_texture", "texture"), &TouchScreenButton::set_texture); - ClassDB::bind_method(D_METHOD("get_texture"), &TouchScreenButton::get_texture); - - ClassDB::bind_method(D_METHOD("set_texture_pressed", "texture_pressed"), &TouchScreenButton::set_texture_pressed); - ClassDB::bind_method(D_METHOD("get_texture_pressed"), &TouchScreenButton::get_texture_pressed); - - ClassDB::bind_method(D_METHOD("set_bitmask", "bitmask"), &TouchScreenButton::set_bitmask); - ClassDB::bind_method(D_METHOD("get_bitmask"), &TouchScreenButton::get_bitmask); - - ClassDB::bind_method(D_METHOD("set_shape", "shape"), &TouchScreenButton::set_shape); - ClassDB::bind_method(D_METHOD("get_shape"), &TouchScreenButton::get_shape); - - ClassDB::bind_method(D_METHOD("set_shape_centered", "bool"), &TouchScreenButton::set_shape_centered); - ClassDB::bind_method(D_METHOD("is_shape_centered"), &TouchScreenButton::is_shape_centered); - - ClassDB::bind_method(D_METHOD("set_shape_visible", "bool"), &TouchScreenButton::set_shape_visible); - ClassDB::bind_method(D_METHOD("is_shape_visible"), &TouchScreenButton::is_shape_visible); - - ClassDB::bind_method(D_METHOD("set_action", "action"), &TouchScreenButton::set_action); - ClassDB::bind_method(D_METHOD("get_action"), &TouchScreenButton::get_action); - - ClassDB::bind_method(D_METHOD("set_visibility_mode", "mode"), &TouchScreenButton::set_visibility_mode); - ClassDB::bind_method(D_METHOD("get_visibility_mode"), &TouchScreenButton::get_visibility_mode); - - ClassDB::bind_method(D_METHOD("set_passby_press", "enabled"), &TouchScreenButton::set_passby_press); - ClassDB::bind_method(D_METHOD("is_passby_press_enabled"), &TouchScreenButton::is_passby_press_enabled); - - ClassDB::bind_method(D_METHOD("is_pressed"), &TouchScreenButton::is_pressed); - - ClassDB::bind_method(D_METHOD("_input"), &TouchScreenButton::_input); - - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "normal", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_texture", "get_texture"); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "pressed", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_texture_pressed", "get_texture_pressed"); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "bitmask", PROPERTY_HINT_RESOURCE_TYPE, "BitMap"), "set_bitmask", "get_bitmask"); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "shape", PROPERTY_HINT_RESOURCE_TYPE, "Shape2D"), "set_shape", "get_shape"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "shape_centered"), "set_shape_centered", "is_shape_centered"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "shape_visible"), "set_shape_visible", "is_shape_visible"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "passby_press"), "set_passby_press", "is_passby_press_enabled"); - ADD_PROPERTY(PropertyInfo(Variant::STRING, "action"), "set_action", "get_action"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "visibility_mode", PROPERTY_HINT_ENUM, "Always,TouchScreen Only"), "set_visibility_mode", "get_visibility_mode"); - - ADD_SIGNAL(MethodInfo("pressed")); - ADD_SIGNAL(MethodInfo("released")); - - BIND_ENUM_CONSTANT(VISIBILITY_ALWAYS); - BIND_ENUM_CONSTANT(VISIBILITY_TOUCHSCREEN_ONLY); -} - -TouchScreenButton::TouchScreenButton() { - - finger_pressed = -1; - passby_press = false; - visibility = VISIBILITY_ALWAYS; - shape_centered = true; - shape_visible = true; - unit_rect = Ref(memnew(RectangleShape2D)); - unit_rect->set_extents(Vector2(0.5, 0.5)); -} diff --git a/scene/2d/screen_button.h b/scene/2d/screen_button.h deleted file mode 100644 index fd944ead64..0000000000 --- a/scene/2d/screen_button.h +++ /dev/null @@ -1,115 +0,0 @@ -/*************************************************************************/ -/* screen_button.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#ifndef SCREEN_BUTTON_H -#define SCREEN_BUTTON_H - -#include "scene/2d/node_2d.h" -#include "scene/resources/bit_mask.h" -#include "scene/resources/rectangle_shape_2d.h" -#include "scene/resources/texture.h" - -class TouchScreenButton : public Node2D { - - GDCLASS(TouchScreenButton, Node2D); - -public: - enum VisibilityMode { - VISIBILITY_ALWAYS, - VISIBILITY_TOUCHSCREEN_ONLY - }; - -private: - Ref texture; - Ref texture_pressed; - Ref bitmask; - Ref shape; - bool shape_centered; - bool shape_visible; - - Ref unit_rect; - - StringName action; - bool passby_press; - int finger_pressed; - - VisibilityMode visibility; - - void _input(const Ref &p_event); - - bool _is_point_inside(const Point2 &p_point); - - void _press(int p_finger_pressed); - void _release(bool p_exiting_tree = false); - -protected: - void _notification(int p_what); - static void _bind_methods(); - -public: - void set_texture(const Ref &p_texture); - Ref get_texture() const; - - void set_texture_pressed(const Ref &p_texture_pressed); - Ref get_texture_pressed() const; - - void set_bitmask(const Ref &p_bitmask); - Ref get_bitmask() const; - - void set_shape(const Ref &p_shape); - Ref get_shape() const; - - void set_shape_centered(bool p_shape_centered); - bool is_shape_centered() const; - - void set_shape_visible(bool p_shape_visible); - bool is_shape_visible() const; - - void set_action(const String &p_action); - String get_action() const; - - void set_passby_press(bool p_enable); - bool is_passby_press_enabled() const; - - void set_visibility_mode(VisibilityMode p_mode); - VisibilityMode get_visibility_mode() const; - - bool is_pressed() const; - - virtual Rect2 _edit_get_rect() const; - virtual bool _edit_use_rect() const; - virtual Rect2 get_anchorable_rect() const; - - TouchScreenButton(); -}; - -VARIANT_ENUM_CAST(TouchScreenButton::VisibilityMode); - -#endif // SCREEN_BUTTON_H diff --git a/scene/2d/tile_map.h b/scene/2d/tile_map.h index a44098fd77..e450e1e256 100644 --- a/scene/2d/tile_map.h +++ b/scene/2d/tile_map.h @@ -33,7 +33,7 @@ #include "core/self_list.h" #include "core/vset.h" -#include "scene/2d/navigation2d.h" +#include "scene/2d/navigation_2d.h" #include "scene/2d/node_2d.h" #include "scene/resources/tile_set.h" diff --git a/scene/2d/touch_screen_button.cpp b/scene/2d/touch_screen_button.cpp new file mode 100644 index 0000000000..9a1a759e72 --- /dev/null +++ b/scene/2d/touch_screen_button.cpp @@ -0,0 +1,424 @@ +/*************************************************************************/ +/* touch_screen_button.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "touch_screen_button.h" + +#include "core/input_map.h" +#include "core/os/input.h" +#include "core/os/os.h" + +void TouchScreenButton::set_texture(const Ref &p_texture) { + + texture = p_texture; + update(); +} + +Ref TouchScreenButton::get_texture() const { + + return texture; +} + +void TouchScreenButton::set_texture_pressed(const Ref &p_texture_pressed) { + + texture_pressed = p_texture_pressed; + update(); +} + +Ref TouchScreenButton::get_texture_pressed() const { + + return texture_pressed; +} + +void TouchScreenButton::set_bitmask(const Ref &p_bitmask) { + + bitmask = p_bitmask; +} + +Ref TouchScreenButton::get_bitmask() const { + + return bitmask; +} + +void TouchScreenButton::set_shape(const Ref &p_shape) { + + if (shape.is_valid()) + shape->disconnect("changed", this, "update"); + + shape = p_shape; + + if (shape.is_valid()) + shape->connect("changed", this, "update"); + + update(); +} + +Ref TouchScreenButton::get_shape() const { + + return shape; +} + +void TouchScreenButton::set_shape_centered(bool p_shape_centered) { + + shape_centered = p_shape_centered; + update(); +} + +bool TouchScreenButton::is_shape_visible() const { + + return shape_visible; +} + +void TouchScreenButton::set_shape_visible(bool p_shape_visible) { + + shape_visible = p_shape_visible; + update(); +} + +bool TouchScreenButton::is_shape_centered() const { + + return shape_centered; +} + +void TouchScreenButton::_notification(int p_what) { + + switch (p_what) { + + case NOTIFICATION_DRAW: { + + if (!is_inside_tree()) + return; + if (!Engine::get_singleton()->is_editor_hint() && !OS::get_singleton()->has_touchscreen_ui_hint() && visibility == VISIBILITY_TOUCHSCREEN_ONLY) + return; + + if (finger_pressed != -1) { + + if (texture_pressed.is_valid()) + draw_texture(texture_pressed, Point2()); + else if (texture.is_valid()) + draw_texture(texture, Point2()); + + } else { + if (texture.is_valid()) + draw_texture(texture, Point2()); + } + + if (!shape_visible) + return; + if (!Engine::get_singleton()->is_editor_hint() && !get_tree()->is_debugging_collisions_hint()) + return; + if (shape.is_valid()) { + Color draw_col = get_tree()->get_debug_collisions_color(); + Vector2 pos = shape_centered ? _edit_get_rect().size * 0.5f : Vector2(); + draw_set_transform_matrix(get_canvas_transform().translated(pos)); + shape->draw(get_canvas_item(), draw_col); + } + + } break; + case NOTIFICATION_ENTER_TREE: { + + if (!Engine::get_singleton()->is_editor_hint() && !OS::get_singleton()->has_touchscreen_ui_hint() && visibility == VISIBILITY_TOUCHSCREEN_ONLY) + return; + update(); + + if (!Engine::get_singleton()->is_editor_hint()) + set_process_input(is_visible_in_tree()); + + } break; + case NOTIFICATION_EXIT_TREE: { + if (is_pressed()) + _release(true); + } break; + case NOTIFICATION_VISIBILITY_CHANGED: { + if (Engine::get_singleton()->is_editor_hint()) + break; + if (is_visible_in_tree()) { + set_process_input(true); + } else { + set_process_input(false); + if (is_pressed()) + _release(); + } + } break; + case NOTIFICATION_PAUSED: { + if (is_pressed()) + _release(); + } break; + } +} + +bool TouchScreenButton::is_pressed() const { + + return finger_pressed != -1; +} + +void TouchScreenButton::set_action(const String &p_action) { + + action = p_action; +} + +String TouchScreenButton::get_action() const { + + return action; +} + +void TouchScreenButton::_input(const Ref &p_event) { + + if (!get_tree()) + return; + + if (p_event->get_device() != 0) + return; + + ERR_FAIL_COND(!is_visible_in_tree()); + + const InputEventScreenTouch *st = Object::cast_to(*p_event); + + if (passby_press) { + + const InputEventScreenDrag *sd = Object::cast_to(*p_event); + + if (st && !st->is_pressed() && finger_pressed == st->get_index()) { + + _release(); + } + + if ((st && st->is_pressed()) || sd) { + + int index = st ? st->get_index() : sd->get_index(); + Point2 coord = st ? st->get_position() : sd->get_position(); + + if (finger_pressed == -1 || index == finger_pressed) { + + if (_is_point_inside(coord)) { + if (finger_pressed == -1) { + _press(index); + } + } else { + if (finger_pressed != -1) { + _release(); + } + } + } + } + + } else { + + if (st) { + + if (st->is_pressed()) { + + const bool can_press = finger_pressed == -1; + if (!can_press) + return; //already fingering + + if (_is_point_inside(st->get_position())) { + _press(st->get_index()); + } + } else { + if (st->get_index() == finger_pressed) { + _release(); + } + } + } + } +} + +bool TouchScreenButton::_is_point_inside(const Point2 &p_point) { + + Point2 coord = (get_global_transform_with_canvas()).affine_inverse().xform(p_point); + Rect2 item_rect = _edit_get_rect(); + + bool touched = false; + bool check_rect = true; + + if (shape.is_valid()) { + + check_rect = false; + Transform2D xform = shape_centered ? Transform2D().translated(item_rect.size * 0.5f) : Transform2D(); + touched = shape->collide(xform, unit_rect, Transform2D(0, coord + Vector2(0.5, 0.5))); + } + + if (bitmask.is_valid()) { + + check_rect = false; + if (!touched && Rect2(Point2(), bitmask->get_size()).has_point(coord)) { + + if (bitmask->get_bit(coord)) + touched = true; + } + } + + if (!touched && check_rect) { + if (texture.is_valid()) + touched = item_rect.has_point(coord); + } + + return touched; +} + +void TouchScreenButton::_press(int p_finger_pressed) { + + finger_pressed = p_finger_pressed; + + if (action != StringName()) { + + Input::get_singleton()->action_press(action); + Ref iea; + iea.instance(); + iea->set_action(action); + iea->set_pressed(true); + get_tree()->input_event(iea); + } + + emit_signal("pressed"); + update(); +} + +void TouchScreenButton::_release(bool p_exiting_tree) { + + finger_pressed = -1; + + if (action != StringName()) { + + Input::get_singleton()->action_release(action); + if (!p_exiting_tree) { + + Ref iea; + iea.instance(); + iea->set_action(action); + iea->set_pressed(false); + get_tree()->input_event(iea); + } + } + + if (!p_exiting_tree) { + emit_signal("released"); + update(); + } +} + +Rect2 TouchScreenButton::_edit_get_rect() const { + if (texture.is_null()) + return CanvasItem::_edit_get_rect(); + + return Rect2(Size2(), texture->get_size()); +} + +bool TouchScreenButton::_edit_use_rect() const { + return !texture.is_null(); +} + +Rect2 TouchScreenButton::get_anchorable_rect() const { + if (texture.is_null()) + return CanvasItem::get_anchorable_rect(); + + return Rect2(Size2(), texture->get_size()); +} + +void TouchScreenButton::set_visibility_mode(VisibilityMode p_mode) { + visibility = p_mode; + update(); +} + +TouchScreenButton::VisibilityMode TouchScreenButton::get_visibility_mode() const { + + return visibility; +} + +void TouchScreenButton::set_passby_press(bool p_enable) { + + passby_press = p_enable; +} + +bool TouchScreenButton::is_passby_press_enabled() const { + + return passby_press; +} + +void TouchScreenButton::_bind_methods() { + + ClassDB::bind_method(D_METHOD("set_texture", "texture"), &TouchScreenButton::set_texture); + ClassDB::bind_method(D_METHOD("get_texture"), &TouchScreenButton::get_texture); + + ClassDB::bind_method(D_METHOD("set_texture_pressed", "texture_pressed"), &TouchScreenButton::set_texture_pressed); + ClassDB::bind_method(D_METHOD("get_texture_pressed"), &TouchScreenButton::get_texture_pressed); + + ClassDB::bind_method(D_METHOD("set_bitmask", "bitmask"), &TouchScreenButton::set_bitmask); + ClassDB::bind_method(D_METHOD("get_bitmask"), &TouchScreenButton::get_bitmask); + + ClassDB::bind_method(D_METHOD("set_shape", "shape"), &TouchScreenButton::set_shape); + ClassDB::bind_method(D_METHOD("get_shape"), &TouchScreenButton::get_shape); + + ClassDB::bind_method(D_METHOD("set_shape_centered", "bool"), &TouchScreenButton::set_shape_centered); + ClassDB::bind_method(D_METHOD("is_shape_centered"), &TouchScreenButton::is_shape_centered); + + ClassDB::bind_method(D_METHOD("set_shape_visible", "bool"), &TouchScreenButton::set_shape_visible); + ClassDB::bind_method(D_METHOD("is_shape_visible"), &TouchScreenButton::is_shape_visible); + + ClassDB::bind_method(D_METHOD("set_action", "action"), &TouchScreenButton::set_action); + ClassDB::bind_method(D_METHOD("get_action"), &TouchScreenButton::get_action); + + ClassDB::bind_method(D_METHOD("set_visibility_mode", "mode"), &TouchScreenButton::set_visibility_mode); + ClassDB::bind_method(D_METHOD("get_visibility_mode"), &TouchScreenButton::get_visibility_mode); + + ClassDB::bind_method(D_METHOD("set_passby_press", "enabled"), &TouchScreenButton::set_passby_press); + ClassDB::bind_method(D_METHOD("is_passby_press_enabled"), &TouchScreenButton::is_passby_press_enabled); + + ClassDB::bind_method(D_METHOD("is_pressed"), &TouchScreenButton::is_pressed); + + ClassDB::bind_method(D_METHOD("_input"), &TouchScreenButton::_input); + + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "normal", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_texture", "get_texture"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "pressed", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_texture_pressed", "get_texture_pressed"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "bitmask", PROPERTY_HINT_RESOURCE_TYPE, "BitMap"), "set_bitmask", "get_bitmask"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "shape", PROPERTY_HINT_RESOURCE_TYPE, "Shape2D"), "set_shape", "get_shape"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "shape_centered"), "set_shape_centered", "is_shape_centered"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "shape_visible"), "set_shape_visible", "is_shape_visible"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "passby_press"), "set_passby_press", "is_passby_press_enabled"); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "action"), "set_action", "get_action"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "visibility_mode", PROPERTY_HINT_ENUM, "Always,TouchScreen Only"), "set_visibility_mode", "get_visibility_mode"); + + ADD_SIGNAL(MethodInfo("pressed")); + ADD_SIGNAL(MethodInfo("released")); + + BIND_ENUM_CONSTANT(VISIBILITY_ALWAYS); + BIND_ENUM_CONSTANT(VISIBILITY_TOUCHSCREEN_ONLY); +} + +TouchScreenButton::TouchScreenButton() { + + finger_pressed = -1; + passby_press = false; + visibility = VISIBILITY_ALWAYS; + shape_centered = true; + shape_visible = true; + unit_rect = Ref(memnew(RectangleShape2D)); + unit_rect->set_extents(Vector2(0.5, 0.5)); +} diff --git a/scene/2d/touch_screen_button.h b/scene/2d/touch_screen_button.h new file mode 100644 index 0000000000..df54e5340b --- /dev/null +++ b/scene/2d/touch_screen_button.h @@ -0,0 +1,115 @@ +/*************************************************************************/ +/* touch_screen_button.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef TOUCH_SCREEN_BUTTON_H +#define TOUCH_SCREEN_BUTTON_H + +#include "scene/2d/node_2d.h" +#include "scene/resources/bit_map.h" +#include "scene/resources/rectangle_shape_2d.h" +#include "scene/resources/texture.h" + +class TouchScreenButton : public Node2D { + + GDCLASS(TouchScreenButton, Node2D); + +public: + enum VisibilityMode { + VISIBILITY_ALWAYS, + VISIBILITY_TOUCHSCREEN_ONLY + }; + +private: + Ref texture; + Ref texture_pressed; + Ref bitmask; + Ref shape; + bool shape_centered; + bool shape_visible; + + Ref unit_rect; + + StringName action; + bool passby_press; + int finger_pressed; + + VisibilityMode visibility; + + void _input(const Ref &p_event); + + bool _is_point_inside(const Point2 &p_point); + + void _press(int p_finger_pressed); + void _release(bool p_exiting_tree = false); + +protected: + void _notification(int p_what); + static void _bind_methods(); + +public: + void set_texture(const Ref &p_texture); + Ref get_texture() const; + + void set_texture_pressed(const Ref &p_texture_pressed); + Ref get_texture_pressed() const; + + void set_bitmask(const Ref &p_bitmask); + Ref get_bitmask() const; + + void set_shape(const Ref &p_shape); + Ref get_shape() const; + + void set_shape_centered(bool p_shape_centered); + bool is_shape_centered() const; + + void set_shape_visible(bool p_shape_visible); + bool is_shape_visible() const; + + void set_action(const String &p_action); + String get_action() const; + + void set_passby_press(bool p_enable); + bool is_passby_press_enabled() const; + + void set_visibility_mode(VisibilityMode p_mode); + VisibilityMode get_visibility_mode() const; + + bool is_pressed() const; + + virtual Rect2 _edit_get_rect() const; + virtual bool _edit_use_rect() const; + virtual Rect2 get_anchorable_rect() const; + + TouchScreenButton(); +}; + +VARIANT_ENUM_CAST(TouchScreenButton::VisibilityMode); + +#endif // TOUCH_SCREEN_BUTTON_H diff --git a/scene/3d/SCsub b/scene/3d/SCsub index 35cc7479d8..200cf4316f 100644 --- a/scene/3d/SCsub +++ b/scene/3d/SCsub @@ -7,6 +7,6 @@ if env['disable_3d']: env.scene_sources.append("3d/skeleton.cpp") env.scene_sources.append("3d/particles.cpp") env.scene_sources.append("3d/visual_instance.cpp") - env.scene_sources.append("3d/scenario_fx.cpp") + env.scene_sources.append("3d/world_environment.cpp") else: env.add_source_files(env.scene_sources, "*.cpp") diff --git a/scene/3d/reflection_probe.h b/scene/3d/reflection_probe.h index 2921a3a881..48d65b79f7 100644 --- a/scene/3d/reflection_probe.h +++ b/scene/3d/reflection_probe.h @@ -32,7 +32,7 @@ #define REFLECTIONPROBE_H #include "scene/3d/visual_instance.h" -#include "scene/resources/sky_box.h" +#include "scene/resources/sky.h" #include "scene/resources/texture.h" #include "servers/visual_server.h" diff --git a/scene/3d/scenario_fx.cpp b/scene/3d/scenario_fx.cpp deleted file mode 100644 index ad9b61e1ff..0000000000 --- a/scene/3d/scenario_fx.cpp +++ /dev/null @@ -1,112 +0,0 @@ -/*************************************************************************/ -/* scenario_fx.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#include "scenario_fx.h" -#include "scene/main/viewport.h" - -void WorldEnvironment::_notification(int p_what) { - - if (p_what == Spatial::NOTIFICATION_ENTER_WORLD || p_what == Spatial::NOTIFICATION_ENTER_TREE) { - - if (environment.is_valid()) { - if (get_viewport()->find_world()->get_environment().is_valid()) { - WARN_PRINT("World already has an environment (Another WorldEnvironment?), overriding."); - } - get_viewport()->find_world()->set_environment(environment); - add_to_group("_world_environment_" + itos(get_viewport()->find_world()->get_scenario().get_id())); - } - - } else if (p_what == Spatial::NOTIFICATION_EXIT_WORLD || p_what == Spatial::NOTIFICATION_EXIT_TREE) { - - if (environment.is_valid() && get_viewport()->find_world()->get_environment() == environment) { - get_viewport()->find_world()->set_environment(Ref()); - remove_from_group("_world_environment_" + itos(get_viewport()->find_world()->get_scenario().get_id())); - } - } -} - -void WorldEnvironment::set_environment(const Ref &p_environment) { - - if (is_inside_tree() && environment.is_valid() && get_viewport()->find_world()->get_environment() == environment) { - get_viewport()->find_world()->set_environment(Ref()); - remove_from_group("_world_environment_" + itos(get_viewport()->find_world()->get_scenario().get_id())); - //clean up - } - - environment = p_environment; - if (is_inside_tree() && environment.is_valid()) { - if (get_viewport()->find_world()->get_environment().is_valid()) { - WARN_PRINT("World already has an environment (Another WorldEnvironment?), overriding."); - } - get_viewport()->find_world()->set_environment(environment); - add_to_group("_world_environment_" + itos(get_viewport()->find_world()->get_scenario().get_id())); - } - - update_configuration_warning(); -} - -Ref WorldEnvironment::get_environment() const { - - return environment; -} - -String WorldEnvironment::get_configuration_warning() const { - - if (!environment.is_valid()) { - return TTR("WorldEnvironment needs an Environment resource."); - } - - if (/*!is_visible_in_tree() ||*/ !is_inside_tree()) - return String(); - - List nodes; - get_tree()->get_nodes_in_group("_world_environment_" + itos(get_viewport()->find_world()->get_scenario().get_id()), &nodes); - - if (nodes.size() > 1) { - return TTR("Only one WorldEnvironment is allowed per scene (or set of instanced scenes)."); - } - - // Commenting this warning for now, I think it makes no sense. If anyone can figure out what its supposed to do, feedback welcome. Else it should be deprecated. - //if (environment.is_valid() && get_viewport() && !get_viewport()->get_camera() && environment->get_background() != Environment::BG_CANVAS) { - // return TTR("This WorldEnvironment is ignored. Either add a Camera (for 3D scenes) or set this environment's Background Mode to Canvas (for 2D scenes)."); - //} - - return String(); -} - -void WorldEnvironment::_bind_methods() { - - ClassDB::bind_method(D_METHOD("set_environment", "env"), &WorldEnvironment::set_environment); - ClassDB::bind_method(D_METHOD("get_environment"), &WorldEnvironment::get_environment); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "environment", PROPERTY_HINT_RESOURCE_TYPE, "Environment"), "set_environment", "get_environment"); -} - -WorldEnvironment::WorldEnvironment() { -} diff --git a/scene/3d/scenario_fx.h b/scene/3d/scenario_fx.h deleted file mode 100644 index 6317dae75d..0000000000 --- a/scene/3d/scenario_fx.h +++ /dev/null @@ -1,59 +0,0 @@ -/*************************************************************************/ -/* scenario_fx.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#ifndef SCENARIO_FX_H -#define SCENARIO_FX_H - -#include "scene/3d/spatial.h" - -/** - @author Juan Linietsky -*/ - -class WorldEnvironment : public Node { - - GDCLASS(WorldEnvironment, Node); - - Ref environment; - -protected: - void _notification(int p_what); - static void _bind_methods(); - -public: - void set_environment(const Ref &p_environment); - Ref get_environment() const; - - String get_configuration_warning() const; - - WorldEnvironment(); -}; - -#endif diff --git a/scene/3d/world_environment.cpp b/scene/3d/world_environment.cpp new file mode 100644 index 0000000000..3cd43cbf5b --- /dev/null +++ b/scene/3d/world_environment.cpp @@ -0,0 +1,112 @@ +/*************************************************************************/ +/* world_environment.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "world_environment.h" +#include "scene/main/viewport.h" + +void WorldEnvironment::_notification(int p_what) { + + if (p_what == Spatial::NOTIFICATION_ENTER_WORLD || p_what == Spatial::NOTIFICATION_ENTER_TREE) { + + if (environment.is_valid()) { + if (get_viewport()->find_world()->get_environment().is_valid()) { + WARN_PRINT("World already has an environment (Another WorldEnvironment?), overriding."); + } + get_viewport()->find_world()->set_environment(environment); + add_to_group("_world_environment_" + itos(get_viewport()->find_world()->get_scenario().get_id())); + } + + } else if (p_what == Spatial::NOTIFICATION_EXIT_WORLD || p_what == Spatial::NOTIFICATION_EXIT_TREE) { + + if (environment.is_valid() && get_viewport()->find_world()->get_environment() == environment) { + get_viewport()->find_world()->set_environment(Ref()); + remove_from_group("_world_environment_" + itos(get_viewport()->find_world()->get_scenario().get_id())); + } + } +} + +void WorldEnvironment::set_environment(const Ref &p_environment) { + + if (is_inside_tree() && environment.is_valid() && get_viewport()->find_world()->get_environment() == environment) { + get_viewport()->find_world()->set_environment(Ref()); + remove_from_group("_world_environment_" + itos(get_viewport()->find_world()->get_scenario().get_id())); + //clean up + } + + environment = p_environment; + if (is_inside_tree() && environment.is_valid()) { + if (get_viewport()->find_world()->get_environment().is_valid()) { + WARN_PRINT("World already has an environment (Another WorldEnvironment?), overriding."); + } + get_viewport()->find_world()->set_environment(environment); + add_to_group("_world_environment_" + itos(get_viewport()->find_world()->get_scenario().get_id())); + } + + update_configuration_warning(); +} + +Ref WorldEnvironment::get_environment() const { + + return environment; +} + +String WorldEnvironment::get_configuration_warning() const { + + if (!environment.is_valid()) { + return TTR("WorldEnvironment needs an Environment resource."); + } + + if (/*!is_visible_in_tree() ||*/ !is_inside_tree()) + return String(); + + List nodes; + get_tree()->get_nodes_in_group("_world_environment_" + itos(get_viewport()->find_world()->get_scenario().get_id()), &nodes); + + if (nodes.size() > 1) { + return TTR("Only one WorldEnvironment is allowed per scene (or set of instanced scenes)."); + } + + // Commenting this warning for now, I think it makes no sense. If anyone can figure out what its supposed to do, feedback welcome. Else it should be deprecated. + //if (environment.is_valid() && get_viewport() && !get_viewport()->get_camera() && environment->get_background() != Environment::BG_CANVAS) { + // return TTR("This WorldEnvironment is ignored. Either add a Camera (for 3D scenes) or set this environment's Background Mode to Canvas (for 2D scenes)."); + //} + + return String(); +} + +void WorldEnvironment::_bind_methods() { + + ClassDB::bind_method(D_METHOD("set_environment", "env"), &WorldEnvironment::set_environment); + ClassDB::bind_method(D_METHOD("get_environment"), &WorldEnvironment::get_environment); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "environment", PROPERTY_HINT_RESOURCE_TYPE, "Environment"), "set_environment", "get_environment"); +} + +WorldEnvironment::WorldEnvironment() { +} diff --git a/scene/3d/world_environment.h b/scene/3d/world_environment.h new file mode 100644 index 0000000000..bf36a0a532 --- /dev/null +++ b/scene/3d/world_environment.h @@ -0,0 +1,59 @@ +/*************************************************************************/ +/* world_environment.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef SCENARIO_FX_H +#define SCENARIO_FX_H + +#include "scene/3d/spatial.h" + +/** + @author Juan Linietsky +*/ + +class WorldEnvironment : public Node { + + GDCLASS(WorldEnvironment, Node); + + Ref environment; + +protected: + void _notification(int p_what); + static void _bind_methods(); + +public: + void set_environment(const Ref &p_environment); + Ref get_environment() const; + + String get_configuration_warning() const; + + WorldEnvironment(); +}; + +#endif diff --git a/scene/audio/audio_player.cpp b/scene/audio/audio_player.cpp deleted file mode 100644 index 4eae3b04e7..0000000000 --- a/scene/audio/audio_player.cpp +++ /dev/null @@ -1,395 +0,0 @@ -/*************************************************************************/ -/* audio_player.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#include "audio_player.h" - -#include "core/engine.h" - -void AudioStreamPlayer::_mix_internal(bool p_fadeout) { - - int bus_index = AudioServer::get_singleton()->thread_find_bus_index(bus); - - //get data - AudioFrame *buffer = mix_buffer.ptrw(); - int buffer_size = mix_buffer.size(); - - if (p_fadeout) { - // Short fadeout ramp - buffer_size = MIN(buffer_size, 128); - } - - stream_playback->mix(buffer, pitch_scale, buffer_size); - - //multiply volume interpolating to avoid clicks if this changes - float target_volume = p_fadeout ? -80.0 : volume_db; - float vol = Math::db2linear(mix_volume_db); - float vol_inc = (Math::db2linear(target_volume) - vol) / float(buffer_size); - - for (int i = 0; i < buffer_size; i++) { - buffer[i] *= vol; - vol += vol_inc; - } - - //set volume for next mix - mix_volume_db = target_volume; - - AudioFrame *targets[4] = { NULL, NULL, NULL, NULL }; - - if (AudioServer::get_singleton()->get_speaker_mode() == AudioServer::SPEAKER_MODE_STEREO) { - targets[0] = AudioServer::get_singleton()->thread_get_channel_mix_buffer(bus_index, 0); - } else { - switch (mix_target) { - case MIX_TARGET_STEREO: { - targets[0] = AudioServer::get_singleton()->thread_get_channel_mix_buffer(bus_index, 0); - } break; - case MIX_TARGET_SURROUND: { - for (int i = 0; i < AudioServer::get_singleton()->get_channel_count(); i++) { - targets[i] = AudioServer::get_singleton()->thread_get_channel_mix_buffer(bus_index, i); - } - } break; - case MIX_TARGET_CENTER: { - targets[0] = AudioServer::get_singleton()->thread_get_channel_mix_buffer(bus_index, 1); - } break; - } - } - - for (int c = 0; c < 4; c++) { - if (!targets[c]) - break; - for (int i = 0; i < buffer_size; i++) { - targets[c][i] += buffer[i]; - } - } -} - -void AudioStreamPlayer::_mix_audio() { - - if (!stream_playback.is_valid() || !active) - return; - - if (stream_paused) { - if (stream_paused_fade) { - _mix_internal(true); - stream_paused_fade = false; - } - return; - } - - if (setseek >= 0.0) { - if (stream_playback->is_playing()) { - - //fade out to avoid pops - _mix_internal(true); - } - stream_playback->start(setseek); - setseek = -1.0; //reset seek - mix_volume_db = volume_db; //reset ramp - } - - _mix_internal(false); -} - -void AudioStreamPlayer::_notification(int p_what) { - - if (p_what == NOTIFICATION_ENTER_TREE) { - - AudioServer::get_singleton()->add_callback(_mix_audios, this); - if (autoplay && !Engine::get_singleton()->is_editor_hint()) { - play(); - } - } - - if (p_what == NOTIFICATION_INTERNAL_PROCESS) { - - if (!active || (setseek < 0 && !stream_playback->is_playing())) { - active = false; - set_process_internal(false); - emit_signal("finished"); - } - } - - if (p_what == NOTIFICATION_EXIT_TREE) { - - AudioServer::get_singleton()->remove_callback(_mix_audios, this); - } - - if (p_what == NOTIFICATION_PAUSED) { - if (!can_process()) { - // Node can't process so we start fading out to silence - set_stream_paused(true); - } - } - - if (p_what == NOTIFICATION_UNPAUSED) { - set_stream_paused(false); - } -} - -void AudioStreamPlayer::set_stream(Ref p_stream) { - - AudioServer::get_singleton()->lock(); - - mix_buffer.resize(AudioServer::get_singleton()->thread_get_mix_buffer_size()); - - if (stream_playback.is_valid()) { - stream_playback.unref(); - stream.unref(); - active = false; - setseek = -1; - } - - if (p_stream.is_valid()) { - stream = p_stream; - stream_playback = p_stream->instance_playback(); - } - - AudioServer::get_singleton()->unlock(); - - if (p_stream.is_valid() && stream_playback.is_null()) { - stream.unref(); - } -} - -Ref AudioStreamPlayer::get_stream() const { - - return stream; -} - -void AudioStreamPlayer::set_volume_db(float p_volume) { - - volume_db = p_volume; -} -float AudioStreamPlayer::get_volume_db() const { - - return volume_db; -} - -void AudioStreamPlayer::set_pitch_scale(float p_pitch_scale) { - ERR_FAIL_COND(p_pitch_scale <= 0.0); - pitch_scale = p_pitch_scale; -} -float AudioStreamPlayer::get_pitch_scale() const { - return pitch_scale; -} - -void AudioStreamPlayer::play(float p_from_pos) { - - if (stream_playback.is_valid()) { - //mix_volume_db = volume_db; do not reset volume ramp here, can cause clicks - setseek = p_from_pos; - active = true; - set_process_internal(true); - } -} - -void AudioStreamPlayer::seek(float p_seconds) { - - if (stream_playback.is_valid()) { - setseek = p_seconds; - } -} - -void AudioStreamPlayer::stop() { - - if (stream_playback.is_valid()) { - stream_playback->stop(); - active = false; - set_process_internal(false); - } -} - -bool AudioStreamPlayer::is_playing() const { - - if (stream_playback.is_valid()) { - return active; //&& stream_playback->is_playing(); - } - - return false; -} - -float AudioStreamPlayer::get_playback_position() { - - if (stream_playback.is_valid()) { - return stream_playback->get_playback_position(); - } - - return 0; -} - -void AudioStreamPlayer::set_bus(const StringName &p_bus) { - - //if audio is active, must lock this - AudioServer::get_singleton()->lock(); - bus = p_bus; - AudioServer::get_singleton()->unlock(); -} -StringName AudioStreamPlayer::get_bus() const { - - for (int i = 0; i < AudioServer::get_singleton()->get_bus_count(); i++) { - if (AudioServer::get_singleton()->get_bus_name(i) == bus) { - return bus; - } - } - return "Master"; -} - -void AudioStreamPlayer::set_autoplay(bool p_enable) { - - autoplay = p_enable; -} -bool AudioStreamPlayer::is_autoplay_enabled() { - - return autoplay; -} - -void AudioStreamPlayer::set_mix_target(MixTarget p_target) { - - mix_target = p_target; -} - -AudioStreamPlayer::MixTarget AudioStreamPlayer::get_mix_target() const { - - return mix_target; -} - -void AudioStreamPlayer::_set_playing(bool p_enable) { - - if (p_enable) - play(); - else - stop(); -} -bool AudioStreamPlayer::_is_active() const { - - return active; -} - -void AudioStreamPlayer::set_stream_paused(bool p_pause) { - - if (p_pause != stream_paused) { - stream_paused = p_pause; - stream_paused_fade = p_pause ? true : false; - } -} - -bool AudioStreamPlayer::get_stream_paused() const { - - return stream_paused; -} - -void AudioStreamPlayer::_validate_property(PropertyInfo &property) const { - - if (property.name == "bus") { - - String options; - for (int i = 0; i < AudioServer::get_singleton()->get_bus_count(); i++) { - if (i > 0) - options += ","; - String name = AudioServer::get_singleton()->get_bus_name(i); - options += name; - } - - property.hint_string = options; - } -} - -void AudioStreamPlayer::_bus_layout_changed() { - - _change_notify(); -} - -void AudioStreamPlayer::_bind_methods() { - - ClassDB::bind_method(D_METHOD("set_stream", "stream"), &AudioStreamPlayer::set_stream); - ClassDB::bind_method(D_METHOD("get_stream"), &AudioStreamPlayer::get_stream); - - ClassDB::bind_method(D_METHOD("set_volume_db", "volume_db"), &AudioStreamPlayer::set_volume_db); - ClassDB::bind_method(D_METHOD("get_volume_db"), &AudioStreamPlayer::get_volume_db); - - ClassDB::bind_method(D_METHOD("set_pitch_scale", "pitch_scale"), &AudioStreamPlayer::set_pitch_scale); - ClassDB::bind_method(D_METHOD("get_pitch_scale"), &AudioStreamPlayer::get_pitch_scale); - - ClassDB::bind_method(D_METHOD("play", "from_position"), &AudioStreamPlayer::play, DEFVAL(0.0)); - ClassDB::bind_method(D_METHOD("seek", "to_position"), &AudioStreamPlayer::seek); - ClassDB::bind_method(D_METHOD("stop"), &AudioStreamPlayer::stop); - - ClassDB::bind_method(D_METHOD("is_playing"), &AudioStreamPlayer::is_playing); - ClassDB::bind_method(D_METHOD("get_playback_position"), &AudioStreamPlayer::get_playback_position); - - ClassDB::bind_method(D_METHOD("set_bus", "bus"), &AudioStreamPlayer::set_bus); - ClassDB::bind_method(D_METHOD("get_bus"), &AudioStreamPlayer::get_bus); - - ClassDB::bind_method(D_METHOD("set_autoplay", "enable"), &AudioStreamPlayer::set_autoplay); - ClassDB::bind_method(D_METHOD("is_autoplay_enabled"), &AudioStreamPlayer::is_autoplay_enabled); - - ClassDB::bind_method(D_METHOD("set_mix_target", "mix_target"), &AudioStreamPlayer::set_mix_target); - ClassDB::bind_method(D_METHOD("get_mix_target"), &AudioStreamPlayer::get_mix_target); - - ClassDB::bind_method(D_METHOD("_set_playing", "enable"), &AudioStreamPlayer::_set_playing); - ClassDB::bind_method(D_METHOD("_is_active"), &AudioStreamPlayer::_is_active); - - ClassDB::bind_method(D_METHOD("_bus_layout_changed"), &AudioStreamPlayer::_bus_layout_changed); - - ClassDB::bind_method(D_METHOD("set_stream_paused", "pause"), &AudioStreamPlayer::set_stream_paused); - ClassDB::bind_method(D_METHOD("get_stream_paused"), &AudioStreamPlayer::get_stream_paused); - - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "stream", PROPERTY_HINT_RESOURCE_TYPE, "AudioStream"), "set_stream", "get_stream"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "volume_db", PROPERTY_HINT_RANGE, "-80,24"), "set_volume_db", "get_volume_db"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "pitch_scale", PROPERTY_HINT_RANGE, "0.01,32,0.01"), "set_pitch_scale", "get_pitch_scale"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "playing", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "_set_playing", "is_playing"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "autoplay"), "set_autoplay", "is_autoplay_enabled"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "stream_paused", PROPERTY_HINT_NONE, ""), "set_stream_paused", "get_stream_paused"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "mix_target", PROPERTY_HINT_ENUM, "Stereo,Surround,Center"), "set_mix_target", "get_mix_target"); - ADD_PROPERTY(PropertyInfo(Variant::STRING, "bus", PROPERTY_HINT_ENUM, ""), "set_bus", "get_bus"); - - ADD_SIGNAL(MethodInfo("finished")); - - BIND_ENUM_CONSTANT(MIX_TARGET_STEREO); - BIND_ENUM_CONSTANT(MIX_TARGET_SURROUND); - BIND_ENUM_CONSTANT(MIX_TARGET_CENTER); -} - -AudioStreamPlayer::AudioStreamPlayer() { - - mix_volume_db = 0; - pitch_scale = 1.0; - volume_db = 0; - autoplay = false; - setseek = -1; - active = false; - stream_paused = false; - stream_paused_fade = false; - mix_target = MIX_TARGET_STEREO; - - AudioServer::get_singleton()->connect("bus_layout_changed", this, "_bus_layout_changed"); -} - -AudioStreamPlayer::~AudioStreamPlayer() { -} diff --git a/scene/audio/audio_player.h b/scene/audio/audio_player.h deleted file mode 100644 index 2e9526c335..0000000000 --- a/scene/audio/audio_player.h +++ /dev/null @@ -1,113 +0,0 @@ -/*************************************************************************/ -/* audio_player.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#ifndef AUDIOPLAYER_H -#define AUDIOPLAYER_H - -#include "scene/main/node.h" -#include "servers/audio/audio_stream.h" - -class AudioStreamPlayer : public Node { - - GDCLASS(AudioStreamPlayer, Node) - -public: - enum MixTarget { - MIX_TARGET_STEREO, - MIX_TARGET_SURROUND, - MIX_TARGET_CENTER - }; - -private: - Ref stream_playback; - Ref stream; - Vector mix_buffer; - - volatile float setseek; - volatile bool active; - - float mix_volume_db; - float pitch_scale; - float volume_db; - bool autoplay; - bool stream_paused; - bool stream_paused_fade; - StringName bus; - - MixTarget mix_target; - - void _mix_internal(bool p_fadeout); - void _mix_audio(); - static void _mix_audios(void *self) { reinterpret_cast(self)->_mix_audio(); } - - void _set_playing(bool p_enable); - bool _is_active() const; - - void _bus_layout_changed(); - -protected: - void _validate_property(PropertyInfo &property) const; - void _notification(int p_what); - static void _bind_methods(); - -public: - void set_stream(Ref p_stream); - Ref get_stream() const; - - void set_volume_db(float p_volume); - float get_volume_db() const; - - void set_pitch_scale(float p_pitch_scale); - float get_pitch_scale() const; - - void play(float p_from_pos = 0.0); - void seek(float p_seconds); - void stop(); - bool is_playing() const; - float get_playback_position(); - - void set_bus(const StringName &p_bus); - StringName get_bus() const; - - void set_autoplay(bool p_enable); - bool is_autoplay_enabled(); - - void set_mix_target(MixTarget p_target); - MixTarget get_mix_target() const; - - void set_stream_paused(bool p_pause); - bool get_stream_paused() const; - - AudioStreamPlayer(); - ~AudioStreamPlayer(); -}; - -VARIANT_ENUM_CAST(AudioStreamPlayer::MixTarget) -#endif // AUDIOPLAYER_H diff --git a/scene/audio/audio_stream_player.cpp b/scene/audio/audio_stream_player.cpp new file mode 100644 index 0000000000..e6864e2117 --- /dev/null +++ b/scene/audio/audio_stream_player.cpp @@ -0,0 +1,395 @@ +/*************************************************************************/ +/* audio_stream_player.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "audio_stream_player.h" + +#include "core/engine.h" + +void AudioStreamPlayer::_mix_internal(bool p_fadeout) { + + int bus_index = AudioServer::get_singleton()->thread_find_bus_index(bus); + + //get data + AudioFrame *buffer = mix_buffer.ptrw(); + int buffer_size = mix_buffer.size(); + + if (p_fadeout) { + // Short fadeout ramp + buffer_size = MIN(buffer_size, 128); + } + + stream_playback->mix(buffer, pitch_scale, buffer_size); + + //multiply volume interpolating to avoid clicks if this changes + float target_volume = p_fadeout ? -80.0 : volume_db; + float vol = Math::db2linear(mix_volume_db); + float vol_inc = (Math::db2linear(target_volume) - vol) / float(buffer_size); + + for (int i = 0; i < buffer_size; i++) { + buffer[i] *= vol; + vol += vol_inc; + } + + //set volume for next mix + mix_volume_db = target_volume; + + AudioFrame *targets[4] = { NULL, NULL, NULL, NULL }; + + if (AudioServer::get_singleton()->get_speaker_mode() == AudioServer::SPEAKER_MODE_STEREO) { + targets[0] = AudioServer::get_singleton()->thread_get_channel_mix_buffer(bus_index, 0); + } else { + switch (mix_target) { + case MIX_TARGET_STEREO: { + targets[0] = AudioServer::get_singleton()->thread_get_channel_mix_buffer(bus_index, 0); + } break; + case MIX_TARGET_SURROUND: { + for (int i = 0; i < AudioServer::get_singleton()->get_channel_count(); i++) { + targets[i] = AudioServer::get_singleton()->thread_get_channel_mix_buffer(bus_index, i); + } + } break; + case MIX_TARGET_CENTER: { + targets[0] = AudioServer::get_singleton()->thread_get_channel_mix_buffer(bus_index, 1); + } break; + } + } + + for (int c = 0; c < 4; c++) { + if (!targets[c]) + break; + for (int i = 0; i < buffer_size; i++) { + targets[c][i] += buffer[i]; + } + } +} + +void AudioStreamPlayer::_mix_audio() { + + if (!stream_playback.is_valid() || !active) + return; + + if (stream_paused) { + if (stream_paused_fade) { + _mix_internal(true); + stream_paused_fade = false; + } + return; + } + + if (setseek >= 0.0) { + if (stream_playback->is_playing()) { + + //fade out to avoid pops + _mix_internal(true); + } + stream_playback->start(setseek); + setseek = -1.0; //reset seek + mix_volume_db = volume_db; //reset ramp + } + + _mix_internal(false); +} + +void AudioStreamPlayer::_notification(int p_what) { + + if (p_what == NOTIFICATION_ENTER_TREE) { + + AudioServer::get_singleton()->add_callback(_mix_audios, this); + if (autoplay && !Engine::get_singleton()->is_editor_hint()) { + play(); + } + } + + if (p_what == NOTIFICATION_INTERNAL_PROCESS) { + + if (!active || (setseek < 0 && !stream_playback->is_playing())) { + active = false; + set_process_internal(false); + emit_signal("finished"); + } + } + + if (p_what == NOTIFICATION_EXIT_TREE) { + + AudioServer::get_singleton()->remove_callback(_mix_audios, this); + } + + if (p_what == NOTIFICATION_PAUSED) { + if (!can_process()) { + // Node can't process so we start fading out to silence + set_stream_paused(true); + } + } + + if (p_what == NOTIFICATION_UNPAUSED) { + set_stream_paused(false); + } +} + +void AudioStreamPlayer::set_stream(Ref p_stream) { + + AudioServer::get_singleton()->lock(); + + mix_buffer.resize(AudioServer::get_singleton()->thread_get_mix_buffer_size()); + + if (stream_playback.is_valid()) { + stream_playback.unref(); + stream.unref(); + active = false; + setseek = -1; + } + + if (p_stream.is_valid()) { + stream = p_stream; + stream_playback = p_stream->instance_playback(); + } + + AudioServer::get_singleton()->unlock(); + + if (p_stream.is_valid() && stream_playback.is_null()) { + stream.unref(); + } +} + +Ref AudioStreamPlayer::get_stream() const { + + return stream; +} + +void AudioStreamPlayer::set_volume_db(float p_volume) { + + volume_db = p_volume; +} +float AudioStreamPlayer::get_volume_db() const { + + return volume_db; +} + +void AudioStreamPlayer::set_pitch_scale(float p_pitch_scale) { + ERR_FAIL_COND(p_pitch_scale <= 0.0); + pitch_scale = p_pitch_scale; +} +float AudioStreamPlayer::get_pitch_scale() const { + return pitch_scale; +} + +void AudioStreamPlayer::play(float p_from_pos) { + + if (stream_playback.is_valid()) { + //mix_volume_db = volume_db; do not reset volume ramp here, can cause clicks + setseek = p_from_pos; + active = true; + set_process_internal(true); + } +} + +void AudioStreamPlayer::seek(float p_seconds) { + + if (stream_playback.is_valid()) { + setseek = p_seconds; + } +} + +void AudioStreamPlayer::stop() { + + if (stream_playback.is_valid()) { + stream_playback->stop(); + active = false; + set_process_internal(false); + } +} + +bool AudioStreamPlayer::is_playing() const { + + if (stream_playback.is_valid()) { + return active; //&& stream_playback->is_playing(); + } + + return false; +} + +float AudioStreamPlayer::get_playback_position() { + + if (stream_playback.is_valid()) { + return stream_playback->get_playback_position(); + } + + return 0; +} + +void AudioStreamPlayer::set_bus(const StringName &p_bus) { + + //if audio is active, must lock this + AudioServer::get_singleton()->lock(); + bus = p_bus; + AudioServer::get_singleton()->unlock(); +} +StringName AudioStreamPlayer::get_bus() const { + + for (int i = 0; i < AudioServer::get_singleton()->get_bus_count(); i++) { + if (AudioServer::get_singleton()->get_bus_name(i) == bus) { + return bus; + } + } + return "Master"; +} + +void AudioStreamPlayer::set_autoplay(bool p_enable) { + + autoplay = p_enable; +} +bool AudioStreamPlayer::is_autoplay_enabled() { + + return autoplay; +} + +void AudioStreamPlayer::set_mix_target(MixTarget p_target) { + + mix_target = p_target; +} + +AudioStreamPlayer::MixTarget AudioStreamPlayer::get_mix_target() const { + + return mix_target; +} + +void AudioStreamPlayer::_set_playing(bool p_enable) { + + if (p_enable) + play(); + else + stop(); +} +bool AudioStreamPlayer::_is_active() const { + + return active; +} + +void AudioStreamPlayer::set_stream_paused(bool p_pause) { + + if (p_pause != stream_paused) { + stream_paused = p_pause; + stream_paused_fade = p_pause ? true : false; + } +} + +bool AudioStreamPlayer::get_stream_paused() const { + + return stream_paused; +} + +void AudioStreamPlayer::_validate_property(PropertyInfo &property) const { + + if (property.name == "bus") { + + String options; + for (int i = 0; i < AudioServer::get_singleton()->get_bus_count(); i++) { + if (i > 0) + options += ","; + String name = AudioServer::get_singleton()->get_bus_name(i); + options += name; + } + + property.hint_string = options; + } +} + +void AudioStreamPlayer::_bus_layout_changed() { + + _change_notify(); +} + +void AudioStreamPlayer::_bind_methods() { + + ClassDB::bind_method(D_METHOD("set_stream", "stream"), &AudioStreamPlayer::set_stream); + ClassDB::bind_method(D_METHOD("get_stream"), &AudioStreamPlayer::get_stream); + + ClassDB::bind_method(D_METHOD("set_volume_db", "volume_db"), &AudioStreamPlayer::set_volume_db); + ClassDB::bind_method(D_METHOD("get_volume_db"), &AudioStreamPlayer::get_volume_db); + + ClassDB::bind_method(D_METHOD("set_pitch_scale", "pitch_scale"), &AudioStreamPlayer::set_pitch_scale); + ClassDB::bind_method(D_METHOD("get_pitch_scale"), &AudioStreamPlayer::get_pitch_scale); + + ClassDB::bind_method(D_METHOD("play", "from_position"), &AudioStreamPlayer::play, DEFVAL(0.0)); + ClassDB::bind_method(D_METHOD("seek", "to_position"), &AudioStreamPlayer::seek); + ClassDB::bind_method(D_METHOD("stop"), &AudioStreamPlayer::stop); + + ClassDB::bind_method(D_METHOD("is_playing"), &AudioStreamPlayer::is_playing); + ClassDB::bind_method(D_METHOD("get_playback_position"), &AudioStreamPlayer::get_playback_position); + + ClassDB::bind_method(D_METHOD("set_bus", "bus"), &AudioStreamPlayer::set_bus); + ClassDB::bind_method(D_METHOD("get_bus"), &AudioStreamPlayer::get_bus); + + ClassDB::bind_method(D_METHOD("set_autoplay", "enable"), &AudioStreamPlayer::set_autoplay); + ClassDB::bind_method(D_METHOD("is_autoplay_enabled"), &AudioStreamPlayer::is_autoplay_enabled); + + ClassDB::bind_method(D_METHOD("set_mix_target", "mix_target"), &AudioStreamPlayer::set_mix_target); + ClassDB::bind_method(D_METHOD("get_mix_target"), &AudioStreamPlayer::get_mix_target); + + ClassDB::bind_method(D_METHOD("_set_playing", "enable"), &AudioStreamPlayer::_set_playing); + ClassDB::bind_method(D_METHOD("_is_active"), &AudioStreamPlayer::_is_active); + + ClassDB::bind_method(D_METHOD("_bus_layout_changed"), &AudioStreamPlayer::_bus_layout_changed); + + ClassDB::bind_method(D_METHOD("set_stream_paused", "pause"), &AudioStreamPlayer::set_stream_paused); + ClassDB::bind_method(D_METHOD("get_stream_paused"), &AudioStreamPlayer::get_stream_paused); + + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "stream", PROPERTY_HINT_RESOURCE_TYPE, "AudioStream"), "set_stream", "get_stream"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "volume_db", PROPERTY_HINT_RANGE, "-80,24"), "set_volume_db", "get_volume_db"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "pitch_scale", PROPERTY_HINT_RANGE, "0.01,32,0.01"), "set_pitch_scale", "get_pitch_scale"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "playing", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "_set_playing", "is_playing"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "autoplay"), "set_autoplay", "is_autoplay_enabled"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "stream_paused", PROPERTY_HINT_NONE, ""), "set_stream_paused", "get_stream_paused"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "mix_target", PROPERTY_HINT_ENUM, "Stereo,Surround,Center"), "set_mix_target", "get_mix_target"); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "bus", PROPERTY_HINT_ENUM, ""), "set_bus", "get_bus"); + + ADD_SIGNAL(MethodInfo("finished")); + + BIND_ENUM_CONSTANT(MIX_TARGET_STEREO); + BIND_ENUM_CONSTANT(MIX_TARGET_SURROUND); + BIND_ENUM_CONSTANT(MIX_TARGET_CENTER); +} + +AudioStreamPlayer::AudioStreamPlayer() { + + mix_volume_db = 0; + pitch_scale = 1.0; + volume_db = 0; + autoplay = false; + setseek = -1; + active = false; + stream_paused = false; + stream_paused_fade = false; + mix_target = MIX_TARGET_STEREO; + + AudioServer::get_singleton()->connect("bus_layout_changed", this, "_bus_layout_changed"); +} + +AudioStreamPlayer::~AudioStreamPlayer() { +} diff --git a/scene/audio/audio_stream_player.h b/scene/audio/audio_stream_player.h new file mode 100644 index 0000000000..0f7713bf33 --- /dev/null +++ b/scene/audio/audio_stream_player.h @@ -0,0 +1,114 @@ +/*************************************************************************/ +/* audio_stream_player.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef AUDIO_STREAM_PLAYER_H +#define AUDIO_STREAM_PLAYER_H + +#include "scene/main/node.h" +#include "servers/audio/audio_stream.h" + +class AudioStreamPlayer : public Node { + + GDCLASS(AudioStreamPlayer, Node) + +public: + enum MixTarget { + MIX_TARGET_STEREO, + MIX_TARGET_SURROUND, + MIX_TARGET_CENTER + }; + +private: + Ref stream_playback; + Ref stream; + Vector mix_buffer; + + volatile float setseek; + volatile bool active; + + float mix_volume_db; + float pitch_scale; + float volume_db; + bool autoplay; + bool stream_paused; + bool stream_paused_fade; + StringName bus; + + MixTarget mix_target; + + void _mix_internal(bool p_fadeout); + void _mix_audio(); + static void _mix_audios(void *self) { reinterpret_cast(self)->_mix_audio(); } + + void _set_playing(bool p_enable); + bool _is_active() const; + + void _bus_layout_changed(); + +protected: + void _validate_property(PropertyInfo &property) const; + void _notification(int p_what); + static void _bind_methods(); + +public: + void set_stream(Ref p_stream); + Ref get_stream() const; + + void set_volume_db(float p_volume); + float get_volume_db() const; + + void set_pitch_scale(float p_pitch_scale); + float get_pitch_scale() const; + + void play(float p_from_pos = 0.0); + void seek(float p_seconds); + void stop(); + bool is_playing() const; + float get_playback_position(); + + void set_bus(const StringName &p_bus); + StringName get_bus() const; + + void set_autoplay(bool p_enable); + bool is_autoplay_enabled(); + + void set_mix_target(MixTarget p_target); + MixTarget get_mix_target() const; + + void set_stream_paused(bool p_pause); + bool get_stream_paused() const; + + AudioStreamPlayer(); + ~AudioStreamPlayer(); +}; + +VARIANT_ENUM_CAST(AudioStreamPlayer::MixTarget) + +#endif // AUDIO_STREAM_PLAYER_H diff --git a/scene/gui/gradient_edit.h b/scene/gui/gradient_edit.h index fd340b3f6c..662278a17b 100644 --- a/scene/gui/gradient_edit.h +++ b/scene/gui/gradient_edit.h @@ -33,8 +33,8 @@ #include "scene/gui/color_picker.h" #include "scene/gui/popup.h" -#include "scene/resources/color_ramp.h" #include "scene/resources/default_theme/theme_data.h" +#include "scene/resources/gradient.h" #define POINT_WIDTH (8 * EDSCALE) diff --git a/scene/gui/link_button.h b/scene/gui/link_button.h index ffe248ac5e..17c4bca67b 100644 --- a/scene/gui/link_button.h +++ b/scene/gui/link_button.h @@ -32,7 +32,7 @@ #define LINKBUTTON_H #include "scene/gui/base_button.h" -#include "scene/resources/bit_mask.h" +#include "scene/resources/bit_map.h" class LinkButton : public BaseButton { diff --git a/scene/gui/texture_button.h b/scene/gui/texture_button.h index 4dc0de5358..d9224de686 100644 --- a/scene/gui/texture_button.h +++ b/scene/gui/texture_button.h @@ -32,7 +32,7 @@ #define TEXTURE_BUTTON_H #include "scene/gui/base_button.h" -#include "scene/resources/bit_mask.h" +#include "scene/resources/bit_map.h" class TextureButton : public BaseButton { GDCLASS(TextureButton, BaseButton); diff --git a/scene/main/scene_tree.h b/scene/main/scene_tree.h index 3a1ff5cb06..e15a64604d 100644 --- a/scene/main/scene_tree.h +++ b/scene/main/scene_tree.h @@ -43,7 +43,6 @@ @author Juan Linietsky */ -class SceneTree; class PackedScene; class Node; class Viewport; diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp index 61d6fc7401..c66814d115 100644 --- a/scene/main/viewport.cpp +++ b/scene/main/viewport.cpp @@ -37,8 +37,8 @@ #include "scene/3d/camera.h" #include "scene/3d/collision_object.h" #include "scene/3d/listener.h" -#include "scene/3d/scenario_fx.h" #include "scene/3d/spatial.h" +#include "scene/3d/world_environment.h" #include "scene/gui/control.h" #include "scene/gui/label.h" #include "scene/gui/menu_button.h" diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp index 078d880d0e..49c9c4c23c 100644 --- a/scene/register_scene_types.cpp +++ b/scene/register_scene_types.cpp @@ -48,7 +48,7 @@ #include "scene/2d/light_occluder_2d.h" #include "scene/2d/line_2d.h" #include "scene/2d/mesh_instance_2d.h" -#include "scene/2d/navigation2d.h" +#include "scene/2d/navigation_2d.h" #include "scene/2d/parallax_background.h" #include "scene/2d/parallax_layer.h" #include "scene/2d/particles_2d.h" @@ -58,10 +58,10 @@ #include "scene/2d/position_2d.h" #include "scene/2d/ray_cast_2d.h" #include "scene/2d/remote_transform_2d.h" -#include "scene/2d/screen_button.h" #include "scene/2d/skeleton_2d.h" #include "scene/2d/sprite.h" #include "scene/2d/tile_map.h" +#include "scene/2d/touch_screen_button.h" #include "scene/2d/visibility_notifier_2d.h" #include "scene/2d/y_sort.h" #include "scene/animation/animation_blend_space_1d.h" @@ -73,7 +73,7 @@ #include "scene/animation/animation_tree_player.h" #include "scene/animation/root_motion_view.h" #include "scene/animation/tween.h" -#include "scene/audio/audio_player.h" +#include "scene/audio/audio_stream_player.h" #include "scene/gui/box_container.h" #include "scene/gui/button.h" #include "scene/gui/center_container.h" @@ -125,12 +125,11 @@ #include "scene/main/timer.h" #include "scene/main/viewport.h" #include "scene/resources/audio_stream_sample.h" -#include "scene/resources/bit_mask.h" +#include "scene/resources/bit_map.h" #include "scene/resources/box_shape.h" #include "scene/resources/capsule_shape.h" #include "scene/resources/capsule_shape_2d.h" #include "scene/resources/circle_shape_2d.h" -#include "scene/resources/color_ramp.h" #include "scene/resources/concave_polygon_shape.h" #include "scene/resources/concave_polygon_shape_2d.h" #include "scene/resources/convex_polygon_shape.h" @@ -139,6 +138,8 @@ #include "scene/resources/default_theme/default_theme.h" #include "scene/resources/dynamic_font.h" #include "scene/resources/dynamic_font_stb.h" +#include "scene/resources/gradient.h" +#include "scene/resources/line_shape_2d.h" #include "scene/resources/material.h" #include "scene/resources/mesh.h" #include "scene/resources/mesh_data_tool.h" @@ -151,10 +152,9 @@ #include "scene/resources/primitive_meshes.h" #include "scene/resources/ray_shape.h" #include "scene/resources/rectangle_shape_2d.h" -#include "scene/resources/scene_format_text.h" +#include "scene/resources/resource_format_text.h" #include "scene/resources/segment_shape_2d.h" -#include "scene/resources/shape_line_2d.h" -#include "scene/resources/sky_box.h" +#include "scene/resources/sky.h" #include "scene/resources/sphere_shape.h" #include "scene/resources/surface_tool.h" #include "scene/resources/text_file.h" @@ -167,8 +167,8 @@ #include "scene/resources/world_2d.h" #include "scene/scene_string_names.h" -#include "scene/3d/scenario_fx.h" #include "scene/3d/spatial.h" +#include "scene/3d/world_environment.h" #ifndef _3D_DISABLED #include "scene/3d/area.h" diff --git a/scene/resources/bit_map.cpp b/scene/resources/bit_map.cpp new file mode 100644 index 0000000000..8263096c8f --- /dev/null +++ b/scene/resources/bit_map.cpp @@ -0,0 +1,625 @@ +/*************************************************************************/ +/* bit_map.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "bit_map.h" + +#include "core/io/image_loader.h" + +void BitMap::create(const Size2 &p_size) { + + ERR_FAIL_COND(p_size.width < 1); + ERR_FAIL_COND(p_size.height < 1); + + width = p_size.width; + height = p_size.height; + bitmask.resize(((width * height) / 8) + 1); + zeromem(bitmask.ptrw(), bitmask.size()); +} + +void BitMap::create_from_image_alpha(const Ref &p_image, float p_threshold) { + + ERR_FAIL_COND(p_image.is_null() || p_image->empty()); + Ref img = p_image->duplicate(); + img->convert(Image::FORMAT_LA8); + ERR_FAIL_COND(img->get_format() != Image::FORMAT_LA8); + + create(Size2(img->get_width(), img->get_height())); + + PoolVector::Read r = img->get_data().read(); + uint8_t *w = bitmask.ptrw(); + + for (int i = 0; i < width * height; i++) { + + int bbyte = i / 8; + int bbit = i % 8; + if (r[i * 2 + 1] / 255.0 > p_threshold) { + w[bbyte] |= (1 << bbit); + } + } +} + +void BitMap::set_bit_rect(const Rect2 &p_rect, bool p_value) { + + Rect2i current = Rect2i(0, 0, width, height).clip(p_rect); + uint8_t *data = bitmask.ptrw(); + + for (int i = current.position.x; i < current.position.x + current.size.x; i++) { + + for (int j = current.position.y; j < current.position.y + current.size.y; j++) { + + int ofs = width * j + i; + int bbyte = ofs / 8; + int bbit = ofs % 8; + + uint8_t b = data[bbyte]; + + if (p_value) + b |= (1 << bbit); + else + b &= ~(1 << bbit); + + data[bbyte] = b; + } + } +} + +int BitMap::get_true_bit_count() const { + + int ds = bitmask.size(); + const uint8_t *d = bitmask.ptr(); + int c = 0; + + //fast, almot branchless version + + for (int i = 0; i < ds; i++) { + + c += (d[i] & (1 << 7)) >> 7; + c += (d[i] & (1 << 6)) >> 6; + c += (d[i] & (1 << 5)) >> 5; + c += (d[i] & (1 << 4)) >> 4; + c += (d[i] & (1 << 3)) >> 3; + c += (d[i] & (1 << 2)) >> 2; + c += d[i] & 1; + } + + return c; +} + +void BitMap::set_bit(const Point2 &p_pos, bool p_value) { + + int x = p_pos.x; + int y = p_pos.y; + + ERR_FAIL_INDEX(x, width); + ERR_FAIL_INDEX(y, height); + + int ofs = width * y + x; + int bbyte = ofs / 8; + int bbit = ofs % 8; + + uint8_t b = bitmask[bbyte]; + + if (p_value) + b |= (1 << bbit); + else + b &= ~(1 << bbit); + + bitmask.write[bbyte] = b; +} + +bool BitMap::get_bit(const Point2 &p_pos) const { + + int x = Math::fast_ftoi(p_pos.x); + int y = Math::fast_ftoi(p_pos.y); + ERR_FAIL_INDEX_V(x, width, false); + ERR_FAIL_INDEX_V(y, height, false); + + int ofs = width * y + x; + int bbyte = ofs / 8; + int bbit = ofs % 8; + + return (bitmask[bbyte] & (1 << bbit)) != 0; +} + +Size2 BitMap::get_size() const { + + return Size2(width, height); +} + +void BitMap::_set_data(const Dictionary &p_d) { + + ERR_FAIL_COND(!p_d.has("size")); + ERR_FAIL_COND(!p_d.has("data")); + + create(p_d["size"]); + bitmask = p_d["data"]; +} + +Dictionary BitMap::_get_data() const { + + Dictionary d; + d["size"] = get_size(); + d["data"] = bitmask; + return d; +} + +Vector BitMap::_march_square(const Rect2i &rect, const Point2i &start) const { + + int stepx = 0; + int stepy = 0; + int prevx = 0; + int prevy = 0; + int startx = start.x; + int starty = start.y; + int curx = startx; + int cury = starty; + unsigned int count = 0; + Set case9s; + Set case6s; + Vector _points; + do { + int sv = 0; + { //square value + + /* + checking the 2x2 pixel grid, assigning these values to each pixel, if not transparent + +---+---+ + | 1 | 2 | + +---+---+ + | 4 | 8 | <- current pixel (curx,cury) + +---+---+ + */ + //NOTE: due to the way we pick points from texture, rect needs to be smaller, otherwise it goes outside 1 pixel + Rect2i fixed_rect = Rect2i(rect.position, rect.size - Size2i(2, 2)); + Point2i tl = Point2i(curx - 1, cury - 1); + sv += (fixed_rect.has_point(tl) && get_bit(tl)) ? 1 : 0; + Point2i tr = Point2i(curx, cury - 1); + sv += (fixed_rect.has_point(tr) && get_bit(tr)) ? 2 : 0; + Point2i bl = Point2i(curx - 1, cury); + sv += (fixed_rect.has_point(bl) && get_bit(bl)) ? 4 : 0; + Point2i br = Point2i(curx, cury); + sv += (fixed_rect.has_point(br) && get_bit(br)) ? 8 : 0; + ERR_FAIL_COND_V(sv == 0 || sv == 15, Vector()); + } + + switch (sv) { + + case 1: + case 5: + case 13: + /* going UP with these cases: + 1 5 13 + +---+---+ +---+---+ +---+---+ + | 1 | | | 1 | | | 1 | | + +---+---+ +---+---+ +---+---+ + | | | | 4 | | | 4 | 8 | + +---+---+ +---+---+ +---+---+ + */ + stepx = 0; + stepy = -1; + break; + + case 8: + case 10: + case 11: + /* going DOWN with these cases: + 8 10 11 + +---+---+ +---+---+ +---+---+ + | | | | | 2 | | 1 | 2 | + +---+---+ +---+---+ +---+---+ + | | 8 | | | 8 | | | 8 | + +---+---+ +---+---+ +---+---+ + */ + stepx = 0; + stepy = 1; + break; + + case 4: + case 12: + case 14: + /* going LEFT with these cases: + 4 12 14 + +---+---+ +---+---+ +---+---+ + | | | | | | | | 2 | + +---+---+ +---+---+ +---+---+ + | 4 | | | 4 | 8 | | 4 | 8 | + +---+---+ +---+---+ +---+---+ + */ + stepx = -1; + stepy = 0; + break; + + case 2: + case 3: + case 7: + /* going RIGHT with these cases: + 2 3 7 + +---+---+ +---+---+ +---+---+ + | | 2 | | 1 | 2 | | 1 | 2 | + +---+---+ +---+---+ +---+---+ + | | | | | | | 4 | | + +---+---+ +---+---+ +---+---+ + */ + stepx = 1; + stepy = 0; + break; + case 9: + /* + +---+---+ + | 1 | | + +---+---+ + | | 8 | + +---+---+ + this should normally go UP, but if we already been here, we go down + */ + if (case9s.has(Point2i(curx, cury))) { + //found, so we go down, and delete from case9s; + stepx = 0; + stepy = 1; + case9s.erase(Point2i(curx, cury)); + } else { + //not found, we go up, and add to case9s; + stepx = 0; + stepy = -1; + case9s.insert(Point2i(curx, cury)); + } + break; + case 6: + /* + 6 + +---+---+ + | | 2 | + +---+---+ + | 4 | | + +---+---+ + this normally go RIGHT, but if its coming from UP, it should go LEFT + */ + if (case6s.has(Point2i(curx, cury))) { + //found, so we go down, and delete from case6s; + stepx = -1; + stepy = 0; + case6s.erase(Point2i(curx, cury)); + } else { + //not found, we go up, and add to case6s; + stepx = 1; + stepy = 0; + case6s.insert(Point2i(curx, cury)); + } + break; + default: + ERR_PRINT("this shouldn't happen."); + } + //little optimization + // if previous direction is same as current direction, + // then we should modify the last vec to current + curx += stepx; + cury += stepy; + if (stepx == prevx && stepy == prevy) { + _points.write[_points.size() - 1].x = (float)(curx - rect.position.x); + _points.write[_points.size() - 1].y = (float)(cury + rect.position.y); + } else { + _points.push_back(Vector2((float)(curx - rect.position.x), (float)(cury + rect.position.y))); + } + + count++; + prevx = stepx; + prevy = stepy; + + ERR_FAIL_COND_V(count > width * height, _points); + } while (curx != startx || cury != starty); + return _points; +} + +static float perpendicular_distance(const Vector2 &i, const Vector2 &start, const Vector2 &end) { + float res; + float slope; + float intercept; + + if (start.x == end.x) { + res = Math::absf(i.x - end.x); + } else if (start.y == end.y) { + res = Math::absf(i.y - end.y); + } else { + slope = (end.y - start.y) / (end.x - start.x); + intercept = start.y - (slope * start.x); + res = Math::absf(slope * i.x - i.y + intercept) / Math::sqrt(Math::pow(slope, 2.0f) + 1.0); + } + return res; +} + +static Vector rdp(const Vector &v, float optimization) { + if (v.size() < 3) + return v; + + int index = -1; + float dist = 0; + //not looping first and last point + for (size_t i = 1, size = v.size(); i < size - 1; ++i) { + float cdist = perpendicular_distance(v[i], v[0], v[v.size() - 1]); + if (cdist > dist) { + dist = cdist; + index = static_cast(i); + } + } + if (dist > optimization) { + + Vector left, right; + left.resize(index); + for (int i = 0; i < index; i++) { + left.write[i] = v[i]; + } + right.resize(v.size() - index); + for (int i = 0; i < right.size(); i++) { + right.write[i] = v[index + i]; + } + Vector r1 = rdp(left, optimization); + Vector r2 = rdp(right, optimization); + + int middle = r1.size(); + r1.resize(r1.size() + r2.size()); + for (int i = 0; i < r2.size(); i++) { + r1.write[middle + i] = r2[i]; + } + return r1; + } else { + Vector ret; + ret.push_back(v[0]); + ret.push_back(v[v.size() - 1]); + return ret; + } +} + +static Vector reduce(const Vector &points, const Rect2i &rect, float epsilon) { + int size = points.size(); + // if there are less than 3 points, then we have nothing + ERR_FAIL_COND_V(size < 3, Vector()); + // if there are less than 9 points (but more than 3), then we don't need to reduce it + if (size < 9) { + return points; + } + + float maxEp = MIN(rect.size.width, rect.size.height); + float ep = CLAMP(epsilon, 0.0, maxEp / 2); + Vector result = rdp(points, ep); + + Vector2 last = result[result.size() - 1]; + + if (last.y > result[0].y && last.distance_to(result[0]) < ep * 0.5f) { + result.write[0].y = last.y; + result.resize(result.size() - 1); + } + return result; +} + +struct FillBitsStackEntry { + Point2i pos; + int i; + int j; +}; + +static void fill_bits(const BitMap *p_src, Ref &p_map, const Point2i &p_pos, const Rect2i &rect) { + + // Using a custom stack to work iteratively to avoid stack overflow on big bitmaps + PoolVector stack; + // Tracking size since we won't be shrinking the stack vector + int stack_size = 0; + + Point2i pos = p_pos; + int next_i = 0; + int next_j = 0; + + bool reenter = true; + bool popped = false; + do { + if (reenter) { + next_i = pos.x - 1; + next_j = pos.y - 1; + reenter = false; + } + + for (int i = next_i; i <= pos.x + 1; i++) { + for (int j = next_j; j <= pos.y + 1; j++) { + if (popped) { + // The next loop over j must start normally + next_j = pos.y; + popped = false; + // Skip because an iteration was already executed with current counter values + continue; + } + + if (i < rect.position.x || i >= rect.position.x + rect.size.x) + continue; + if (j < rect.position.y || j >= rect.position.y + rect.size.y) + continue; + + if (p_map->get_bit(Vector2(i, j))) + continue; + + else if (p_src->get_bit(Vector2(i, j))) { + p_map->set_bit(Vector2(i, j), true); + + FillBitsStackEntry se = { pos, i, j }; + stack.resize(MAX(stack_size + 1, stack.size())); + stack.set(stack_size, se); + stack_size++; + + pos = Point2i(i, j); + reenter = true; + break; + } + } + if (reenter) { + break; + } + } + if (!reenter) { + if (stack_size) { + FillBitsStackEntry se = stack.get(stack_size - 1); + stack_size--; + pos = se.pos; + next_i = se.i; + next_j = se.j; + popped = true; + } + } + } while (reenter || popped); + + print_verbose("BitMap: Max stack size: " + itos(stack.size())); +} + +Vector > BitMap::clip_opaque_to_polygons(const Rect2 &p_rect, float p_epsilon) const { + + Rect2i r = Rect2i(0, 0, width, height).clip(p_rect); + print_verbose("BitMap: Rect: " + r); + + Point2i from; + Ref fill; + fill.instance(); + fill->create(get_size()); + + Vector > polygons; + for (int i = r.position.y; i < r.position.y + r.size.height; i++) { + for (int j = r.position.x; j < r.position.x + r.size.width; j++) { + if (!fill->get_bit(Point2(j, i)) && get_bit(Point2(j, i))) { + + Vector polygon = _march_square(r, Point2i(j, i)); + print_verbose("BitMap: Pre reduce: " + itos(polygon.size())); + polygon = reduce(polygon, r, p_epsilon); + print_verbose("BitMap: Post reduce: " + itos(polygon.size())); + polygons.push_back(polygon); + fill_bits(this, fill, Point2i(j, i), r); + } + } + } + + return polygons; +} + +void BitMap::grow_mask(int p_pixels, const Rect2 &p_rect) { + + Rect2i r = Rect2i(0, 0, width, height).clip(p_rect); + + Ref copy; + copy.instance(); + copy->create(get_size()); + copy->bitmask = bitmask; + + for (int i = r.position.y; i < r.position.y + r.size.height; i++) { + for (int j = r.position.x; j < r.position.x + r.size.width; j++) { + if (copy->get_bit(Point2(j, i))) + continue; + + bool found = false; + + for (int y = i - p_pixels; y <= i + p_pixels; y++) { + for (int x = j - p_pixels; x <= j + p_pixels; x++) { + + if (x < p_rect.position.x || x >= p_rect.position.x + p_rect.size.x) + continue; + if (y < p_rect.position.y || y >= p_rect.position.y + p_rect.size.y) + continue; + + float d = Point2(j, i).distance_to(Point2(x, y)) - CMP_EPSILON; + if (d > p_pixels) + continue; + + if (copy->get_bit(Point2(x, y))) { + found = true; + break; + } + } + if (found) + break; + } + + if (found) { + set_bit(Point2(j, i), true); + } + } + } +} + +Array BitMap::_opaque_to_polygons_bind(const Rect2 &p_rect, float p_epsilon) const { + + Vector > result = clip_opaque_to_polygons(p_rect, p_epsilon); + + // Convert result to bindable types + + Array result_array; + result_array.resize(result.size()); + for (int i = 0; i < result.size(); i++) { + + const Vector &polygon = result[i]; + + PoolVector2Array polygon_array; + polygon_array.resize(polygon.size()); + + { + PoolVector2Array::Write w = polygon_array.write(); + for (int j = 0; j < polygon.size(); j++) { + w[j] = polygon[j]; + } + } + + result_array[i] = polygon_array; + } + + return result_array; +} + +void BitMap::_bind_methods() { + + ClassDB::bind_method(D_METHOD("create", "size"), &BitMap::create); + ClassDB::bind_method(D_METHOD("create_from_image_alpha", "image", "threshold"), &BitMap::create_from_image_alpha, DEFVAL(0.1)); + + ClassDB::bind_method(D_METHOD("set_bit", "position", "bit"), &BitMap::set_bit); + ClassDB::bind_method(D_METHOD("get_bit", "position"), &BitMap::get_bit); + + ClassDB::bind_method(D_METHOD("set_bit_rect", "rect", "bit"), &BitMap::set_bit_rect); + ClassDB::bind_method(D_METHOD("get_true_bit_count"), &BitMap::get_true_bit_count); + + ClassDB::bind_method(D_METHOD("get_size"), &BitMap::get_size); + + ClassDB::bind_method(D_METHOD("_set_data"), &BitMap::_set_data); + ClassDB::bind_method(D_METHOD("_get_data"), &BitMap::_get_data); + + ClassDB::bind_method(D_METHOD("grow_mask", "pixels", "rect"), &BitMap::grow_mask); + ClassDB::bind_method(D_METHOD("opaque_to_polygons", "rect", "epsilon"), &BitMap::_opaque_to_polygons_bind, DEFVAL(2.0)); + + ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_data", "_get_data"); +} + +BitMap::BitMap() { + + width = 0; + height = 0; +} + +////////////////////////////////////// diff --git a/scene/resources/bit_map.h b/scene/resources/bit_map.h new file mode 100644 index 0000000000..b3c86afd38 --- /dev/null +++ b/scene/resources/bit_map.h @@ -0,0 +1,75 @@ +/*************************************************************************/ +/* bit_map.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef BIT_MAP_H +#define BIT_MAP_H + +#include "core/image.h" +#include "core/io/resource_loader.h" +#include "core/resource.h" + +class BitMap : public Resource { + + GDCLASS(BitMap, Resource); + OBJ_SAVE_TYPE(BitMap); + + Vector bitmask; + int width; + int height; + + Vector _march_square(const Rect2i &rect, const Point2i &start) const; + + Array _opaque_to_polygons_bind(const Rect2 &p_rect, float p_epsilon) const; + +protected: + void _set_data(const Dictionary &p_d); + Dictionary _get_data() const; + + static void _bind_methods(); + +public: + void create(const Size2 &p_size); + void create_from_image_alpha(const Ref &p_image, float p_threshold = 0.1); + + void set_bit(const Point2 &p_pos, bool p_value); + bool get_bit(const Point2 &p_pos) const; + void set_bit_rect(const Rect2 &p_rect, bool p_value); + int get_true_bit_count() const; + + Size2 get_size() const; + + void grow_mask(int p_pixels, const Rect2 &p_rect); + + Vector > clip_opaque_to_polygons(const Rect2 &p_rect, float p_epsilon = 2.0) const; + + BitMap(); +}; + +#endif // BIT_MAP_H diff --git a/scene/resources/bit_mask.cpp b/scene/resources/bit_mask.cpp deleted file mode 100644 index 0e2152f244..0000000000 --- a/scene/resources/bit_mask.cpp +++ /dev/null @@ -1,625 +0,0 @@ -/*************************************************************************/ -/* bit_mask.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#include "bit_mask.h" - -#include "core/io/image_loader.h" - -void BitMap::create(const Size2 &p_size) { - - ERR_FAIL_COND(p_size.width < 1); - ERR_FAIL_COND(p_size.height < 1); - - width = p_size.width; - height = p_size.height; - bitmask.resize(((width * height) / 8) + 1); - zeromem(bitmask.ptrw(), bitmask.size()); -} - -void BitMap::create_from_image_alpha(const Ref &p_image, float p_threshold) { - - ERR_FAIL_COND(p_image.is_null() || p_image->empty()); - Ref img = p_image->duplicate(); - img->convert(Image::FORMAT_LA8); - ERR_FAIL_COND(img->get_format() != Image::FORMAT_LA8); - - create(Size2(img->get_width(), img->get_height())); - - PoolVector::Read r = img->get_data().read(); - uint8_t *w = bitmask.ptrw(); - - for (int i = 0; i < width * height; i++) { - - int bbyte = i / 8; - int bbit = i % 8; - if (r[i * 2 + 1] / 255.0 > p_threshold) { - w[bbyte] |= (1 << bbit); - } - } -} - -void BitMap::set_bit_rect(const Rect2 &p_rect, bool p_value) { - - Rect2i current = Rect2i(0, 0, width, height).clip(p_rect); - uint8_t *data = bitmask.ptrw(); - - for (int i = current.position.x; i < current.position.x + current.size.x; i++) { - - for (int j = current.position.y; j < current.position.y + current.size.y; j++) { - - int ofs = width * j + i; - int bbyte = ofs / 8; - int bbit = ofs % 8; - - uint8_t b = data[bbyte]; - - if (p_value) - b |= (1 << bbit); - else - b &= ~(1 << bbit); - - data[bbyte] = b; - } - } -} - -int BitMap::get_true_bit_count() const { - - int ds = bitmask.size(); - const uint8_t *d = bitmask.ptr(); - int c = 0; - - //fast, almot branchless version - - for (int i = 0; i < ds; i++) { - - c += (d[i] & (1 << 7)) >> 7; - c += (d[i] & (1 << 6)) >> 6; - c += (d[i] & (1 << 5)) >> 5; - c += (d[i] & (1 << 4)) >> 4; - c += (d[i] & (1 << 3)) >> 3; - c += (d[i] & (1 << 2)) >> 2; - c += d[i] & 1; - } - - return c; -} - -void BitMap::set_bit(const Point2 &p_pos, bool p_value) { - - int x = p_pos.x; - int y = p_pos.y; - - ERR_FAIL_INDEX(x, width); - ERR_FAIL_INDEX(y, height); - - int ofs = width * y + x; - int bbyte = ofs / 8; - int bbit = ofs % 8; - - uint8_t b = bitmask[bbyte]; - - if (p_value) - b |= (1 << bbit); - else - b &= ~(1 << bbit); - - bitmask.write[bbyte] = b; -} - -bool BitMap::get_bit(const Point2 &p_pos) const { - - int x = Math::fast_ftoi(p_pos.x); - int y = Math::fast_ftoi(p_pos.y); - ERR_FAIL_INDEX_V(x, width, false); - ERR_FAIL_INDEX_V(y, height, false); - - int ofs = width * y + x; - int bbyte = ofs / 8; - int bbit = ofs % 8; - - return (bitmask[bbyte] & (1 << bbit)) != 0; -} - -Size2 BitMap::get_size() const { - - return Size2(width, height); -} - -void BitMap::_set_data(const Dictionary &p_d) { - - ERR_FAIL_COND(!p_d.has("size")); - ERR_FAIL_COND(!p_d.has("data")); - - create(p_d["size"]); - bitmask = p_d["data"]; -} - -Dictionary BitMap::_get_data() const { - - Dictionary d; - d["size"] = get_size(); - d["data"] = bitmask; - return d; -} - -Vector BitMap::_march_square(const Rect2i &rect, const Point2i &start) const { - - int stepx = 0; - int stepy = 0; - int prevx = 0; - int prevy = 0; - int startx = start.x; - int starty = start.y; - int curx = startx; - int cury = starty; - unsigned int count = 0; - Set case9s; - Set case6s; - Vector _points; - do { - int sv = 0; - { //square value - - /* - checking the 2x2 pixel grid, assigning these values to each pixel, if not transparent - +---+---+ - | 1 | 2 | - +---+---+ - | 4 | 8 | <- current pixel (curx,cury) - +---+---+ - */ - //NOTE: due to the way we pick points from texture, rect needs to be smaller, otherwise it goes outside 1 pixel - Rect2i fixed_rect = Rect2i(rect.position, rect.size - Size2i(2, 2)); - Point2i tl = Point2i(curx - 1, cury - 1); - sv += (fixed_rect.has_point(tl) && get_bit(tl)) ? 1 : 0; - Point2i tr = Point2i(curx, cury - 1); - sv += (fixed_rect.has_point(tr) && get_bit(tr)) ? 2 : 0; - Point2i bl = Point2i(curx - 1, cury); - sv += (fixed_rect.has_point(bl) && get_bit(bl)) ? 4 : 0; - Point2i br = Point2i(curx, cury); - sv += (fixed_rect.has_point(br) && get_bit(br)) ? 8 : 0; - ERR_FAIL_COND_V(sv == 0 || sv == 15, Vector()); - } - - switch (sv) { - - case 1: - case 5: - case 13: - /* going UP with these cases: - 1 5 13 - +---+---+ +---+---+ +---+---+ - | 1 | | | 1 | | | 1 | | - +---+---+ +---+---+ +---+---+ - | | | | 4 | | | 4 | 8 | - +---+---+ +---+---+ +---+---+ - */ - stepx = 0; - stepy = -1; - break; - - case 8: - case 10: - case 11: - /* going DOWN with these cases: - 8 10 11 - +---+---+ +---+---+ +---+---+ - | | | | | 2 | | 1 | 2 | - +---+---+ +---+---+ +---+---+ - | | 8 | | | 8 | | | 8 | - +---+---+ +---+---+ +---+---+ - */ - stepx = 0; - stepy = 1; - break; - - case 4: - case 12: - case 14: - /* going LEFT with these cases: - 4 12 14 - +---+---+ +---+---+ +---+---+ - | | | | | | | | 2 | - +---+---+ +---+---+ +---+---+ - | 4 | | | 4 | 8 | | 4 | 8 | - +---+---+ +---+---+ +---+---+ - */ - stepx = -1; - stepy = 0; - break; - - case 2: - case 3: - case 7: - /* going RIGHT with these cases: - 2 3 7 - +---+---+ +---+---+ +---+---+ - | | 2 | | 1 | 2 | | 1 | 2 | - +---+---+ +---+---+ +---+---+ - | | | | | | | 4 | | - +---+---+ +---+---+ +---+---+ - */ - stepx = 1; - stepy = 0; - break; - case 9: - /* - +---+---+ - | 1 | | - +---+---+ - | | 8 | - +---+---+ - this should normally go UP, but if we already been here, we go down - */ - if (case9s.has(Point2i(curx, cury))) { - //found, so we go down, and delete from case9s; - stepx = 0; - stepy = 1; - case9s.erase(Point2i(curx, cury)); - } else { - //not found, we go up, and add to case9s; - stepx = 0; - stepy = -1; - case9s.insert(Point2i(curx, cury)); - } - break; - case 6: - /* - 6 - +---+---+ - | | 2 | - +---+---+ - | 4 | | - +---+---+ - this normally go RIGHT, but if its coming from UP, it should go LEFT - */ - if (case6s.has(Point2i(curx, cury))) { - //found, so we go down, and delete from case6s; - stepx = -1; - stepy = 0; - case6s.erase(Point2i(curx, cury)); - } else { - //not found, we go up, and add to case6s; - stepx = 1; - stepy = 0; - case6s.insert(Point2i(curx, cury)); - } - break; - default: - ERR_PRINT("this shouldn't happen."); - } - //little optimization - // if previous direction is same as current direction, - // then we should modify the last vec to current - curx += stepx; - cury += stepy; - if (stepx == prevx && stepy == prevy) { - _points.write[_points.size() - 1].x = (float)(curx - rect.position.x); - _points.write[_points.size() - 1].y = (float)(cury + rect.position.y); - } else { - _points.push_back(Vector2((float)(curx - rect.position.x), (float)(cury + rect.position.y))); - } - - count++; - prevx = stepx; - prevy = stepy; - - ERR_FAIL_COND_V(count > width * height, _points); - } while (curx != startx || cury != starty); - return _points; -} - -static float perpendicular_distance(const Vector2 &i, const Vector2 &start, const Vector2 &end) { - float res; - float slope; - float intercept; - - if (start.x == end.x) { - res = Math::absf(i.x - end.x); - } else if (start.y == end.y) { - res = Math::absf(i.y - end.y); - } else { - slope = (end.y - start.y) / (end.x - start.x); - intercept = start.y - (slope * start.x); - res = Math::absf(slope * i.x - i.y + intercept) / Math::sqrt(Math::pow(slope, 2.0f) + 1.0); - } - return res; -} - -static Vector rdp(const Vector &v, float optimization) { - if (v.size() < 3) - return v; - - int index = -1; - float dist = 0; - //not looping first and last point - for (size_t i = 1, size = v.size(); i < size - 1; ++i) { - float cdist = perpendicular_distance(v[i], v[0], v[v.size() - 1]); - if (cdist > dist) { - dist = cdist; - index = static_cast(i); - } - } - if (dist > optimization) { - - Vector left, right; - left.resize(index); - for (int i = 0; i < index; i++) { - left.write[i] = v[i]; - } - right.resize(v.size() - index); - for (int i = 0; i < right.size(); i++) { - right.write[i] = v[index + i]; - } - Vector r1 = rdp(left, optimization); - Vector r2 = rdp(right, optimization); - - int middle = r1.size(); - r1.resize(r1.size() + r2.size()); - for (int i = 0; i < r2.size(); i++) { - r1.write[middle + i] = r2[i]; - } - return r1; - } else { - Vector ret; - ret.push_back(v[0]); - ret.push_back(v[v.size() - 1]); - return ret; - } -} - -static Vector reduce(const Vector &points, const Rect2i &rect, float epsilon) { - int size = points.size(); - // if there are less than 3 points, then we have nothing - ERR_FAIL_COND_V(size < 3, Vector()); - // if there are less than 9 points (but more than 3), then we don't need to reduce it - if (size < 9) { - return points; - } - - float maxEp = MIN(rect.size.width, rect.size.height); - float ep = CLAMP(epsilon, 0.0, maxEp / 2); - Vector result = rdp(points, ep); - - Vector2 last = result[result.size() - 1]; - - if (last.y > result[0].y && last.distance_to(result[0]) < ep * 0.5f) { - result.write[0].y = last.y; - result.resize(result.size() - 1); - } - return result; -} - -struct FillBitsStackEntry { - Point2i pos; - int i; - int j; -}; - -static void fill_bits(const BitMap *p_src, Ref &p_map, const Point2i &p_pos, const Rect2i &rect) { - - // Using a custom stack to work iteratively to avoid stack overflow on big bitmaps - PoolVector stack; - // Tracking size since we won't be shrinking the stack vector - int stack_size = 0; - - Point2i pos = p_pos; - int next_i = 0; - int next_j = 0; - - bool reenter = true; - bool popped = false; - do { - if (reenter) { - next_i = pos.x - 1; - next_j = pos.y - 1; - reenter = false; - } - - for (int i = next_i; i <= pos.x + 1; i++) { - for (int j = next_j; j <= pos.y + 1; j++) { - if (popped) { - // The next loop over j must start normally - next_j = pos.y; - popped = false; - // Skip because an iteration was already executed with current counter values - continue; - } - - if (i < rect.position.x || i >= rect.position.x + rect.size.x) - continue; - if (j < rect.position.y || j >= rect.position.y + rect.size.y) - continue; - - if (p_map->get_bit(Vector2(i, j))) - continue; - - else if (p_src->get_bit(Vector2(i, j))) { - p_map->set_bit(Vector2(i, j), true); - - FillBitsStackEntry se = { pos, i, j }; - stack.resize(MAX(stack_size + 1, stack.size())); - stack.set(stack_size, se); - stack_size++; - - pos = Point2i(i, j); - reenter = true; - break; - } - } - if (reenter) { - break; - } - } - if (!reenter) { - if (stack_size) { - FillBitsStackEntry se = stack.get(stack_size - 1); - stack_size--; - pos = se.pos; - next_i = se.i; - next_j = se.j; - popped = true; - } - } - } while (reenter || popped); - - print_verbose("BitMap: Max stack size: " + itos(stack.size())); -} - -Vector > BitMap::clip_opaque_to_polygons(const Rect2 &p_rect, float p_epsilon) const { - - Rect2i r = Rect2i(0, 0, width, height).clip(p_rect); - print_verbose("BitMap: Rect: " + r); - - Point2i from; - Ref fill; - fill.instance(); - fill->create(get_size()); - - Vector > polygons; - for (int i = r.position.y; i < r.position.y + r.size.height; i++) { - for (int j = r.position.x; j < r.position.x + r.size.width; j++) { - if (!fill->get_bit(Point2(j, i)) && get_bit(Point2(j, i))) { - - Vector polygon = _march_square(r, Point2i(j, i)); - print_verbose("BitMap: Pre reduce: " + itos(polygon.size())); - polygon = reduce(polygon, r, p_epsilon); - print_verbose("BitMap: Post reduce: " + itos(polygon.size())); - polygons.push_back(polygon); - fill_bits(this, fill, Point2i(j, i), r); - } - } - } - - return polygons; -} - -void BitMap::grow_mask(int p_pixels, const Rect2 &p_rect) { - - Rect2i r = Rect2i(0, 0, width, height).clip(p_rect); - - Ref copy; - copy.instance(); - copy->create(get_size()); - copy->bitmask = bitmask; - - for (int i = r.position.y; i < r.position.y + r.size.height; i++) { - for (int j = r.position.x; j < r.position.x + r.size.width; j++) { - if (copy->get_bit(Point2(j, i))) - continue; - - bool found = false; - - for (int y = i - p_pixels; y <= i + p_pixels; y++) { - for (int x = j - p_pixels; x <= j + p_pixels; x++) { - - if (x < p_rect.position.x || x >= p_rect.position.x + p_rect.size.x) - continue; - if (y < p_rect.position.y || y >= p_rect.position.y + p_rect.size.y) - continue; - - float d = Point2(j, i).distance_to(Point2(x, y)) - CMP_EPSILON; - if (d > p_pixels) - continue; - - if (copy->get_bit(Point2(x, y))) { - found = true; - break; - } - } - if (found) - break; - } - - if (found) { - set_bit(Point2(j, i), true); - } - } - } -} - -Array BitMap::_opaque_to_polygons_bind(const Rect2 &p_rect, float p_epsilon) const { - - Vector > result = clip_opaque_to_polygons(p_rect, p_epsilon); - - // Convert result to bindable types - - Array result_array; - result_array.resize(result.size()); - for (int i = 0; i < result.size(); i++) { - - const Vector &polygon = result[i]; - - PoolVector2Array polygon_array; - polygon_array.resize(polygon.size()); - - { - PoolVector2Array::Write w = polygon_array.write(); - for (int j = 0; j < polygon.size(); j++) { - w[j] = polygon[j]; - } - } - - result_array[i] = polygon_array; - } - - return result_array; -} - -void BitMap::_bind_methods() { - - ClassDB::bind_method(D_METHOD("create", "size"), &BitMap::create); - ClassDB::bind_method(D_METHOD("create_from_image_alpha", "image", "threshold"), &BitMap::create_from_image_alpha, DEFVAL(0.1)); - - ClassDB::bind_method(D_METHOD("set_bit", "position", "bit"), &BitMap::set_bit); - ClassDB::bind_method(D_METHOD("get_bit", "position"), &BitMap::get_bit); - - ClassDB::bind_method(D_METHOD("set_bit_rect", "rect", "bit"), &BitMap::set_bit_rect); - ClassDB::bind_method(D_METHOD("get_true_bit_count"), &BitMap::get_true_bit_count); - - ClassDB::bind_method(D_METHOD("get_size"), &BitMap::get_size); - - ClassDB::bind_method(D_METHOD("_set_data"), &BitMap::_set_data); - ClassDB::bind_method(D_METHOD("_get_data"), &BitMap::_get_data); - - ClassDB::bind_method(D_METHOD("grow_mask", "pixels", "rect"), &BitMap::grow_mask); - ClassDB::bind_method(D_METHOD("opaque_to_polygons", "rect", "epsilon"), &BitMap::_opaque_to_polygons_bind, DEFVAL(2.0)); - - ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_data", "_get_data"); -} - -BitMap::BitMap() { - - width = 0; - height = 0; -} - -////////////////////////////////////// diff --git a/scene/resources/bit_mask.h b/scene/resources/bit_mask.h deleted file mode 100644 index 4575064260..0000000000 --- a/scene/resources/bit_mask.h +++ /dev/null @@ -1,75 +0,0 @@ -/*************************************************************************/ -/* bit_mask.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#ifndef BIT_MASK_H -#define BIT_MASK_H - -#include "core/image.h" -#include "core/io/resource_loader.h" -#include "core/resource.h" - -class BitMap : public Resource { - - GDCLASS(BitMap, Resource); - OBJ_SAVE_TYPE(BitMap); - - Vector bitmask; - int width; - int height; - - Vector _march_square(const Rect2i &rect, const Point2i &start) const; - - Array _opaque_to_polygons_bind(const Rect2 &p_rect, float p_epsilon) const; - -protected: - void _set_data(const Dictionary &p_d); - Dictionary _get_data() const; - - static void _bind_methods(); - -public: - void create(const Size2 &p_size); - void create_from_image_alpha(const Ref &p_image, float p_threshold = 0.1); - - void set_bit(const Point2 &p_pos, bool p_value); - bool get_bit(const Point2 &p_pos) const; - void set_bit_rect(const Rect2 &p_rect, bool p_value); - int get_true_bit_count() const; - - Size2 get_size() const; - - void grow_mask(int p_pixels, const Rect2 &p_rect); - - Vector > clip_opaque_to_polygons(const Rect2 &p_rect, float p_epsilon = 2.0) const; - - BitMap(); -}; - -#endif // BIT_MASK_H diff --git a/scene/resources/bounds.cpp b/scene/resources/bounds.cpp deleted file mode 100644 index e6fa5b818d..0000000000 --- a/scene/resources/bounds.cpp +++ /dev/null @@ -1,52 +0,0 @@ -/*************************************************************************/ -/* bounds.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#include "bounds.h" - -void Bounds::_bind_methods() { - - ClassDB::bind_method(D_METHOD("set_bsp_tree", "bsp_tree"), &Bounds::set_bsp_tree); - ClassDB::bind_method(D_METHOD("get_bsp_tree"), &Bounds::get_bsp_tree); - - ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "bsp_tree"), "set_bsp_tree", "get_bsp_tree"); -} - -void Bounds::set_bsp_tree(const BSP_Tree &p_bsp_tree) { - - bsp_tree = p_bsp_tree; -} - -BSP_Tree Bounds::get_bsp_tree() const { - - return bsp_tree; -} - -Bounds::Bounds() { -} diff --git a/scene/resources/bounds.h b/scene/resources/bounds.h deleted file mode 100644 index 9a1801f23d..0000000000 --- a/scene/resources/bounds.h +++ /dev/null @@ -1,52 +0,0 @@ -/*************************************************************************/ -/* bounds.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#ifndef BOUNDS_H -#define BOUNDS_H - -#include "core/math/bsp_tree.h" -#include "core/resource.h" - -class Bounds : public Resource { - - GDCLASS(Bounds, Resource); - BSP_Tree bsp_tree; - -protected: - static void _bind_methods(); - -public: - void set_bsp_tree(const BSP_Tree &p_bsp_tree); - BSP_Tree get_bsp_tree() const; - - Bounds(); -}; - -#endif // BOUNDS_H diff --git a/scene/resources/color_ramp.cpp b/scene/resources/color_ramp.cpp deleted file mode 100644 index 845a1474a4..0000000000 --- a/scene/resources/color_ramp.cpp +++ /dev/null @@ -1,175 +0,0 @@ -/*************************************************************************/ -/* color_ramp.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#include "color_ramp.h" -#include "core/core_string_names.h" - -//setter and getter names for property serialization -#define COLOR_RAMP_GET_OFFSETS "get_offsets" -#define COLOR_RAMP_GET_COLORS "get_colors" -#define COLOR_RAMP_SET_OFFSETS "set_offsets" -#define COLOR_RAMP_SET_COLORS "set_colors" - -Gradient::Gradient() { - //Set initial color ramp transition from black to white - points.resize(2); - points.write[0].color = Color(0, 0, 0, 1); - points.write[0].offset = 0; - points.write[1].color = Color(1, 1, 1, 1); - points.write[1].offset = 1; - is_sorted = true; -} - -Gradient::~Gradient() { -} - -void Gradient::_bind_methods() { - - ClassDB::bind_method(D_METHOD("add_point", "offset", "color"), &Gradient::add_point); - ClassDB::bind_method(D_METHOD("remove_point", "offset"), &Gradient::remove_point); - - ClassDB::bind_method(D_METHOD("set_offset", "point", "offset"), &Gradient::set_offset); - ClassDB::bind_method(D_METHOD("get_offset", "point"), &Gradient::get_offset); - - ClassDB::bind_method(D_METHOD("set_color", "point", "color"), &Gradient::set_color); - ClassDB::bind_method(D_METHOD("get_color", "point"), &Gradient::get_color); - - ClassDB::bind_method(D_METHOD("interpolate", "offset"), &Gradient::get_color_at_offset); - - ClassDB::bind_method(D_METHOD("get_point_count"), &Gradient::get_points_count); - - ClassDB::bind_method(D_METHOD(COLOR_RAMP_SET_OFFSETS, "offsets"), &Gradient::set_offsets); - ClassDB::bind_method(D_METHOD(COLOR_RAMP_GET_OFFSETS), &Gradient::get_offsets); - - ClassDB::bind_method(D_METHOD(COLOR_RAMP_SET_COLORS, "colors"), &Gradient::set_colors); - ClassDB::bind_method(D_METHOD(COLOR_RAMP_GET_COLORS), &Gradient::get_colors); - - ADD_PROPERTY(PropertyInfo(Variant::POOL_REAL_ARRAY, "offsets"), COLOR_RAMP_SET_OFFSETS, COLOR_RAMP_GET_OFFSETS); - ADD_PROPERTY(PropertyInfo(Variant::POOL_COLOR_ARRAY, "colors"), COLOR_RAMP_SET_COLORS, COLOR_RAMP_GET_COLORS); -} - -Vector Gradient::get_offsets() const { - Vector offsets; - offsets.resize(points.size()); - for (int i = 0; i < points.size(); i++) { - offsets.write[i] = points[i].offset; - } - return offsets; -} - -Vector Gradient::get_colors() const { - Vector colors; - colors.resize(points.size()); - for (int i = 0; i < points.size(); i++) { - colors.write[i] = points[i].color; - } - return colors; -} - -void Gradient::set_offsets(const Vector &p_offsets) { - points.resize(p_offsets.size()); - for (int i = 0; i < points.size(); i++) { - points.write[i].offset = p_offsets[i]; - } - is_sorted = false; - emit_signal(CoreStringNames::get_singleton()->changed); -} - -void Gradient::set_colors(const Vector &p_colors) { - if (points.size() < p_colors.size()) - is_sorted = false; - points.resize(p_colors.size()); - for (int i = 0; i < points.size(); i++) { - points.write[i].color = p_colors[i]; - } - emit_signal(CoreStringNames::get_singleton()->changed); -} - -Vector &Gradient::get_points() { - return points; -} - -void Gradient::add_point(float p_offset, const Color &p_color) { - - Point p; - p.offset = p_offset; - p.color = p_color; - is_sorted = false; - points.push_back(p); - - emit_signal(CoreStringNames::get_singleton()->changed); -} - -void Gradient::remove_point(int p_index) { - - ERR_FAIL_INDEX(p_index, points.size()); - ERR_FAIL_COND(points.size() <= 2); - points.remove(p_index); - emit_signal(CoreStringNames::get_singleton()->changed); -} - -void Gradient::set_points(Vector &p_points) { - points = p_points; - is_sorted = false; - emit_signal(CoreStringNames::get_singleton()->changed); -} - -void Gradient::set_offset(int pos, const float offset) { - if (points.size() <= pos) - points.resize(pos + 1); - points.write[pos].offset = offset; - is_sorted = false; - emit_signal(CoreStringNames::get_singleton()->changed); -} - -float Gradient::get_offset(int pos) const { - if (points.size() && points.size() > pos) - return points[pos].offset; - return 0; //TODO: Maybe throw some error instead? -} - -void Gradient::set_color(int pos, const Color &color) { - if (points.size() <= pos) { - points.resize(pos + 1); - is_sorted = false; - } - points.write[pos].color = color; - emit_signal(CoreStringNames::get_singleton()->changed); -} - -Color Gradient::get_color(int pos) const { - if (points.size() && points.size() > pos) - return points[pos].color; - return Color(0, 0, 0, 1); //TODO: Maybe throw some error instead? -} - -int Gradient::get_points_count() const { - return points.size(); -} diff --git a/scene/resources/color_ramp.h b/scene/resources/color_ramp.h deleted file mode 100644 index 7a96bb429b..0000000000 --- a/scene/resources/color_ramp.h +++ /dev/null @@ -1,129 +0,0 @@ -/*************************************************************************/ -/* color_ramp.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#ifndef SCENE_RESOURCES_COLOR_RAMP_H_ -#define SCENE_RESOURCES_COLOR_RAMP_H_ - -#include "core/resource.h" - -class Gradient : public Resource { - GDCLASS(Gradient, Resource); - OBJ_SAVE_TYPE(Gradient); - -public: - struct Point { - - float offset; - Color color; - bool operator<(const Point &p_ponit) const { - return offset < p_ponit.offset; - } - }; - -private: - Vector points; - bool is_sorted; - -protected: - static void _bind_methods(); - -public: - Gradient(); - virtual ~Gradient(); - - void add_point(float p_offset, const Color &p_color); - void remove_point(int p_index); - - void set_points(Vector &p_points); - Vector &get_points(); - - void set_offset(int pos, const float offset); - float get_offset(int pos) const; - - void set_color(int pos, const Color &color); - Color get_color(int pos) const; - - void set_offsets(const Vector &p_offsets); - Vector get_offsets() const; - - void set_colors(const Vector &p_colors); - Vector get_colors() const; - - _FORCE_INLINE_ Color get_color_at_offset(float p_offset) { - - if (points.empty()) - return Color(0, 0, 0, 1); - - if (!is_sorted) { - points.sort(); - is_sorted = true; - } - - //binary search - int low = 0; - int high = points.size() - 1; - int middle = 0; - -#if DEBUG_ENABLED - if (low > high) - ERR_PRINT("low > high, this may be a bug"); -#endif - - while (low <= high) { - middle = (low + high) / 2; - const Point &point = points[middle]; - if (point.offset > p_offset) { - high = middle - 1; //search low end of array - } else if (point.offset < p_offset) { - low = middle + 1; //search high end of array - } else { - return point.color; - } - } - - //return interpolated value - if (points[middle].offset > p_offset) { - middle--; - } - int first = middle; - int second = middle + 1; - if (second >= points.size()) - return points[points.size() - 1].color; - if (first < 0) - return points[0].color; - const Point &pointFirst = points[first]; - const Point &pointSecond = points[second]; - return pointFirst.color.linear_interpolate(pointSecond.color, (p_offset - pointFirst.offset) / (pointSecond.offset - pointFirst.offset)); - } - - int get_points_count() const; -}; - -#endif /* SCENE_RESOURCES_COLOR_RAMP_H_ */ diff --git a/scene/resources/environment.h b/scene/resources/environment.h index 666112b473..a54f13a88f 100644 --- a/scene/resources/environment.h +++ b/scene/resources/environment.h @@ -32,7 +32,7 @@ #define ENVIRONMENT_H #include "core/resource.h" -#include "scene/resources/sky_box.h" +#include "scene/resources/sky.h" #include "scene/resources/texture.h" #include "servers/visual_server.h" diff --git a/scene/resources/gradient.cpp b/scene/resources/gradient.cpp new file mode 100644 index 0000000000..99ce8ef821 --- /dev/null +++ b/scene/resources/gradient.cpp @@ -0,0 +1,176 @@ +/*************************************************************************/ +/* gradient.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "gradient.h" + +#include "core/core_string_names.h" + +//setter and getter names for property serialization +#define COLOR_RAMP_GET_OFFSETS "get_offsets" +#define COLOR_RAMP_GET_COLORS "get_colors" +#define COLOR_RAMP_SET_OFFSETS "set_offsets" +#define COLOR_RAMP_SET_COLORS "set_colors" + +Gradient::Gradient() { + //Set initial color ramp transition from black to white + points.resize(2); + points.write[0].color = Color(0, 0, 0, 1); + points.write[0].offset = 0; + points.write[1].color = Color(1, 1, 1, 1); + points.write[1].offset = 1; + is_sorted = true; +} + +Gradient::~Gradient() { +} + +void Gradient::_bind_methods() { + + ClassDB::bind_method(D_METHOD("add_point", "offset", "color"), &Gradient::add_point); + ClassDB::bind_method(D_METHOD("remove_point", "offset"), &Gradient::remove_point); + + ClassDB::bind_method(D_METHOD("set_offset", "point", "offset"), &Gradient::set_offset); + ClassDB::bind_method(D_METHOD("get_offset", "point"), &Gradient::get_offset); + + ClassDB::bind_method(D_METHOD("set_color", "point", "color"), &Gradient::set_color); + ClassDB::bind_method(D_METHOD("get_color", "point"), &Gradient::get_color); + + ClassDB::bind_method(D_METHOD("interpolate", "offset"), &Gradient::get_color_at_offset); + + ClassDB::bind_method(D_METHOD("get_point_count"), &Gradient::get_points_count); + + ClassDB::bind_method(D_METHOD(COLOR_RAMP_SET_OFFSETS, "offsets"), &Gradient::set_offsets); + ClassDB::bind_method(D_METHOD(COLOR_RAMP_GET_OFFSETS), &Gradient::get_offsets); + + ClassDB::bind_method(D_METHOD(COLOR_RAMP_SET_COLORS, "colors"), &Gradient::set_colors); + ClassDB::bind_method(D_METHOD(COLOR_RAMP_GET_COLORS), &Gradient::get_colors); + + ADD_PROPERTY(PropertyInfo(Variant::POOL_REAL_ARRAY, "offsets"), COLOR_RAMP_SET_OFFSETS, COLOR_RAMP_GET_OFFSETS); + ADD_PROPERTY(PropertyInfo(Variant::POOL_COLOR_ARRAY, "colors"), COLOR_RAMP_SET_COLORS, COLOR_RAMP_GET_COLORS); +} + +Vector Gradient::get_offsets() const { + Vector offsets; + offsets.resize(points.size()); + for (int i = 0; i < points.size(); i++) { + offsets.write[i] = points[i].offset; + } + return offsets; +} + +Vector Gradient::get_colors() const { + Vector colors; + colors.resize(points.size()); + for (int i = 0; i < points.size(); i++) { + colors.write[i] = points[i].color; + } + return colors; +} + +void Gradient::set_offsets(const Vector &p_offsets) { + points.resize(p_offsets.size()); + for (int i = 0; i < points.size(); i++) { + points.write[i].offset = p_offsets[i]; + } + is_sorted = false; + emit_signal(CoreStringNames::get_singleton()->changed); +} + +void Gradient::set_colors(const Vector &p_colors) { + if (points.size() < p_colors.size()) + is_sorted = false; + points.resize(p_colors.size()); + for (int i = 0; i < points.size(); i++) { + points.write[i].color = p_colors[i]; + } + emit_signal(CoreStringNames::get_singleton()->changed); +} + +Vector &Gradient::get_points() { + return points; +} + +void Gradient::add_point(float p_offset, const Color &p_color) { + + Point p; + p.offset = p_offset; + p.color = p_color; + is_sorted = false; + points.push_back(p); + + emit_signal(CoreStringNames::get_singleton()->changed); +} + +void Gradient::remove_point(int p_index) { + + ERR_FAIL_INDEX(p_index, points.size()); + ERR_FAIL_COND(points.size() <= 2); + points.remove(p_index); + emit_signal(CoreStringNames::get_singleton()->changed); +} + +void Gradient::set_points(Vector &p_points) { + points = p_points; + is_sorted = false; + emit_signal(CoreStringNames::get_singleton()->changed); +} + +void Gradient::set_offset(int pos, const float offset) { + if (points.size() <= pos) + points.resize(pos + 1); + points.write[pos].offset = offset; + is_sorted = false; + emit_signal(CoreStringNames::get_singleton()->changed); +} + +float Gradient::get_offset(int pos) const { + if (points.size() && points.size() > pos) + return points[pos].offset; + return 0; //TODO: Maybe throw some error instead? +} + +void Gradient::set_color(int pos, const Color &color) { + if (points.size() <= pos) { + points.resize(pos + 1); + is_sorted = false; + } + points.write[pos].color = color; + emit_signal(CoreStringNames::get_singleton()->changed); +} + +Color Gradient::get_color(int pos) const { + if (points.size() && points.size() > pos) + return points[pos].color; + return Color(0, 0, 0, 1); //TODO: Maybe throw some error instead? +} + +int Gradient::get_points_count() const { + return points.size(); +} diff --git a/scene/resources/gradient.h b/scene/resources/gradient.h new file mode 100644 index 0000000000..a51a0ca0d0 --- /dev/null +++ b/scene/resources/gradient.h @@ -0,0 +1,129 @@ +/*************************************************************************/ +/* gradient.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef GRADIENT_H +#define GRADIENT_H + +#include "core/resource.h" + +class Gradient : public Resource { + GDCLASS(Gradient, Resource); + OBJ_SAVE_TYPE(Gradient); + +public: + struct Point { + + float offset; + Color color; + bool operator<(const Point &p_ponit) const { + return offset < p_ponit.offset; + } + }; + +private: + Vector points; + bool is_sorted; + +protected: + static void _bind_methods(); + +public: + Gradient(); + virtual ~Gradient(); + + void add_point(float p_offset, const Color &p_color); + void remove_point(int p_index); + + void set_points(Vector &p_points); + Vector &get_points(); + + void set_offset(int pos, const float offset); + float get_offset(int pos) const; + + void set_color(int pos, const Color &color); + Color get_color(int pos) const; + + void set_offsets(const Vector &p_offsets); + Vector get_offsets() const; + + void set_colors(const Vector &p_colors); + Vector get_colors() const; + + _FORCE_INLINE_ Color get_color_at_offset(float p_offset) { + + if (points.empty()) + return Color(0, 0, 0, 1); + + if (!is_sorted) { + points.sort(); + is_sorted = true; + } + + //binary search + int low = 0; + int high = points.size() - 1; + int middle = 0; + +#if DEBUG_ENABLED + if (low > high) + ERR_PRINT("low > high, this may be a bug"); +#endif + + while (low <= high) { + middle = (low + high) / 2; + const Point &point = points[middle]; + if (point.offset > p_offset) { + high = middle - 1; //search low end of array + } else if (point.offset < p_offset) { + low = middle + 1; //search high end of array + } else { + return point.color; + } + } + + //return interpolated value + if (points[middle].offset > p_offset) { + middle--; + } + int first = middle; + int second = middle + 1; + if (second >= points.size()) + return points[points.size() - 1].color; + if (first < 0) + return points[0].color; + const Point &pointFirst = points[first]; + const Point &pointSecond = points[second]; + return pointFirst.color.linear_interpolate(pointSecond.color, (p_offset - pointFirst.offset) / (pointSecond.offset - pointFirst.offset)); + } + + int get_points_count() const; +}; + +#endif // GRADIENT_H diff --git a/scene/resources/line_shape_2d.cpp b/scene/resources/line_shape_2d.cpp new file mode 100644 index 0000000000..f5d5fb561a --- /dev/null +++ b/scene/resources/line_shape_2d.cpp @@ -0,0 +1,121 @@ +/*************************************************************************/ +/* line_shape_2d.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "line_shape_2d.h" + +#include "servers/physics_2d_server.h" +#include "servers/visual_server.h" + +bool LineShape2D::_edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const { + + Vector2 point = get_d() * get_normal(); + Vector2 l[2][2] = { { point - get_normal().tangent() * 100, point + get_normal().tangent() * 100 }, { point, point + get_normal() * 30 } }; + + for (int i = 0; i < 2; i++) { + Vector2 closest = Geometry::get_closest_point_to_segment_2d(p_point, l[i]); + if (p_point.distance_to(closest) < p_tolerance) + return true; + } + + return false; +} + +void LineShape2D::_update_shape() { + + Array arr; + arr.push_back(normal); + arr.push_back(d); + Physics2DServer::get_singleton()->shape_set_data(get_rid(), arr); + emit_changed(); +} + +void LineShape2D::set_normal(const Vector2 &p_normal) { + + normal = p_normal; + _update_shape(); +} + +void LineShape2D::set_d(real_t p_d) { + + d = p_d; + _update_shape(); +} + +Vector2 LineShape2D::get_normal() const { + + return normal; +} +real_t LineShape2D::get_d() const { + + return d; +} + +void LineShape2D::draw(const RID &p_to_rid, const Color &p_color) { + + Vector2 point = get_d() * get_normal(); + + Vector2 l1[2] = { point - get_normal().tangent() * 100, point + get_normal().tangent() * 100 }; + VS::get_singleton()->canvas_item_add_line(p_to_rid, l1[0], l1[1], p_color, 3); + Vector2 l2[2] = { point, point + get_normal() * 30 }; + VS::get_singleton()->canvas_item_add_line(p_to_rid, l2[0], l2[1], p_color, 3); +} +Rect2 LineShape2D::get_rect() const { + + Vector2 point = get_d() * get_normal(); + + Vector2 l1[2] = { point - get_normal().tangent() * 100, point + get_normal().tangent() * 100 }; + Vector2 l2[2] = { point, point + get_normal() * 30 }; + Rect2 rect; + rect.position = l1[0]; + rect.expand_to(l1[1]); + rect.expand_to(l2[0]); + rect.expand_to(l2[1]); + return rect; +} + +void LineShape2D::_bind_methods() { + + ClassDB::bind_method(D_METHOD("set_normal", "normal"), &LineShape2D::set_normal); + ClassDB::bind_method(D_METHOD("get_normal"), &LineShape2D::get_normal); + + ClassDB::bind_method(D_METHOD("set_d", "d"), &LineShape2D::set_d); + ClassDB::bind_method(D_METHOD("get_d"), &LineShape2D::get_d); + + ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "normal"), "set_normal", "get_normal"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "d"), "set_d", "get_d"); +} + +LineShape2D::LineShape2D() : + Shape2D(Physics2DServer::get_singleton()->line_shape_create()) { + + normal = Vector2(0, -1); + d = 0; + _update_shape(); +} diff --git a/scene/resources/line_shape_2d.h b/scene/resources/line_shape_2d.h new file mode 100644 index 0000000000..f684862025 --- /dev/null +++ b/scene/resources/line_shape_2d.h @@ -0,0 +1,62 @@ +/*************************************************************************/ +/* line_shape_2d.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef LINE_SHAPE_2D_H +#define LINE_SHAPE_2D_H + +#include "scene/resources/shape_2d.h" + +class LineShape2D : public Shape2D { + GDCLASS(LineShape2D, Shape2D); + + Vector2 normal; + real_t d; + + void _update_shape(); + +protected: + static void _bind_methods(); + +public: + virtual bool _edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const; + + void set_normal(const Vector2 &p_normal); + void set_d(real_t p_d); + + Vector2 get_normal() const; + real_t get_d() const; + + virtual void draw(const RID &p_to_rid, const Color &p_color); + virtual Rect2 get_rect() const; + + LineShape2D(); +}; + +#endif // LINE_SHAPE_2D_H diff --git a/scene/resources/resource_format_text.cpp b/scene/resources/resource_format_text.cpp new file mode 100644 index 0000000000..e838d4a685 --- /dev/null +++ b/scene/resources/resource_format_text.cpp @@ -0,0 +1,1756 @@ +/*************************************************************************/ +/* resource_format_text.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "resource_format_text.h" + +#include "core/io/resource_format_binary.h" +#include "core/os/dir_access.h" +#include "core/project_settings.h" +#include "core/version.h" + +//version 2: changed names for basis, aabb, poolvectors, etc. +#define FORMAT_VERSION 2 + +#include "core/os/dir_access.h" +#include "core/version.h" + +#define _printerr() ERR_PRINT(String(res_path + ":" + itos(lines) + " - Parse Error: " + error_text).utf8().get_data()); + +/// + +void ResourceInteractiveLoaderText::set_local_path(const String &p_local_path) { + + res_path = p_local_path; +} + +Ref ResourceInteractiveLoaderText::get_resource() { + + return resource; +} + +Error ResourceInteractiveLoaderText::_parse_sub_resource_dummy(DummyReadData *p_data, VariantParser::Stream *p_stream, Ref &r_res, int &line, String &r_err_str) { + + VariantParser::Token token; + VariantParser::get_token(p_stream, token, line, r_err_str); + if (token.type != VariantParser::TK_NUMBER) { + r_err_str = "Expected number (sub-resource index)"; + return ERR_PARSE_ERROR; + } + + int index = token.value; + + if (!p_data->resource_map.has(index)) { + Ref dr; + dr.instance(); + dr->set_subindex(index); + p_data->resource_map[index] = dr; + p_data->resource_set.insert(dr); + } + + r_res = p_data->resource_map[index]; + + VariantParser::get_token(p_stream, token, line, r_err_str); + if (token.type != VariantParser::TK_PARENTHESIS_CLOSE) { + r_err_str = "Expected ')'"; + return ERR_PARSE_ERROR; + } + + return OK; +} + +Error ResourceInteractiveLoaderText::_parse_ext_resource_dummy(DummyReadData *p_data, VariantParser::Stream *p_stream, Ref &r_res, int &line, String &r_err_str) { + + VariantParser::Token token; + VariantParser::get_token(p_stream, token, line, r_err_str); + if (token.type != VariantParser::TK_NUMBER) { + r_err_str = "Expected number (sub-resource index)"; + return ERR_PARSE_ERROR; + } + + int id = token.value; + + ERR_FAIL_COND_V(!p_data->rev_external_resources.has(id), ERR_PARSE_ERROR); + + r_res = p_data->rev_external_resources[id]; + + VariantParser::get_token(p_stream, token, line, r_err_str); + if (token.type != VariantParser::TK_PARENTHESIS_CLOSE) { + r_err_str = "Expected ')'"; + return ERR_PARSE_ERROR; + } + + return OK; +} + +Error ResourceInteractiveLoaderText::_parse_sub_resource(VariantParser::Stream *p_stream, Ref &r_res, int &line, String &r_err_str) { + + VariantParser::Token token; + VariantParser::get_token(p_stream, token, line, r_err_str); + if (token.type != VariantParser::TK_NUMBER) { + r_err_str = "Expected number (sub-resource index)"; + return ERR_PARSE_ERROR; + } + + int index = token.value; + + String path = local_path + "::" + itos(index); + + if (!ignore_resource_parsing) { + + if (!ResourceCache::has(path)) { + r_err_str = "Can't load cached sub-resource: " + path; + return ERR_PARSE_ERROR; + } + + r_res = RES(ResourceCache::get(path)); + } else { + r_res = RES(); + } + + VariantParser::get_token(p_stream, token, line, r_err_str); + if (token.type != VariantParser::TK_PARENTHESIS_CLOSE) { + r_err_str = "Expected ')'"; + return ERR_PARSE_ERROR; + } + + return OK; +} + +Error ResourceInteractiveLoaderText::_parse_ext_resource(VariantParser::Stream *p_stream, Ref &r_res, int &line, String &r_err_str) { + + VariantParser::Token token; + VariantParser::get_token(p_stream, token, line, r_err_str); + if (token.type != VariantParser::TK_NUMBER) { + r_err_str = "Expected number (sub-resource index)"; + return ERR_PARSE_ERROR; + } + + int id = token.value; + + if (!ignore_resource_parsing) { + + if (!ext_resources.has(id)) { + r_err_str = "Can't load cached ext-resource #" + itos(id); + return ERR_PARSE_ERROR; + } + + String path = ext_resources[id].path; + String type = ext_resources[id].type; + + if (path.find("://") == -1 && path.is_rel_path()) { + // path is relative to file being loaded, so convert to a resource path + path = ProjectSettings::get_singleton()->localize_path(res_path.get_base_dir().plus_file(path)); + } + + r_res = ResourceLoader::load(path, type); + + if (r_res.is_null()) { + WARN_PRINT(String("Couldn't load external resource: " + path).utf8().get_data()); + } + } else { + r_res = RES(); + } + + VariantParser::get_token(p_stream, token, line, r_err_str); + if (token.type != VariantParser::TK_PARENTHESIS_CLOSE) { + r_err_str = "Expected ')'"; + return ERR_PARSE_ERROR; + } + + return OK; +} + +Ref ResourceInteractiveLoaderText::_parse_node_tag(VariantParser::ResourceParser &parser) { + Ref packed_scene; + packed_scene.instance(); + + while (true) { + + if (next_tag.name == "node") { + + int parent = -1; + int owner = -1; + int type = -1; + int name = -1; + int instance = -1; + int index = -1; + //int base_scene=-1; + + if (next_tag.fields.has("name")) { + name = packed_scene->get_state()->add_name(next_tag.fields["name"]); + } + + if (next_tag.fields.has("parent")) { + NodePath np = next_tag.fields["parent"]; + np.prepend_period(); //compatible to how it manages paths internally + parent = packed_scene->get_state()->add_node_path(np); + } + + if (next_tag.fields.has("type")) { + type = packed_scene->get_state()->add_name(next_tag.fields["type"]); + } else { + type = SceneState::TYPE_INSTANCED; //no type? assume this was instanced + } + + if (next_tag.fields.has("instance")) { + + instance = packed_scene->get_state()->add_value(next_tag.fields["instance"]); + + if (packed_scene->get_state()->get_node_count() == 0 && parent == -1) { + packed_scene->get_state()->set_base_scene(instance); + instance = -1; + } + } + + if (next_tag.fields.has("instance_placeholder")) { + + String path = next_tag.fields["instance_placeholder"]; + + int path_v = packed_scene->get_state()->add_value(path); + + if (packed_scene->get_state()->get_node_count() == 0) { + error = ERR_FILE_CORRUPT; + error_text = "Instance Placeholder can't be used for inheritance."; + _printerr(); + return Ref(); + } + + instance = path_v | SceneState::FLAG_INSTANCE_IS_PLACEHOLDER; + } + + if (next_tag.fields.has("owner")) { + owner = packed_scene->get_state()->add_node_path(next_tag.fields["owner"]); + } else { + if (parent != -1 && !(type == SceneState::TYPE_INSTANCED && instance == -1)) + owner = 0; //if no owner, owner is root + } + + if (next_tag.fields.has("index")) { + index = next_tag.fields["index"]; + } + + int node_id = packed_scene->get_state()->add_node(parent, owner, type, name, instance, index); + + if (next_tag.fields.has("groups")) { + + Array groups = next_tag.fields["groups"]; + for (int i = 0; i < groups.size(); i++) { + packed_scene->get_state()->add_node_group(node_id, packed_scene->get_state()->add_name(groups[i])); + } + } + + while (true) { + + String assign; + Variant value; + + error = VariantParser::parse_tag_assign_eof(&stream, lines, error_text, next_tag, assign, value, &parser); + + if (error) { + if (error != ERR_FILE_EOF) { + _printerr(); + return Ref(); + } else { + return packed_scene; + } + } + + if (assign != String()) { + int nameidx = packed_scene->get_state()->add_name(assign); + int valueidx = packed_scene->get_state()->add_value(value); + packed_scene->get_state()->add_node_property(node_id, nameidx, valueidx); + //it's assignment + } else if (next_tag.name != String()) { + break; + } + } + } else if (next_tag.name == "connection") { + + if (!next_tag.fields.has("from")) { + error = ERR_FILE_CORRUPT; + error_text = "missing 'from' field from connection tag"; + return Ref(); + } + + if (!next_tag.fields.has("to")) { + error = ERR_FILE_CORRUPT; + error_text = "missing 'to' field from connection tag"; + return Ref(); + } + + if (!next_tag.fields.has("signal")) { + error = ERR_FILE_CORRUPT; + error_text = "missing 'signal' field from connection tag"; + return Ref(); + } + + if (!next_tag.fields.has("method")) { + error = ERR_FILE_CORRUPT; + error_text = "missing 'method' field from connection tag"; + return Ref(); + } + + NodePath from = next_tag.fields["from"]; + NodePath to = next_tag.fields["to"]; + StringName method = next_tag.fields["method"]; + StringName signal = next_tag.fields["signal"]; + int flags = CONNECT_PERSIST; + Array binds; + + if (next_tag.fields.has("flags")) { + flags = next_tag.fields["flags"]; + } + + if (next_tag.fields.has("binds")) { + binds = next_tag.fields["binds"]; + } + + Vector bind_ints; + for (int i = 0; i < binds.size(); i++) { + bind_ints.push_back(packed_scene->get_state()->add_value(binds[i])); + } + + packed_scene->get_state()->add_connection( + packed_scene->get_state()->add_node_path(from.simplified()), + packed_scene->get_state()->add_node_path(to.simplified()), + packed_scene->get_state()->add_name(signal), + packed_scene->get_state()->add_name(method), + flags, + bind_ints); + + error = VariantParser::parse_tag(&stream, lines, error_text, next_tag, &parser); + + if (error) { + if (error != ERR_FILE_EOF) { + _printerr(); + return Ref(); + } else { + return packed_scene; + } + } + } else if (next_tag.name == "editable") { + + if (!next_tag.fields.has("path")) { + error = ERR_FILE_CORRUPT; + error_text = "missing 'path' field from connection tag"; + _printerr(); + return Ref(); + } + + NodePath path = next_tag.fields["path"]; + + packed_scene->get_state()->add_editable_instance(path.simplified()); + + error = VariantParser::parse_tag(&stream, lines, error_text, next_tag, &parser); + + if (error) { + if (error != ERR_FILE_EOF) { + _printerr(); + return Ref(); + } else { + return packed_scene; + } + } + } else { + + error = ERR_FILE_CORRUPT; + _printerr(); + return Ref(); + } + } + + return packed_scene; +} + +Error ResourceInteractiveLoaderText::poll() { + + if (error != OK) + return error; + + if (next_tag.name == "ext_resource") { + + if (!next_tag.fields.has("path")) { + error = ERR_FILE_CORRUPT; + error_text = "Missing 'path' in external resource tag"; + _printerr(); + return error; + } + + if (!next_tag.fields.has("type")) { + error = ERR_FILE_CORRUPT; + error_text = "Missing 'type' in external resource tag"; + _printerr(); + return error; + } + + if (!next_tag.fields.has("id")) { + error = ERR_FILE_CORRUPT; + error_text = "Missing 'id' in external resource tag"; + _printerr(); + return error; + } + + String path = next_tag.fields["path"]; + String type = next_tag.fields["type"]; + int index = next_tag.fields["id"]; + + if (path.find("://") == -1 && path.is_rel_path()) { + // path is relative to file being loaded, so convert to a resource path + path = ProjectSettings::get_singleton()->localize_path(local_path.get_base_dir().plus_file(path)); + } + + if (remaps.has(path)) { + path = remaps[path]; + } + + RES res = ResourceLoader::load(path, type); + + if (res.is_null()) { + + if (ResourceLoader::get_abort_on_missing_resources()) { + error = ERR_FILE_CORRUPT; + error_text = "[ext_resource] referenced nonexistent resource at: " + path; + _printerr(); + return error; + } else { + ResourceLoader::notify_dependency_error(local_path, path, type); + } + } else { + + resource_cache.push_back(res); + } + + ExtResource er; + er.path = path; + er.type = type; + ext_resources[index] = er; + + error = VariantParser::parse_tag(&stream, lines, error_text, next_tag, &rp); + + if (error) { + _printerr(); + } + + resource_current++; + return error; + + } else if (next_tag.name == "sub_resource") { + + if (!next_tag.fields.has("type")) { + error = ERR_FILE_CORRUPT; + error_text = "Missing 'type' in external resource tag"; + _printerr(); + return error; + } + + if (!next_tag.fields.has("id")) { + error = ERR_FILE_CORRUPT; + error_text = "Missing 'index' in external resource tag"; + _printerr(); + return error; + } + + String type = next_tag.fields["type"]; + int id = next_tag.fields["id"]; + + String path = local_path + "::" + itos(id); + + //bool exists=ResourceCache::has(path); + + Ref res; + + if (!ResourceCache::has(path)) { //only if it doesn't exist + + Object *obj = ClassDB::instance(type); + if (!obj) { + + error_text += "Can't create sub resource of type: " + type; + _printerr(); + error = ERR_FILE_CORRUPT; + return error; + } + + Resource *r = Object::cast_to(obj); + if (!r) { + + error_text += "Can't create sub resource of type, because not a resource: " + type; + _printerr(); + error = ERR_FILE_CORRUPT; + return error; + } + + res = Ref(r); + resource_cache.push_back(res); + res->set_path(path); + } + + resource_current++; + + while (true) { + + String assign; + Variant value; + + error = VariantParser::parse_tag_assign_eof(&stream, lines, error_text, next_tag, assign, value, &rp); + + if (error) { + _printerr(); + return error; + } + + if (assign != String()) { + if (res.is_valid()) { + res->set(assign, value); + } + //it's assignment + } else if (next_tag.name != String()) { + + error = OK; + break; + } else { + error = ERR_FILE_CORRUPT; + error_text = "Premature end of file while parsing [sub_resource]"; + _printerr(); + return error; + } + } + + return OK; + + } else if (next_tag.name == "resource") { + + if (is_scene) { + + error_text += "found the 'resource' tag on a scene file!"; + _printerr(); + error = ERR_FILE_CORRUPT; + return error; + } + + Object *obj = ClassDB::instance(res_type); + if (!obj) { + + error_text += "Can't create sub resource of type: " + res_type; + _printerr(); + error = ERR_FILE_CORRUPT; + return error; + } + + Resource *r = Object::cast_to(obj); + if (!r) { + + error_text += "Can't create sub resource of type, because not a resource: " + res_type; + _printerr(); + error = ERR_FILE_CORRUPT; + return error; + } + + resource = Ref(r); + + resource_current++; + + while (true) { + + String assign; + Variant value; + + error = VariantParser::parse_tag_assign_eof(&stream, lines, error_text, next_tag, assign, value, &rp); + + if (error) { + if (error != ERR_FILE_EOF) { + _printerr(); + } else { + if (!ResourceCache::has(res_path)) { + resource->set_path(res_path); + } + resource->set_as_translation_remapped(translation_remapped); + } + return error; + } + + if (assign != String()) { + resource->set(assign, value); + //it's assignment + } else if (next_tag.name != String()) { + + error = ERR_FILE_CORRUPT; + error_text = "Extra tag found when parsing main resource file"; + _printerr(); + return error; + } else { + error = ERR_FILE_EOF; + return error; + } + } + + return OK; + + } else if (next_tag.name == "node") { + + if (!is_scene) { + + error_text += "found the 'node' tag on a resource file!"; + _printerr(); + error = ERR_FILE_CORRUPT; + return error; + } + + Ref packed_scene = _parse_node_tag(rp); + + if (!packed_scene.is_valid()) + return error; + + error = ERR_FILE_EOF; + //get it here + resource = packed_scene; + if (!ResourceCache::has(res_path)) { + packed_scene->set_path(res_path); + } + + return error; + + } else { + error_text += "Unknown tag in file: " + next_tag.name; + _printerr(); + error = ERR_FILE_CORRUPT; + return error; + } + + return OK; +} + +int ResourceInteractiveLoaderText::get_stage() const { + + return resource_current; +} +int ResourceInteractiveLoaderText::get_stage_count() const { + + return resources_total; //+ext_resources; +} + +void ResourceInteractiveLoaderText::set_translation_remapped(bool p_remapped) { + + translation_remapped = p_remapped; +} + +ResourceInteractiveLoaderText::ResourceInteractiveLoaderText() { + translation_remapped = false; +} + +ResourceInteractiveLoaderText::~ResourceInteractiveLoaderText() { + + memdelete(f); +} + +void ResourceInteractiveLoaderText::get_dependencies(FileAccess *p_f, List *p_dependencies, bool p_add_types) { + + open(p_f); + ignore_resource_parsing = true; + ERR_FAIL_COND(error != OK); + + while (next_tag.name == "ext_resource") { + + if (!next_tag.fields.has("type")) { + error = ERR_FILE_CORRUPT; + error_text = "Missing 'type' in external resource tag"; + _printerr(); + return; + } + + if (!next_tag.fields.has("id")) { + error = ERR_FILE_CORRUPT; + error_text = "Missing 'index' in external resource tag"; + _printerr(); + return; + } + + String path = next_tag.fields["path"]; + String type = next_tag.fields["type"]; + + if (path.find("://") == -1 && path.is_rel_path()) { + // path is relative to file being loaded, so convert to a resource path + path = ProjectSettings::get_singleton()->localize_path(local_path.get_base_dir().plus_file(path)); + } + + if (p_add_types) { + path += "::" + type; + } + + p_dependencies->push_back(path); + + Error err = VariantParser::parse_tag(&stream, lines, error_text, next_tag, &rp); + + if (err) { + print_line(error_text + " - " + itos(lines)); + error_text = "Unexpected end of file"; + _printerr(); + error = ERR_FILE_CORRUPT; + } + } +} + +Error ResourceInteractiveLoaderText::rename_dependencies(FileAccess *p_f, const String &p_path, const Map &p_map) { + + open(p_f, true); + ERR_FAIL_COND_V(error != OK, error); + ignore_resource_parsing = true; + //FileAccess + + FileAccess *fw = NULL; + + String base_path = local_path.get_base_dir(); + + uint64_t tag_end = f->get_position(); + + while (true) { + + Error err = VariantParser::parse_tag(&stream, lines, error_text, next_tag, &rp); + + if (err != OK) { + if (fw) { + memdelete(fw); + } + error = ERR_FILE_CORRUPT; + ERR_FAIL_V(error); + } + + if (next_tag.name != "ext_resource") { + + //nothing was done + if (!fw) + return OK; + + break; + + } else { + + if (!fw) { + + fw = FileAccess::open(p_path + ".depren", FileAccess::WRITE); + if (is_scene) { + fw->store_line("[gd_scene load_steps=" + itos(resources_total) + " format=" + itos(FORMAT_VERSION) + "]\n"); + } else { + fw->store_line("[gd_resource type=\"" + res_type + "\" load_steps=" + itos(resources_total) + " format=" + itos(FORMAT_VERSION) + "]\n"); + } + } + + if (!next_tag.fields.has("path") || !next_tag.fields.has("id") || !next_tag.fields.has("type")) { + memdelete(fw); + error = ERR_FILE_CORRUPT; + ERR_FAIL_V(error); + } + + String path = next_tag.fields["path"]; + int index = next_tag.fields["id"]; + String type = next_tag.fields["type"]; + + bool relative = false; + if (!path.begins_with("res://")) { + path = base_path.plus_file(path).simplify_path(); + relative = true; + } + + if (p_map.has(path)) { + String np = p_map[path]; + path = np; + } + + if (relative) { + //restore relative + path = base_path.path_to_file(path); + } + + fw->store_line("[ext_resource path=\"" + path + "\" type=\"" + type + "\" id=" + itos(index) + "]"); + + tag_end = f->get_position(); + } + } + + f->seek(tag_end); + + uint8_t c = f->get_8(); + while (!f->eof_reached()) { + fw->store_8(c); + c = f->get_8(); + } + f->close(); + + bool all_ok = fw->get_error() == OK; + + memdelete(fw); + + if (!all_ok) { + return ERR_CANT_CREATE; + } + + DirAccess *da = DirAccess::create(DirAccess::ACCESS_RESOURCES); + da->remove(p_path); + da->rename(p_path + ".depren", p_path); + memdelete(da); + + return OK; +} + +void ResourceInteractiveLoaderText::open(FileAccess *p_f, bool p_skip_first_tag) { + + error = OK; + + lines = 1; + f = p_f; + + stream.f = f; + is_scene = false; + ignore_resource_parsing = false; + resource_current = 0; + + VariantParser::Tag tag; + Error err = VariantParser::parse_tag(&stream, lines, error_text, tag); + + if (err) { + + error = err; + _printerr(); + return; + } + + if (tag.fields.has("format")) { + int fmt = tag.fields["format"]; + if (fmt > FORMAT_VERSION) { + error_text = "Saved with newer format version"; + _printerr(); + error = ERR_PARSE_ERROR; + return; + } + } + + if (tag.name == "gd_scene") { + is_scene = true; + + } else if (tag.name == "gd_resource") { + if (!tag.fields.has("type")) { + error_text = "Missing 'type' field in 'gd_resource' tag"; + _printerr(); + error = ERR_PARSE_ERROR; + return; + } + + res_type = tag.fields["type"]; + + } else { + error_text = "Unrecognized file type: " + tag.name; + _printerr(); + error = ERR_PARSE_ERROR; + return; + } + + if (tag.fields.has("load_steps")) { + resources_total = tag.fields["load_steps"]; + } else { + resources_total = 0; + } + + if (!p_skip_first_tag) { + + err = VariantParser::parse_tag(&stream, lines, error_text, next_tag, &rp); + + if (err) { + error_text = "Unexpected end of file"; + _printerr(); + error = ERR_FILE_CORRUPT; + } + } + + rp.ext_func = _parse_ext_resources; + rp.sub_func = _parse_sub_resources; + rp.func = NULL; + rp.userdata = this; +} + +static void bs_save_unicode_string(FileAccess *f, const String &p_string, bool p_bit_on_len = false) { + + CharString utf8 = p_string.utf8(); + if (p_bit_on_len) { + f->store_32((utf8.length() + 1) | 0x80000000); + } else { + f->store_32(utf8.length() + 1); + } + f->store_buffer((const uint8_t *)utf8.get_data(), utf8.length() + 1); +} + +Error ResourceInteractiveLoaderText::save_as_binary(FileAccess *p_f, const String &p_path) { + + if (error) + return error; + + FileAccessRef wf = FileAccess::open(p_path, FileAccess::WRITE); + if (!wf) { + return ERR_CANT_OPEN; + } + + //save header compressed + static const uint8_t header[4] = { 'R', 'S', 'R', 'C' }; + wf->store_buffer(header, 4); + + wf->store_32(0); //endianness, little endian + wf->store_32(0); //64 bits file, false for now + wf->store_32(VERSION_MAJOR); + wf->store_32(VERSION_MINOR); + static const int save_format_version = 3; //use format version 3 for saving + wf->store_32(save_format_version); + + bs_save_unicode_string(wf.f, is_scene ? "PackedScene" : resource_type); + wf->store_64(0); //offset to import metadata, this is no longer used + for (int i = 0; i < 14; i++) + wf->store_32(0); // reserved + + wf->store_32(0); //string table size, will not be in use + size_t ext_res_count_pos = wf->get_position(); + + wf->store_32(0); //zero ext resources, still parsing them + + //go with external resources + + DummyReadData dummy_read; + VariantParser::ResourceParser rp; + rp.ext_func = _parse_ext_resource_dummys; + rp.sub_func = _parse_sub_resource_dummys; + rp.userdata = &dummy_read; + + while (next_tag.name == "ext_resource") { + + if (!next_tag.fields.has("path")) { + error = ERR_FILE_CORRUPT; + error_text = "Missing 'path' in external resource tag"; + _printerr(); + return error; + } + + if (!next_tag.fields.has("type")) { + error = ERR_FILE_CORRUPT; + error_text = "Missing 'type' in external resource tag"; + _printerr(); + return error; + } + + if (!next_tag.fields.has("id")) { + error = ERR_FILE_CORRUPT; + error_text = "Missing 'id' in external resource tag"; + _printerr(); + return error; + } + + String path = next_tag.fields["path"]; + String type = next_tag.fields["type"]; + int index = next_tag.fields["id"]; + + bs_save_unicode_string(wf.f, type); + bs_save_unicode_string(wf.f, path); + + int lindex = dummy_read.external_resources.size(); + Ref dr; + dr.instance(); + dr->set_path("res://dummy" + itos(lindex)); //anything is good to detect it for saving as external + dummy_read.external_resources[dr] = lindex; + dummy_read.rev_external_resources[index] = dr; + + error = VariantParser::parse_tag(&stream, lines, error_text, next_tag, &rp); + + if (error) { + _printerr(); + return error; + } + } + + // save external resource table + wf->seek(ext_res_count_pos); + wf->store_32(dummy_read.external_resources.size()); + wf->seek_end(); + + //now, save resources to a separate file, for now + + size_t sub_res_count_pos = wf->get_position(); + wf->store_32(0); //zero sub resources, still parsing them + + String temp_file = p_path + ".temp"; + FileAccessRef wf2 = FileAccess::open(temp_file, FileAccess::WRITE); + if (!wf2) { + return ERR_CANT_OPEN; + } + + Vector local_offsets; + Vector local_pointers_pos; + + while (next_tag.name == "sub_resource" || next_tag.name == "resource") { + + String type; + int id = -1; + bool main_res; + + if (next_tag.name == "sub_resource") { + if (!next_tag.fields.has("type")) { + error = ERR_FILE_CORRUPT; + error_text = "Missing 'type' in external resource tag"; + _printerr(); + return error; + } + + if (!next_tag.fields.has("id")) { + error = ERR_FILE_CORRUPT; + error_text = "Missing 'index' in external resource tag"; + _printerr(); + return error; + } + + type = next_tag.fields["type"]; + id = next_tag.fields["id"]; + main_res = false; + } else { + type = res_type; + id = 0; //used for last anyway + main_res = true; + } + + local_offsets.push_back(wf2->get_position()); + + bs_save_unicode_string(wf, "local://" + itos(id)); + local_pointers_pos.push_back(wf->get_position()); + wf->store_64(0); //temp local offset + + bs_save_unicode_string(wf2, type); + size_t propcount_ofs = wf2->get_position(); + wf2->store_32(0); + + int prop_count = 0; + + while (true) { + + String assign; + Variant value; + + error = VariantParser::parse_tag_assign_eof(&stream, lines, error_text, next_tag, assign, value, &rp); + + if (error) { + if (main_res && error == ERR_FILE_EOF) { + next_tag.name = ""; //exit + break; + } + + _printerr(); + return error; + } + + if (assign != String()) { + + Map empty_string_map; //unused + bs_save_unicode_string(wf2, assign, true); + ResourceFormatSaverBinaryInstance::write_variant(wf2, value, dummy_read.resource_set, dummy_read.external_resources, empty_string_map); + prop_count++; + + } else if (next_tag.name != String()) { + + error = OK; + break; + } else { + error = ERR_FILE_CORRUPT; + error_text = "Premature end of file while parsing [sub_resource]"; + _printerr(); + return error; + } + } + + wf2->seek(propcount_ofs); + wf2->store_32(prop_count); + wf2->seek_end(); + } + + if (next_tag.name == "node") { + //this is a node, must save one more! + + if (!is_scene) { + + error_text += "found the 'node' tag on a resource file!"; + _printerr(); + error = ERR_FILE_CORRUPT; + return error; + } + + Ref packed_scene = _parse_node_tag(rp); + + if (!packed_scene.is_valid()) + return error; + + error = OK; + //get it here + List props; + packed_scene->get_property_list(&props); + + bs_save_unicode_string(wf, "local://0"); + local_pointers_pos.push_back(wf->get_position()); + wf->store_64(0); //temp local offset + + local_offsets.push_back(wf2->get_position()); + bs_save_unicode_string(wf2, "PackedScene"); + size_t propcount_ofs = wf2->get_position(); + wf2->store_32(0); + + int prop_count = 0; + + for (List::Element *E = props.front(); E; E = E->next()) { + + if (!(E->get().usage & PROPERTY_USAGE_STORAGE)) + continue; + + String name = E->get().name; + Variant value = packed_scene->get(name); + + Map empty_string_map; //unused + bs_save_unicode_string(wf2, name, true); + ResourceFormatSaverBinaryInstance::write_variant(wf2, value, dummy_read.resource_set, dummy_read.external_resources, empty_string_map); + prop_count++; + } + + wf2->seek(propcount_ofs); + wf2->store_32(prop_count); + wf2->seek_end(); + } + + wf2->close(); + + size_t offset_from = wf->get_position(); + wf->seek(sub_res_count_pos); //plus one because the saved one + wf->store_32(local_offsets.size()); + + for (int i = 0; i < local_offsets.size(); i++) { + wf->seek(local_pointers_pos[i]); + wf->store_64(local_offsets[i] + offset_from); + } + + wf->seek_end(); + + Vector data = FileAccess::get_file_as_array(temp_file); + wf->store_buffer(data.ptr(), data.size()); + { + DirAccessRef dar = DirAccess::open(temp_file.get_base_dir()); + dar->remove(temp_file); + } + + wf->store_buffer((const uint8_t *)"RSRC", 4); //magic at end + + wf->close(); + + return OK; +} + +String ResourceInteractiveLoaderText::recognize(FileAccess *p_f) { + + error = OK; + + lines = 1; + f = p_f; + + stream.f = f; + + ignore_resource_parsing = true; + + VariantParser::Tag tag; + Error err = VariantParser::parse_tag(&stream, lines, error_text, tag); + + if (err) { + _printerr(); + return ""; + } + + if (tag.fields.has("format")) { + int fmt = tag.fields["format"]; + if (fmt > FORMAT_VERSION) { + error_text = "Saved with newer format version"; + _printerr(); + return ""; + } + } + + if (tag.name == "gd_scene") + return "PackedScene"; + + if (tag.name != "gd_resource") + return ""; + + if (!tag.fields.has("type")) { + error_text = "Missing 'type' field in 'gd_resource' tag"; + _printerr(); + return ""; + } + + return tag.fields["type"]; +} + +///////////////////// + +Ref ResourceFormatLoaderText::load_interactive(const String &p_path, const String &p_original_path, Error *r_error) { + + if (r_error) + *r_error = ERR_CANT_OPEN; + + Error err; + FileAccess *f = FileAccess::open(p_path, FileAccess::READ, &err); + + if (err != OK) { + + ERR_FAIL_COND_V(err != OK, Ref()); + } + + Ref ria = memnew(ResourceInteractiveLoaderText); + String path = p_original_path != "" ? p_original_path : p_path; + ria->local_path = ProjectSettings::get_singleton()->localize_path(path); + ria->res_path = ria->local_path; + //ria->set_local_path( ProjectSettings::get_singleton()->localize_path(p_path) ); + ria->open(f); + + return ria; +} + +void ResourceFormatLoaderText::get_recognized_extensions_for_type(const String &p_type, List *p_extensions) const { + + if (p_type == "") { + get_recognized_extensions(p_extensions); + return; + } + + if (p_type == "PackedScene") + p_extensions->push_back("tscn"); + else + p_extensions->push_back("tres"); +} + +void ResourceFormatLoaderText::get_recognized_extensions(List *p_extensions) const { + + p_extensions->push_back("tscn"); + p_extensions->push_back("tres"); +} + +bool ResourceFormatLoaderText::handles_type(const String &p_type) const { + + return true; +} +String ResourceFormatLoaderText::get_resource_type(const String &p_path) const { + + String ext = p_path.get_extension().to_lower(); + if (ext == "tscn") + return "PackedScene"; + else if (ext != "tres") + return String(); + + //for anyhting else must test.. + + FileAccess *f = FileAccess::open(p_path, FileAccess::READ); + if (!f) { + + return ""; //could not rwead + } + + Ref ria = memnew(ResourceInteractiveLoaderText); + ria->local_path = ProjectSettings::get_singleton()->localize_path(p_path); + ria->res_path = ria->local_path; + //ria->set_local_path( ProjectSettings::get_singleton()->localize_path(p_path) ); + String r = ria->recognize(f); + return r; +} + +void ResourceFormatLoaderText::get_dependencies(const String &p_path, List *p_dependencies, bool p_add_types) { + + FileAccess *f = FileAccess::open(p_path, FileAccess::READ); + if (!f) { + + ERR_FAIL(); + } + + Ref ria = memnew(ResourceInteractiveLoaderText); + ria->local_path = ProjectSettings::get_singleton()->localize_path(p_path); + ria->res_path = ria->local_path; + //ria->set_local_path( ProjectSettings::get_singleton()->localize_path(p_path) ); + ria->get_dependencies(f, p_dependencies, p_add_types); +} + +Error ResourceFormatLoaderText::rename_dependencies(const String &p_path, const Map &p_map) { + + FileAccess *f = FileAccess::open(p_path, FileAccess::READ); + if (!f) { + + ERR_FAIL_V(ERR_CANT_OPEN); + } + + Ref ria = memnew(ResourceInteractiveLoaderText); + ria->local_path = ProjectSettings::get_singleton()->localize_path(p_path); + ria->res_path = ria->local_path; + //ria->set_local_path( ProjectSettings::get_singleton()->localize_path(p_path) ); + return ria->rename_dependencies(f, p_path, p_map); +} + +ResourceFormatLoaderText *ResourceFormatLoaderText::singleton = NULL; + +Error ResourceFormatLoaderText::convert_file_to_binary(const String &p_src_path, const String &p_dst_path) { + + Error err; + FileAccess *f = FileAccess::open(p_src_path, FileAccess::READ, &err); + + if (err != OK) { + + ERR_FAIL_COND_V(err != OK, ERR_CANT_OPEN); + } + + Ref ria = memnew(ResourceInteractiveLoaderText); + String path = p_src_path; + ria->local_path = ProjectSettings::get_singleton()->localize_path(path); + ria->res_path = ria->local_path; + //ria->set_local_path( ProjectSettings::get_singleton()->localize_path(p_path) ); + ria->open(f); + return ria->save_as_binary(f, p_dst_path); +} + +/*****************************************************************************************************/ +/*****************************************************************************************************/ +/*****************************************************************************************************/ +/*****************************************************************************************************/ +/*****************************************************************************************************/ +/*****************************************************************************************************/ +/*****************************************************************************************************/ +/*****************************************************************************************************/ +/*****************************************************************************************************/ +/*****************************************************************************************************/ + +String ResourceFormatSaverTextInstance::_write_resources(void *ud, const RES &p_resource) { + + ResourceFormatSaverTextInstance *rsi = (ResourceFormatSaverTextInstance *)ud; + return rsi->_write_resource(p_resource); +} + +String ResourceFormatSaverTextInstance::_write_resource(const RES &res) { + + if (external_resources.has(res)) { + + return "ExtResource( " + itos(external_resources[res] + 1) + " )"; + } else { + + if (internal_resources.has(res)) { + return "SubResource( " + itos(internal_resources[res]) + " )"; + } else if (res->get_path().length() && res->get_path().find("::") == -1) { + + //external resource + String path = relative_paths ? local_path.path_to_file(res->get_path()) : res->get_path(); + return "Resource( \"" + path + "\" )"; + } else { + ERR_EXPLAIN("Resource was not pre cached for the resource section, bug?"); + ERR_FAIL_V("null"); + //internal resource + } + } + + return "null"; +} + +void ResourceFormatSaverTextInstance::_find_resources(const Variant &p_variant, bool p_main) { + + switch (p_variant.get_type()) { + case Variant::OBJECT: { + + RES res = p_variant.operator RefPtr(); + + if (res.is_null() || external_resources.has(res)) + return; + + if (!p_main && (!bundle_resources) && res->get_path().length() && res->get_path().find("::") == -1) { + int index = external_resources.size(); + external_resources[res] = index; + return; + } + + if (resource_set.has(res)) + return; + + List property_list; + + res->get_property_list(&property_list); + property_list.sort(); + + List::Element *I = property_list.front(); + + while (I) { + + PropertyInfo pi = I->get(); + + if (pi.usage & PROPERTY_USAGE_STORAGE) { + + Variant v = res->get(I->get().name); + _find_resources(v); + } + + I = I->next(); + } + + resource_set.insert(res); //saved after, so the children it needs are available when loaded + saved_resources.push_back(res); + + } break; + case Variant::ARRAY: { + + Array varray = p_variant; + int len = varray.size(); + for (int i = 0; i < len; i++) { + + Variant v = varray.get(i); + _find_resources(v); + } + + } break; + case Variant::DICTIONARY: { + + Dictionary d = p_variant; + List keys; + d.get_key_list(&keys); + for (List::Element *E = keys.front(); E; E = E->next()) { + + Variant v = d[E->get()]; + _find_resources(v); + } + } break; + default: {} + } +} + +static String _valprop(const String &p_name) { + + // Escape and quote strings with extended ASCII or further Unicode characters + // as well as '"', '=' or ' ' (32) + const CharType *cstr = p_name.c_str(); + for (int i = 0; cstr[i]; i++) { + if (cstr[i] == '=' || cstr[i] == '"' || cstr[i] < 33 || cstr[i] > 126) { + return "\"" + p_name.c_escape_multiline() + "\""; + } + } + // Keep as is + return p_name; +} + +Error ResourceFormatSaverTextInstance::save(const String &p_path, const RES &p_resource, uint32_t p_flags) { + + if (p_path.ends_with(".tscn")) { + packed_scene = p_resource; + } + + Error err; + f = FileAccess::open(p_path, FileAccess::WRITE, &err); + ERR_FAIL_COND_V(err, ERR_CANT_OPEN); + FileAccessRef _fref(f); + + local_path = ProjectSettings::get_singleton()->localize_path(p_path); + + relative_paths = p_flags & ResourceSaver::FLAG_RELATIVE_PATHS; + skip_editor = p_flags & ResourceSaver::FLAG_OMIT_EDITOR_PROPERTIES; + bundle_resources = p_flags & ResourceSaver::FLAG_BUNDLE_RESOURCES; + takeover_paths = p_flags & ResourceSaver::FLAG_REPLACE_SUBRESOURCE_PATHS; + if (!p_path.begins_with("res://")) { + takeover_paths = false; + } + + // save resources + _find_resources(p_resource, true); + + if (packed_scene.is_valid()) { + //add instances to external resources if saving a packed scene + for (int i = 0; i < packed_scene->get_state()->get_node_count(); i++) { + if (packed_scene->get_state()->is_node_instance_placeholder(i)) + continue; + + Ref instance = packed_scene->get_state()->get_node_instance(i); + if (instance.is_valid() && !external_resources.has(instance)) { + int index = external_resources.size(); + external_resources[instance] = index; + } + } + } + + ERR_FAIL_COND_V(err != OK, err); + + { + String title = packed_scene.is_valid() ? "[gd_scene " : "[gd_resource "; + if (packed_scene.is_null()) + title += "type=\"" + p_resource->get_class() + "\" "; + int load_steps = saved_resources.size() + external_resources.size(); + /* + if (packed_scene.is_valid()) { + load_steps+=packed_scene->get_node_count(); + } + //no, better to not use load steps from nodes, no point to that + */ + + if (load_steps > 1) { + title += "load_steps=" + itos(load_steps) + " "; + } + title += "format=" + itos(FORMAT_VERSION) + ""; + + f->store_string(title); + f->store_line("]\n"); //one empty line + } + + Vector sorted_er; + sorted_er.resize(external_resources.size()); + + for (Map::Element *E = external_resources.front(); E; E = E->next()) { + + sorted_er.write[E->get()] = E->key(); + } + + for (int i = 0; i < sorted_er.size(); i++) { + String p = sorted_er[i]->get_path(); + + f->store_string("[ext_resource path=\"" + p + "\" type=\"" + sorted_er[i]->get_save_class() + "\" id=" + itos(i + 1) + "]\n"); //bundled + } + + if (external_resources.size()) + f->store_line(String()); //separate + + Set used_indices; + + for (List::Element *E = saved_resources.front(); E; E = E->next()) { + + RES res = E->get(); + if (E->next() && (res->get_path() == "" || res->get_path().find("::") != -1)) { + + if (res->get_subindex() != 0) { + if (used_indices.has(res->get_subindex())) { + res->set_subindex(0); //repeated + } else { + used_indices.insert(res->get_subindex()); + } + } + } + } + + for (List::Element *E = saved_resources.front(); E; E = E->next()) { + + RES res = E->get(); + ERR_CONTINUE(!resource_set.has(res)); + bool main = (E->next() == NULL); + + if (main && packed_scene.is_valid()) + break; //save as a scene + + if (main) { + f->store_line("[resource]"); + } else { + String line = "[sub_resource "; + if (res->get_subindex() == 0) { + int new_subindex = 1; + if (used_indices.size()) { + new_subindex = used_indices.back()->get() + 1; + } + + res->set_subindex(new_subindex); + used_indices.insert(new_subindex); + } + + int idx = res->get_subindex(); + line += "type=\"" + res->get_class() + "\" id=" + itos(idx); + f->store_line(line + "]"); + if (takeover_paths) { + res->set_path(p_path + "::" + itos(idx), true); + } + + internal_resources[res] = idx; +#ifdef TOOLS_ENABLED + res->set_edited(false); +#endif + } + + List property_list; + res->get_property_list(&property_list); + //property_list.sort(); + for (List::Element *PE = property_list.front(); PE; PE = PE->next()) { + + if (skip_editor && PE->get().name.begins_with("__editor")) + continue; + + if (PE->get().usage & PROPERTY_USAGE_STORAGE) { + + String name = PE->get().name; + Variant value = res->get(name); + Variant default_value = ClassDB::class_get_default_property_value(res->get_class(), name); + + if (default_value.get_type() != Variant::NIL && bool(Variant::evaluate(Variant::OP_EQUAL, value, default_value))) { + continue; + } + + if (PE->get().type == Variant::OBJECT && value.is_zero() && !(PE->get().usage & PROPERTY_USAGE_STORE_IF_NULL)) + continue; + + String vars; + VariantWriter::write_to_string(value, vars, _write_resources, this); + f->store_string(_valprop(name) + " = " + vars + "\n"); + } + } + + f->store_string("\n"); + } + + if (packed_scene.is_valid()) { + //if this is a scene, save nodes and connections! + Ref state = packed_scene->get_state(); + for (int i = 0; i < state->get_node_count(); i++) { + + StringName type = state->get_node_type(i); + StringName name = state->get_node_name(i); + int index = state->get_node_index(i); + NodePath path = state->get_node_path(i, true); + NodePath owner = state->get_node_owner_path(i); + Ref instance = state->get_node_instance(i); + String instance_placeholder = state->get_node_instance_placeholder(i); + Vector groups = state->get_node_groups(i); + + String header = "[node"; + header += " name=\"" + String(name) + "\""; + if (type != StringName()) { + header += " type=\"" + String(type) + "\""; + } + if (path != NodePath()) { + header += " parent=\"" + String(path.simplified()) + "\""; + } + if (owner != NodePath() && owner != NodePath(".")) { + header += " owner=\"" + String(owner.simplified()) + "\""; + } + if (index >= 0) { + header += " index=\"" + itos(index) + "\""; + } + + if (groups.size()) { + String sgroups = " groups=[\n"; + for (int j = 0; j < groups.size(); j++) { + sgroups += "\"" + String(groups[j]).c_escape() + "\",\n"; + } + sgroups += "]"; + header += sgroups; + } + + f->store_string(header); + + if (instance_placeholder != String()) { + + String vars; + f->store_string(" instance_placeholder="); + VariantWriter::write_to_string(instance_placeholder, vars, _write_resources, this); + f->store_string(vars); + } + + if (instance.is_valid()) { + + String vars; + f->store_string(" instance="); + VariantWriter::write_to_string(instance, vars, _write_resources, this); + f->store_string(vars); + } + + f->store_line("]"); + + for (int j = 0; j < state->get_node_property_count(i); j++) { + + String vars; + VariantWriter::write_to_string(state->get_node_property_value(i, j), vars, _write_resources, this); + + f->store_string(_valprop(String(state->get_node_property_name(i, j))) + " = " + vars + "\n"); + } + + f->store_line(String()); + } + + for (int i = 0; i < state->get_connection_count(); i++) { + + String connstr = "[connection"; + connstr += " signal=\"" + String(state->get_connection_signal(i)) + "\""; + connstr += " from=\"" + String(state->get_connection_source(i).simplified()) + "\""; + connstr += " to=\"" + String(state->get_connection_target(i).simplified()) + "\""; + connstr += " method=\"" + String(state->get_connection_method(i)) + "\""; + int flags = state->get_connection_flags(i); + if (flags != Object::CONNECT_PERSIST) { + connstr += " flags=" + itos(flags); + } + + Array binds = state->get_connection_binds(i); + f->store_string(connstr); + if (binds.size()) { + String vars; + VariantWriter::write_to_string(binds, vars, _write_resources, this); + f->store_string(" binds= " + vars); + } + + f->store_line("]"); + } + + Vector editable_instances = state->get_editable_instances(); + for (int i = 0; i < editable_instances.size(); i++) { + f->store_line("\n[editable path=\"" + editable_instances[i].operator String() + "\"]"); + } + } + + if (f->get_error() != OK && f->get_error() != ERR_FILE_EOF) { + f->close(); + return ERR_CANT_CREATE; + } + + f->close(); + //memdelete(f); + + return OK; +} + +Error ResourceFormatSaverText::save(const String &p_path, const RES &p_resource, uint32_t p_flags) { + + if (p_path.ends_with(".sct") && p_resource->get_class() != "PackedScene") { + return ERR_FILE_UNRECOGNIZED; + } + + ResourceFormatSaverTextInstance saver; + return saver.save(p_path, p_resource, p_flags); +} + +bool ResourceFormatSaverText::recognize(const RES &p_resource) const { + + return true; // all recognized! +} +void ResourceFormatSaverText::get_recognized_extensions(const RES &p_resource, List *p_extensions) const { + + if (p_resource->get_class() == "PackedScene") + p_extensions->push_back("tscn"); //text scene + else + p_extensions->push_back("tres"); //text resource +} + +ResourceFormatSaverText *ResourceFormatSaverText::singleton = NULL; +ResourceFormatSaverText::ResourceFormatSaverText() { + singleton = this; +} diff --git a/scene/resources/resource_format_text.h b/scene/resources/resource_format_text.h new file mode 100644 index 0000000000..526f7760d2 --- /dev/null +++ b/scene/resources/resource_format_text.h @@ -0,0 +1,183 @@ +/*************************************************************************/ +/* resource_format_text.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef RESOURCE_FORMAT_TEXT_H +#define RESOURCE_FORMAT_TEXT_H + +#include "core/io/resource_loader.h" +#include "core/io/resource_saver.h" +#include "core/os/file_access.h" +#include "core/variant_parser.h" +#include "scene/resources/packed_scene.h" + +class ResourceInteractiveLoaderText : public ResourceInteractiveLoader { + + bool translation_remapped; + String local_path; + String res_path; + String error_text; + + FileAccess *f; + + VariantParser::StreamFile stream; + + struct ExtResource { + String path; + String type; + }; + + bool is_scene; + String res_type; + + bool ignore_resource_parsing; + + //Map remaps; + + Map ext_resources; + + int resources_total; + int resource_current; + String resource_type; + + VariantParser::Tag next_tag; + + mutable int lines; + + Map remaps; + //void _printerr(); + + static Error _parse_sub_resources(void *p_self, VariantParser::Stream *p_stream, Ref &r_res, int &line, String &r_err_str) { return reinterpret_cast(p_self)->_parse_sub_resource(p_stream, r_res, line, r_err_str); } + static Error _parse_ext_resources(void *p_self, VariantParser::Stream *p_stream, Ref &r_res, int &line, String &r_err_str) { return reinterpret_cast(p_self)->_parse_ext_resource(p_stream, r_res, line, r_err_str); } + + Error _parse_sub_resource(VariantParser::Stream *p_stream, Ref &r_res, int &line, String &r_err_str); + Error _parse_ext_resource(VariantParser::Stream *p_stream, Ref &r_res, int &line, String &r_err_str); + + // for converter + class DummyResource : public Resource { + public: + }; + + struct DummyReadData { + + Map external_resources; + Map rev_external_resources; + Set resource_set; + Map resource_map; + }; + + static Error _parse_sub_resource_dummys(void *p_self, VariantParser::Stream *p_stream, Ref &r_res, int &line, String &r_err_str) { return _parse_sub_resource_dummy((DummyReadData *)(p_self), p_stream, r_res, line, r_err_str); } + static Error _parse_ext_resource_dummys(void *p_self, VariantParser::Stream *p_stream, Ref &r_res, int &line, String &r_err_str) { return _parse_ext_resource_dummy((DummyReadData *)(p_self), p_stream, r_res, line, r_err_str); } + + static Error _parse_sub_resource_dummy(DummyReadData *p_data, VariantParser::Stream *p_stream, Ref &r_res, int &line, String &r_err_str); + static Error _parse_ext_resource_dummy(DummyReadData *p_data, VariantParser::Stream *p_stream, Ref &r_res, int &line, String &r_err_str); + + VariantParser::ResourceParser rp; + + friend class ResourceFormatLoaderText; + + List resource_cache; + Error error; + + RES resource; + + Ref _parse_node_tag(VariantParser::ResourceParser &parser); + +public: + virtual void set_local_path(const String &p_local_path); + virtual Ref get_resource(); + virtual Error poll(); + virtual int get_stage() const; + virtual int get_stage_count() const; + virtual void set_translation_remapped(bool p_remapped); + + void open(FileAccess *p_f, bool p_skip_first_tag = false); + String recognize(FileAccess *p_f); + void get_dependencies(FileAccess *p_f, List *p_dependencies, bool p_add_types); + Error rename_dependencies(FileAccess *p_f, const String &p_path, const Map &p_map); + + Error save_as_binary(FileAccess *p_f, const String &p_path); + ResourceInteractiveLoaderText(); + ~ResourceInteractiveLoaderText(); +}; + +class ResourceFormatLoaderText : public ResourceFormatLoader { + GDCLASS(ResourceFormatLoaderText, ResourceFormatLoader) +public: + static ResourceFormatLoaderText *singleton; + virtual Ref load_interactive(const String &p_path, const String &p_original_path = "", Error *r_error = NULL); + virtual void get_recognized_extensions_for_type(const String &p_type, List *p_extensions) const; + virtual void get_recognized_extensions(List *p_extensions) const; + virtual bool handles_type(const String &p_type) const; + virtual String get_resource_type(const String &p_path) const; + virtual void get_dependencies(const String &p_path, List *p_dependencies, bool p_add_types = false); + virtual Error rename_dependencies(const String &p_path, const Map &p_map); + + static Error convert_file_to_binary(const String &p_src_path, const String &p_dst_path); + + ResourceFormatLoaderText() { singleton = this; } +}; + +class ResourceFormatSaverTextInstance { + + String local_path; + + Ref packed_scene; + + bool takeover_paths; + bool relative_paths; + bool bundle_resources; + bool skip_editor; + FileAccess *f; + Set resource_set; + List saved_resources; + Map external_resources; + Map internal_resources; + + void _find_resources(const Variant &p_variant, bool p_main = false); + + static String _write_resources(void *ud, const RES &p_resource); + String _write_resource(const RES &res); + +public: + Error save(const String &p_path, const RES &p_resource, uint32_t p_flags = 0); +}; + +class ResourceFormatSaverText : public ResourceFormatSaver { + GDCLASS(ResourceFormatSaverText, ResourceFormatSaver) +public: + static ResourceFormatSaverText *singleton; + virtual Error save(const String &p_path, const RES &p_resource, uint32_t p_flags = 0); + virtual bool recognize(const RES &p_resource) const; + virtual void get_recognized_extensions(const RES &p_resource, List *p_extensions) const; + + ResourceFormatSaverText(); +}; + +#endif // RESOURCE_FORMAT_TEXT_H diff --git a/scene/resources/scene_format_text.cpp b/scene/resources/scene_format_text.cpp deleted file mode 100644 index d00a7c2918..0000000000 --- a/scene/resources/scene_format_text.cpp +++ /dev/null @@ -1,1755 +0,0 @@ -/*************************************************************************/ -/* scene_format_text.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#include "scene_format_text.h" -#include "core/io/resource_format_binary.h" -#include "core/os/dir_access.h" -#include "core/project_settings.h" -#include "core/version.h" - -//version 2: changed names for basis, aabb, poolvectors, etc. -#define FORMAT_VERSION 2 - -#include "core/os/dir_access.h" -#include "core/version.h" - -#define _printerr() ERR_PRINT(String(res_path + ":" + itos(lines) + " - Parse Error: " + error_text).utf8().get_data()); - -/// - -void ResourceInteractiveLoaderText::set_local_path(const String &p_local_path) { - - res_path = p_local_path; -} - -Ref ResourceInteractiveLoaderText::get_resource() { - - return resource; -} - -Error ResourceInteractiveLoaderText::_parse_sub_resource_dummy(DummyReadData *p_data, VariantParser::Stream *p_stream, Ref &r_res, int &line, String &r_err_str) { - - VariantParser::Token token; - VariantParser::get_token(p_stream, token, line, r_err_str); - if (token.type != VariantParser::TK_NUMBER) { - r_err_str = "Expected number (sub-resource index)"; - return ERR_PARSE_ERROR; - } - - int index = token.value; - - if (!p_data->resource_map.has(index)) { - Ref dr; - dr.instance(); - dr->set_subindex(index); - p_data->resource_map[index] = dr; - p_data->resource_set.insert(dr); - } - - r_res = p_data->resource_map[index]; - - VariantParser::get_token(p_stream, token, line, r_err_str); - if (token.type != VariantParser::TK_PARENTHESIS_CLOSE) { - r_err_str = "Expected ')'"; - return ERR_PARSE_ERROR; - } - - return OK; -} - -Error ResourceInteractiveLoaderText::_parse_ext_resource_dummy(DummyReadData *p_data, VariantParser::Stream *p_stream, Ref &r_res, int &line, String &r_err_str) { - - VariantParser::Token token; - VariantParser::get_token(p_stream, token, line, r_err_str); - if (token.type != VariantParser::TK_NUMBER) { - r_err_str = "Expected number (sub-resource index)"; - return ERR_PARSE_ERROR; - } - - int id = token.value; - - ERR_FAIL_COND_V(!p_data->rev_external_resources.has(id), ERR_PARSE_ERROR); - - r_res = p_data->rev_external_resources[id]; - - VariantParser::get_token(p_stream, token, line, r_err_str); - if (token.type != VariantParser::TK_PARENTHESIS_CLOSE) { - r_err_str = "Expected ')'"; - return ERR_PARSE_ERROR; - } - - return OK; -} - -Error ResourceInteractiveLoaderText::_parse_sub_resource(VariantParser::Stream *p_stream, Ref &r_res, int &line, String &r_err_str) { - - VariantParser::Token token; - VariantParser::get_token(p_stream, token, line, r_err_str); - if (token.type != VariantParser::TK_NUMBER) { - r_err_str = "Expected number (sub-resource index)"; - return ERR_PARSE_ERROR; - } - - int index = token.value; - - String path = local_path + "::" + itos(index); - - if (!ignore_resource_parsing) { - - if (!ResourceCache::has(path)) { - r_err_str = "Can't load cached sub-resource: " + path; - return ERR_PARSE_ERROR; - } - - r_res = RES(ResourceCache::get(path)); - } else { - r_res = RES(); - } - - VariantParser::get_token(p_stream, token, line, r_err_str); - if (token.type != VariantParser::TK_PARENTHESIS_CLOSE) { - r_err_str = "Expected ')'"; - return ERR_PARSE_ERROR; - } - - return OK; -} - -Error ResourceInteractiveLoaderText::_parse_ext_resource(VariantParser::Stream *p_stream, Ref &r_res, int &line, String &r_err_str) { - - VariantParser::Token token; - VariantParser::get_token(p_stream, token, line, r_err_str); - if (token.type != VariantParser::TK_NUMBER) { - r_err_str = "Expected number (sub-resource index)"; - return ERR_PARSE_ERROR; - } - - int id = token.value; - - if (!ignore_resource_parsing) { - - if (!ext_resources.has(id)) { - r_err_str = "Can't load cached ext-resource #" + itos(id); - return ERR_PARSE_ERROR; - } - - String path = ext_resources[id].path; - String type = ext_resources[id].type; - - if (path.find("://") == -1 && path.is_rel_path()) { - // path is relative to file being loaded, so convert to a resource path - path = ProjectSettings::get_singleton()->localize_path(res_path.get_base_dir().plus_file(path)); - } - - r_res = ResourceLoader::load(path, type); - - if (r_res.is_null()) { - WARN_PRINT(String("Couldn't load external resource: " + path).utf8().get_data()); - } - } else { - r_res = RES(); - } - - VariantParser::get_token(p_stream, token, line, r_err_str); - if (token.type != VariantParser::TK_PARENTHESIS_CLOSE) { - r_err_str = "Expected ')'"; - return ERR_PARSE_ERROR; - } - - return OK; -} - -Ref ResourceInteractiveLoaderText::_parse_node_tag(VariantParser::ResourceParser &parser) { - Ref packed_scene; - packed_scene.instance(); - - while (true) { - - if (next_tag.name == "node") { - - int parent = -1; - int owner = -1; - int type = -1; - int name = -1; - int instance = -1; - int index = -1; - //int base_scene=-1; - - if (next_tag.fields.has("name")) { - name = packed_scene->get_state()->add_name(next_tag.fields["name"]); - } - - if (next_tag.fields.has("parent")) { - NodePath np = next_tag.fields["parent"]; - np.prepend_period(); //compatible to how it manages paths internally - parent = packed_scene->get_state()->add_node_path(np); - } - - if (next_tag.fields.has("type")) { - type = packed_scene->get_state()->add_name(next_tag.fields["type"]); - } else { - type = SceneState::TYPE_INSTANCED; //no type? assume this was instanced - } - - if (next_tag.fields.has("instance")) { - - instance = packed_scene->get_state()->add_value(next_tag.fields["instance"]); - - if (packed_scene->get_state()->get_node_count() == 0 && parent == -1) { - packed_scene->get_state()->set_base_scene(instance); - instance = -1; - } - } - - if (next_tag.fields.has("instance_placeholder")) { - - String path = next_tag.fields["instance_placeholder"]; - - int path_v = packed_scene->get_state()->add_value(path); - - if (packed_scene->get_state()->get_node_count() == 0) { - error = ERR_FILE_CORRUPT; - error_text = "Instance Placeholder can't be used for inheritance."; - _printerr(); - return Ref(); - } - - instance = path_v | SceneState::FLAG_INSTANCE_IS_PLACEHOLDER; - } - - if (next_tag.fields.has("owner")) { - owner = packed_scene->get_state()->add_node_path(next_tag.fields["owner"]); - } else { - if (parent != -1 && !(type == SceneState::TYPE_INSTANCED && instance == -1)) - owner = 0; //if no owner, owner is root - } - - if (next_tag.fields.has("index")) { - index = next_tag.fields["index"]; - } - - int node_id = packed_scene->get_state()->add_node(parent, owner, type, name, instance, index); - - if (next_tag.fields.has("groups")) { - - Array groups = next_tag.fields["groups"]; - for (int i = 0; i < groups.size(); i++) { - packed_scene->get_state()->add_node_group(node_id, packed_scene->get_state()->add_name(groups[i])); - } - } - - while (true) { - - String assign; - Variant value; - - error = VariantParser::parse_tag_assign_eof(&stream, lines, error_text, next_tag, assign, value, &parser); - - if (error) { - if (error != ERR_FILE_EOF) { - _printerr(); - return Ref(); - } else { - return packed_scene; - } - } - - if (assign != String()) { - int nameidx = packed_scene->get_state()->add_name(assign); - int valueidx = packed_scene->get_state()->add_value(value); - packed_scene->get_state()->add_node_property(node_id, nameidx, valueidx); - //it's assignment - } else if (next_tag.name != String()) { - break; - } - } - } else if (next_tag.name == "connection") { - - if (!next_tag.fields.has("from")) { - error = ERR_FILE_CORRUPT; - error_text = "missing 'from' field from connection tag"; - return Ref(); - } - - if (!next_tag.fields.has("to")) { - error = ERR_FILE_CORRUPT; - error_text = "missing 'to' field from connection tag"; - return Ref(); - } - - if (!next_tag.fields.has("signal")) { - error = ERR_FILE_CORRUPT; - error_text = "missing 'signal' field from connection tag"; - return Ref(); - } - - if (!next_tag.fields.has("method")) { - error = ERR_FILE_CORRUPT; - error_text = "missing 'method' field from connection tag"; - return Ref(); - } - - NodePath from = next_tag.fields["from"]; - NodePath to = next_tag.fields["to"]; - StringName method = next_tag.fields["method"]; - StringName signal = next_tag.fields["signal"]; - int flags = CONNECT_PERSIST; - Array binds; - - if (next_tag.fields.has("flags")) { - flags = next_tag.fields["flags"]; - } - - if (next_tag.fields.has("binds")) { - binds = next_tag.fields["binds"]; - } - - Vector bind_ints; - for (int i = 0; i < binds.size(); i++) { - bind_ints.push_back(packed_scene->get_state()->add_value(binds[i])); - } - - packed_scene->get_state()->add_connection( - packed_scene->get_state()->add_node_path(from.simplified()), - packed_scene->get_state()->add_node_path(to.simplified()), - packed_scene->get_state()->add_name(signal), - packed_scene->get_state()->add_name(method), - flags, - bind_ints); - - error = VariantParser::parse_tag(&stream, lines, error_text, next_tag, &parser); - - if (error) { - if (error != ERR_FILE_EOF) { - _printerr(); - return Ref(); - } else { - return packed_scene; - } - } - } else if (next_tag.name == "editable") { - - if (!next_tag.fields.has("path")) { - error = ERR_FILE_CORRUPT; - error_text = "missing 'path' field from connection tag"; - _printerr(); - return Ref(); - } - - NodePath path = next_tag.fields["path"]; - - packed_scene->get_state()->add_editable_instance(path.simplified()); - - error = VariantParser::parse_tag(&stream, lines, error_text, next_tag, &parser); - - if (error) { - if (error != ERR_FILE_EOF) { - _printerr(); - return Ref(); - } else { - return packed_scene; - } - } - } else { - - error = ERR_FILE_CORRUPT; - _printerr(); - return Ref(); - } - } - - return packed_scene; -} - -Error ResourceInteractiveLoaderText::poll() { - - if (error != OK) - return error; - - if (next_tag.name == "ext_resource") { - - if (!next_tag.fields.has("path")) { - error = ERR_FILE_CORRUPT; - error_text = "Missing 'path' in external resource tag"; - _printerr(); - return error; - } - - if (!next_tag.fields.has("type")) { - error = ERR_FILE_CORRUPT; - error_text = "Missing 'type' in external resource tag"; - _printerr(); - return error; - } - - if (!next_tag.fields.has("id")) { - error = ERR_FILE_CORRUPT; - error_text = "Missing 'id' in external resource tag"; - _printerr(); - return error; - } - - String path = next_tag.fields["path"]; - String type = next_tag.fields["type"]; - int index = next_tag.fields["id"]; - - if (path.find("://") == -1 && path.is_rel_path()) { - // path is relative to file being loaded, so convert to a resource path - path = ProjectSettings::get_singleton()->localize_path(local_path.get_base_dir().plus_file(path)); - } - - if (remaps.has(path)) { - path = remaps[path]; - } - - RES res = ResourceLoader::load(path, type); - - if (res.is_null()) { - - if (ResourceLoader::get_abort_on_missing_resources()) { - error = ERR_FILE_CORRUPT; - error_text = "[ext_resource] referenced nonexistent resource at: " + path; - _printerr(); - return error; - } else { - ResourceLoader::notify_dependency_error(local_path, path, type); - } - } else { - - resource_cache.push_back(res); - } - - ExtResource er; - er.path = path; - er.type = type; - ext_resources[index] = er; - - error = VariantParser::parse_tag(&stream, lines, error_text, next_tag, &rp); - - if (error) { - _printerr(); - } - - resource_current++; - return error; - - } else if (next_tag.name == "sub_resource") { - - if (!next_tag.fields.has("type")) { - error = ERR_FILE_CORRUPT; - error_text = "Missing 'type' in external resource tag"; - _printerr(); - return error; - } - - if (!next_tag.fields.has("id")) { - error = ERR_FILE_CORRUPT; - error_text = "Missing 'index' in external resource tag"; - _printerr(); - return error; - } - - String type = next_tag.fields["type"]; - int id = next_tag.fields["id"]; - - String path = local_path + "::" + itos(id); - - //bool exists=ResourceCache::has(path); - - Ref res; - - if (!ResourceCache::has(path)) { //only if it doesn't exist - - Object *obj = ClassDB::instance(type); - if (!obj) { - - error_text += "Can't create sub resource of type: " + type; - _printerr(); - error = ERR_FILE_CORRUPT; - return error; - } - - Resource *r = Object::cast_to(obj); - if (!r) { - - error_text += "Can't create sub resource of type, because not a resource: " + type; - _printerr(); - error = ERR_FILE_CORRUPT; - return error; - } - - res = Ref(r); - resource_cache.push_back(res); - res->set_path(path); - } - - resource_current++; - - while (true) { - - String assign; - Variant value; - - error = VariantParser::parse_tag_assign_eof(&stream, lines, error_text, next_tag, assign, value, &rp); - - if (error) { - _printerr(); - return error; - } - - if (assign != String()) { - if (res.is_valid()) { - res->set(assign, value); - } - //it's assignment - } else if (next_tag.name != String()) { - - error = OK; - break; - } else { - error = ERR_FILE_CORRUPT; - error_text = "Premature end of file while parsing [sub_resource]"; - _printerr(); - return error; - } - } - - return OK; - - } else if (next_tag.name == "resource") { - - if (is_scene) { - - error_text += "found the 'resource' tag on a scene file!"; - _printerr(); - error = ERR_FILE_CORRUPT; - return error; - } - - Object *obj = ClassDB::instance(res_type); - if (!obj) { - - error_text += "Can't create sub resource of type: " + res_type; - _printerr(); - error = ERR_FILE_CORRUPT; - return error; - } - - Resource *r = Object::cast_to(obj); - if (!r) { - - error_text += "Can't create sub resource of type, because not a resource: " + res_type; - _printerr(); - error = ERR_FILE_CORRUPT; - return error; - } - - resource = Ref(r); - - resource_current++; - - while (true) { - - String assign; - Variant value; - - error = VariantParser::parse_tag_assign_eof(&stream, lines, error_text, next_tag, assign, value, &rp); - - if (error) { - if (error != ERR_FILE_EOF) { - _printerr(); - } else { - if (!ResourceCache::has(res_path)) { - resource->set_path(res_path); - } - resource->set_as_translation_remapped(translation_remapped); - } - return error; - } - - if (assign != String()) { - resource->set(assign, value); - //it's assignment - } else if (next_tag.name != String()) { - - error = ERR_FILE_CORRUPT; - error_text = "Extra tag found when parsing main resource file"; - _printerr(); - return error; - } else { - error = ERR_FILE_EOF; - return error; - } - } - - return OK; - - } else if (next_tag.name == "node") { - - if (!is_scene) { - - error_text += "found the 'node' tag on a resource file!"; - _printerr(); - error = ERR_FILE_CORRUPT; - return error; - } - - Ref packed_scene = _parse_node_tag(rp); - - if (!packed_scene.is_valid()) - return error; - - error = ERR_FILE_EOF; - //get it here - resource = packed_scene; - if (!ResourceCache::has(res_path)) { - packed_scene->set_path(res_path); - } - - return error; - - } else { - error_text += "Unknown tag in file: " + next_tag.name; - _printerr(); - error = ERR_FILE_CORRUPT; - return error; - } - - return OK; -} - -int ResourceInteractiveLoaderText::get_stage() const { - - return resource_current; -} -int ResourceInteractiveLoaderText::get_stage_count() const { - - return resources_total; //+ext_resources; -} - -void ResourceInteractiveLoaderText::set_translation_remapped(bool p_remapped) { - - translation_remapped = p_remapped; -} - -ResourceInteractiveLoaderText::ResourceInteractiveLoaderText() { - translation_remapped = false; -} - -ResourceInteractiveLoaderText::~ResourceInteractiveLoaderText() { - - memdelete(f); -} - -void ResourceInteractiveLoaderText::get_dependencies(FileAccess *p_f, List *p_dependencies, bool p_add_types) { - - open(p_f); - ignore_resource_parsing = true; - ERR_FAIL_COND(error != OK); - - while (next_tag.name == "ext_resource") { - - if (!next_tag.fields.has("type")) { - error = ERR_FILE_CORRUPT; - error_text = "Missing 'type' in external resource tag"; - _printerr(); - return; - } - - if (!next_tag.fields.has("id")) { - error = ERR_FILE_CORRUPT; - error_text = "Missing 'index' in external resource tag"; - _printerr(); - return; - } - - String path = next_tag.fields["path"]; - String type = next_tag.fields["type"]; - - if (path.find("://") == -1 && path.is_rel_path()) { - // path is relative to file being loaded, so convert to a resource path - path = ProjectSettings::get_singleton()->localize_path(local_path.get_base_dir().plus_file(path)); - } - - if (p_add_types) { - path += "::" + type; - } - - p_dependencies->push_back(path); - - Error err = VariantParser::parse_tag(&stream, lines, error_text, next_tag, &rp); - - if (err) { - print_line(error_text + " - " + itos(lines)); - error_text = "Unexpected end of file"; - _printerr(); - error = ERR_FILE_CORRUPT; - } - } -} - -Error ResourceInteractiveLoaderText::rename_dependencies(FileAccess *p_f, const String &p_path, const Map &p_map) { - - open(p_f, true); - ERR_FAIL_COND_V(error != OK, error); - ignore_resource_parsing = true; - //FileAccess - - FileAccess *fw = NULL; - - String base_path = local_path.get_base_dir(); - - uint64_t tag_end = f->get_position(); - - while (true) { - - Error err = VariantParser::parse_tag(&stream, lines, error_text, next_tag, &rp); - - if (err != OK) { - if (fw) { - memdelete(fw); - } - error = ERR_FILE_CORRUPT; - ERR_FAIL_V(error); - } - - if (next_tag.name != "ext_resource") { - - //nothing was done - if (!fw) - return OK; - - break; - - } else { - - if (!fw) { - - fw = FileAccess::open(p_path + ".depren", FileAccess::WRITE); - if (is_scene) { - fw->store_line("[gd_scene load_steps=" + itos(resources_total) + " format=" + itos(FORMAT_VERSION) + "]\n"); - } else { - fw->store_line("[gd_resource type=\"" + res_type + "\" load_steps=" + itos(resources_total) + " format=" + itos(FORMAT_VERSION) + "]\n"); - } - } - - if (!next_tag.fields.has("path") || !next_tag.fields.has("id") || !next_tag.fields.has("type")) { - memdelete(fw); - error = ERR_FILE_CORRUPT; - ERR_FAIL_V(error); - } - - String path = next_tag.fields["path"]; - int index = next_tag.fields["id"]; - String type = next_tag.fields["type"]; - - bool relative = false; - if (!path.begins_with("res://")) { - path = base_path.plus_file(path).simplify_path(); - relative = true; - } - - if (p_map.has(path)) { - String np = p_map[path]; - path = np; - } - - if (relative) { - //restore relative - path = base_path.path_to_file(path); - } - - fw->store_line("[ext_resource path=\"" + path + "\" type=\"" + type + "\" id=" + itos(index) + "]"); - - tag_end = f->get_position(); - } - } - - f->seek(tag_end); - - uint8_t c = f->get_8(); - while (!f->eof_reached()) { - fw->store_8(c); - c = f->get_8(); - } - f->close(); - - bool all_ok = fw->get_error() == OK; - - memdelete(fw); - - if (!all_ok) { - return ERR_CANT_CREATE; - } - - DirAccess *da = DirAccess::create(DirAccess::ACCESS_RESOURCES); - da->remove(p_path); - da->rename(p_path + ".depren", p_path); - memdelete(da); - - return OK; -} - -void ResourceInteractiveLoaderText::open(FileAccess *p_f, bool p_skip_first_tag) { - - error = OK; - - lines = 1; - f = p_f; - - stream.f = f; - is_scene = false; - ignore_resource_parsing = false; - resource_current = 0; - - VariantParser::Tag tag; - Error err = VariantParser::parse_tag(&stream, lines, error_text, tag); - - if (err) { - - error = err; - _printerr(); - return; - } - - if (tag.fields.has("format")) { - int fmt = tag.fields["format"]; - if (fmt > FORMAT_VERSION) { - error_text = "Saved with newer format version"; - _printerr(); - error = ERR_PARSE_ERROR; - return; - } - } - - if (tag.name == "gd_scene") { - is_scene = true; - - } else if (tag.name == "gd_resource") { - if (!tag.fields.has("type")) { - error_text = "Missing 'type' field in 'gd_resource' tag"; - _printerr(); - error = ERR_PARSE_ERROR; - return; - } - - res_type = tag.fields["type"]; - - } else { - error_text = "Unrecognized file type: " + tag.name; - _printerr(); - error = ERR_PARSE_ERROR; - return; - } - - if (tag.fields.has("load_steps")) { - resources_total = tag.fields["load_steps"]; - } else { - resources_total = 0; - } - - if (!p_skip_first_tag) { - - err = VariantParser::parse_tag(&stream, lines, error_text, next_tag, &rp); - - if (err) { - error_text = "Unexpected end of file"; - _printerr(); - error = ERR_FILE_CORRUPT; - } - } - - rp.ext_func = _parse_ext_resources; - rp.sub_func = _parse_sub_resources; - rp.func = NULL; - rp.userdata = this; -} - -static void bs_save_unicode_string(FileAccess *f, const String &p_string, bool p_bit_on_len = false) { - - CharString utf8 = p_string.utf8(); - if (p_bit_on_len) { - f->store_32((utf8.length() + 1) | 0x80000000); - } else { - f->store_32(utf8.length() + 1); - } - f->store_buffer((const uint8_t *)utf8.get_data(), utf8.length() + 1); -} - -Error ResourceInteractiveLoaderText::save_as_binary(FileAccess *p_f, const String &p_path) { - - if (error) - return error; - - FileAccessRef wf = FileAccess::open(p_path, FileAccess::WRITE); - if (!wf) { - return ERR_CANT_OPEN; - } - - //save header compressed - static const uint8_t header[4] = { 'R', 'S', 'R', 'C' }; - wf->store_buffer(header, 4); - - wf->store_32(0); //endianness, little endian - wf->store_32(0); //64 bits file, false for now - wf->store_32(VERSION_MAJOR); - wf->store_32(VERSION_MINOR); - static const int save_format_version = 3; //use format version 3 for saving - wf->store_32(save_format_version); - - bs_save_unicode_string(wf.f, is_scene ? "PackedScene" : resource_type); - wf->store_64(0); //offset to import metadata, this is no longer used - for (int i = 0; i < 14; i++) - wf->store_32(0); // reserved - - wf->store_32(0); //string table size, will not be in use - size_t ext_res_count_pos = wf->get_position(); - - wf->store_32(0); //zero ext resources, still parsing them - - //go with external resources - - DummyReadData dummy_read; - VariantParser::ResourceParser rp; - rp.ext_func = _parse_ext_resource_dummys; - rp.sub_func = _parse_sub_resource_dummys; - rp.userdata = &dummy_read; - - while (next_tag.name == "ext_resource") { - - if (!next_tag.fields.has("path")) { - error = ERR_FILE_CORRUPT; - error_text = "Missing 'path' in external resource tag"; - _printerr(); - return error; - } - - if (!next_tag.fields.has("type")) { - error = ERR_FILE_CORRUPT; - error_text = "Missing 'type' in external resource tag"; - _printerr(); - return error; - } - - if (!next_tag.fields.has("id")) { - error = ERR_FILE_CORRUPT; - error_text = "Missing 'id' in external resource tag"; - _printerr(); - return error; - } - - String path = next_tag.fields["path"]; - String type = next_tag.fields["type"]; - int index = next_tag.fields["id"]; - - bs_save_unicode_string(wf.f, type); - bs_save_unicode_string(wf.f, path); - - int lindex = dummy_read.external_resources.size(); - Ref dr; - dr.instance(); - dr->set_path("res://dummy" + itos(lindex)); //anything is good to detect it for saving as external - dummy_read.external_resources[dr] = lindex; - dummy_read.rev_external_resources[index] = dr; - - error = VariantParser::parse_tag(&stream, lines, error_text, next_tag, &rp); - - if (error) { - _printerr(); - return error; - } - } - - // save external resource table - wf->seek(ext_res_count_pos); - wf->store_32(dummy_read.external_resources.size()); - wf->seek_end(); - - //now, save resources to a separate file, for now - - size_t sub_res_count_pos = wf->get_position(); - wf->store_32(0); //zero sub resources, still parsing them - - String temp_file = p_path + ".temp"; - FileAccessRef wf2 = FileAccess::open(temp_file, FileAccess::WRITE); - if (!wf2) { - return ERR_CANT_OPEN; - } - - Vector local_offsets; - Vector local_pointers_pos; - - while (next_tag.name == "sub_resource" || next_tag.name == "resource") { - - String type; - int id = -1; - bool main_res; - - if (next_tag.name == "sub_resource") { - if (!next_tag.fields.has("type")) { - error = ERR_FILE_CORRUPT; - error_text = "Missing 'type' in external resource tag"; - _printerr(); - return error; - } - - if (!next_tag.fields.has("id")) { - error = ERR_FILE_CORRUPT; - error_text = "Missing 'index' in external resource tag"; - _printerr(); - return error; - } - - type = next_tag.fields["type"]; - id = next_tag.fields["id"]; - main_res = false; - } else { - type = res_type; - id = 0; //used for last anyway - main_res = true; - } - - local_offsets.push_back(wf2->get_position()); - - bs_save_unicode_string(wf, "local://" + itos(id)); - local_pointers_pos.push_back(wf->get_position()); - wf->store_64(0); //temp local offset - - bs_save_unicode_string(wf2, type); - size_t propcount_ofs = wf2->get_position(); - wf2->store_32(0); - - int prop_count = 0; - - while (true) { - - String assign; - Variant value; - - error = VariantParser::parse_tag_assign_eof(&stream, lines, error_text, next_tag, assign, value, &rp); - - if (error) { - if (main_res && error == ERR_FILE_EOF) { - next_tag.name = ""; //exit - break; - } - - _printerr(); - return error; - } - - if (assign != String()) { - - Map empty_string_map; //unused - bs_save_unicode_string(wf2, assign, true); - ResourceFormatSaverBinaryInstance::write_variant(wf2, value, dummy_read.resource_set, dummy_read.external_resources, empty_string_map); - prop_count++; - - } else if (next_tag.name != String()) { - - error = OK; - break; - } else { - error = ERR_FILE_CORRUPT; - error_text = "Premature end of file while parsing [sub_resource]"; - _printerr(); - return error; - } - } - - wf2->seek(propcount_ofs); - wf2->store_32(prop_count); - wf2->seek_end(); - } - - if (next_tag.name == "node") { - //this is a node, must save one more! - - if (!is_scene) { - - error_text += "found the 'node' tag on a resource file!"; - _printerr(); - error = ERR_FILE_CORRUPT; - return error; - } - - Ref packed_scene = _parse_node_tag(rp); - - if (!packed_scene.is_valid()) - return error; - - error = OK; - //get it here - List props; - packed_scene->get_property_list(&props); - - bs_save_unicode_string(wf, "local://0"); - local_pointers_pos.push_back(wf->get_position()); - wf->store_64(0); //temp local offset - - local_offsets.push_back(wf2->get_position()); - bs_save_unicode_string(wf2, "PackedScene"); - size_t propcount_ofs = wf2->get_position(); - wf2->store_32(0); - - int prop_count = 0; - - for (List::Element *E = props.front(); E; E = E->next()) { - - if (!(E->get().usage & PROPERTY_USAGE_STORAGE)) - continue; - - String name = E->get().name; - Variant value = packed_scene->get(name); - - Map empty_string_map; //unused - bs_save_unicode_string(wf2, name, true); - ResourceFormatSaverBinaryInstance::write_variant(wf2, value, dummy_read.resource_set, dummy_read.external_resources, empty_string_map); - prop_count++; - } - - wf2->seek(propcount_ofs); - wf2->store_32(prop_count); - wf2->seek_end(); - } - - wf2->close(); - - size_t offset_from = wf->get_position(); - wf->seek(sub_res_count_pos); //plus one because the saved one - wf->store_32(local_offsets.size()); - - for (int i = 0; i < local_offsets.size(); i++) { - wf->seek(local_pointers_pos[i]); - wf->store_64(local_offsets[i] + offset_from); - } - - wf->seek_end(); - - Vector data = FileAccess::get_file_as_array(temp_file); - wf->store_buffer(data.ptr(), data.size()); - { - DirAccessRef dar = DirAccess::open(temp_file.get_base_dir()); - dar->remove(temp_file); - } - - wf->store_buffer((const uint8_t *)"RSRC", 4); //magic at end - - wf->close(); - - return OK; -} - -String ResourceInteractiveLoaderText::recognize(FileAccess *p_f) { - - error = OK; - - lines = 1; - f = p_f; - - stream.f = f; - - ignore_resource_parsing = true; - - VariantParser::Tag tag; - Error err = VariantParser::parse_tag(&stream, lines, error_text, tag); - - if (err) { - _printerr(); - return ""; - } - - if (tag.fields.has("format")) { - int fmt = tag.fields["format"]; - if (fmt > FORMAT_VERSION) { - error_text = "Saved with newer format version"; - _printerr(); - return ""; - } - } - - if (tag.name == "gd_scene") - return "PackedScene"; - - if (tag.name != "gd_resource") - return ""; - - if (!tag.fields.has("type")) { - error_text = "Missing 'type' field in 'gd_resource' tag"; - _printerr(); - return ""; - } - - return tag.fields["type"]; -} - -///////////////////// - -Ref ResourceFormatLoaderText::load_interactive(const String &p_path, const String &p_original_path, Error *r_error) { - - if (r_error) - *r_error = ERR_CANT_OPEN; - - Error err; - FileAccess *f = FileAccess::open(p_path, FileAccess::READ, &err); - - if (err != OK) { - - ERR_FAIL_COND_V(err != OK, Ref()); - } - - Ref ria = memnew(ResourceInteractiveLoaderText); - String path = p_original_path != "" ? p_original_path : p_path; - ria->local_path = ProjectSettings::get_singleton()->localize_path(path); - ria->res_path = ria->local_path; - //ria->set_local_path( ProjectSettings::get_singleton()->localize_path(p_path) ); - ria->open(f); - - return ria; -} - -void ResourceFormatLoaderText::get_recognized_extensions_for_type(const String &p_type, List *p_extensions) const { - - if (p_type == "") { - get_recognized_extensions(p_extensions); - return; - } - - if (p_type == "PackedScene") - p_extensions->push_back("tscn"); - else - p_extensions->push_back("tres"); -} - -void ResourceFormatLoaderText::get_recognized_extensions(List *p_extensions) const { - - p_extensions->push_back("tscn"); - p_extensions->push_back("tres"); -} - -bool ResourceFormatLoaderText::handles_type(const String &p_type) const { - - return true; -} -String ResourceFormatLoaderText::get_resource_type(const String &p_path) const { - - String ext = p_path.get_extension().to_lower(); - if (ext == "tscn") - return "PackedScene"; - else if (ext != "tres") - return String(); - - //for anyhting else must test.. - - FileAccess *f = FileAccess::open(p_path, FileAccess::READ); - if (!f) { - - return ""; //could not rwead - } - - Ref ria = memnew(ResourceInteractiveLoaderText); - ria->local_path = ProjectSettings::get_singleton()->localize_path(p_path); - ria->res_path = ria->local_path; - //ria->set_local_path( ProjectSettings::get_singleton()->localize_path(p_path) ); - String r = ria->recognize(f); - return r; -} - -void ResourceFormatLoaderText::get_dependencies(const String &p_path, List *p_dependencies, bool p_add_types) { - - FileAccess *f = FileAccess::open(p_path, FileAccess::READ); - if (!f) { - - ERR_FAIL(); - } - - Ref ria = memnew(ResourceInteractiveLoaderText); - ria->local_path = ProjectSettings::get_singleton()->localize_path(p_path); - ria->res_path = ria->local_path; - //ria->set_local_path( ProjectSettings::get_singleton()->localize_path(p_path) ); - ria->get_dependencies(f, p_dependencies, p_add_types); -} - -Error ResourceFormatLoaderText::rename_dependencies(const String &p_path, const Map &p_map) { - - FileAccess *f = FileAccess::open(p_path, FileAccess::READ); - if (!f) { - - ERR_FAIL_V(ERR_CANT_OPEN); - } - - Ref ria = memnew(ResourceInteractiveLoaderText); - ria->local_path = ProjectSettings::get_singleton()->localize_path(p_path); - ria->res_path = ria->local_path; - //ria->set_local_path( ProjectSettings::get_singleton()->localize_path(p_path) ); - return ria->rename_dependencies(f, p_path, p_map); -} - -ResourceFormatLoaderText *ResourceFormatLoaderText::singleton = NULL; - -Error ResourceFormatLoaderText::convert_file_to_binary(const String &p_src_path, const String &p_dst_path) { - - Error err; - FileAccess *f = FileAccess::open(p_src_path, FileAccess::READ, &err); - - if (err != OK) { - - ERR_FAIL_COND_V(err != OK, ERR_CANT_OPEN); - } - - Ref ria = memnew(ResourceInteractiveLoaderText); - String path = p_src_path; - ria->local_path = ProjectSettings::get_singleton()->localize_path(path); - ria->res_path = ria->local_path; - //ria->set_local_path( ProjectSettings::get_singleton()->localize_path(p_path) ); - ria->open(f); - return ria->save_as_binary(f, p_dst_path); -} - -/*****************************************************************************************************/ -/*****************************************************************************************************/ -/*****************************************************************************************************/ -/*****************************************************************************************************/ -/*****************************************************************************************************/ -/*****************************************************************************************************/ -/*****************************************************************************************************/ -/*****************************************************************************************************/ -/*****************************************************************************************************/ -/*****************************************************************************************************/ - -String ResourceFormatSaverTextInstance::_write_resources(void *ud, const RES &p_resource) { - - ResourceFormatSaverTextInstance *rsi = (ResourceFormatSaverTextInstance *)ud; - return rsi->_write_resource(p_resource); -} - -String ResourceFormatSaverTextInstance::_write_resource(const RES &res) { - - if (external_resources.has(res)) { - - return "ExtResource( " + itos(external_resources[res] + 1) + " )"; - } else { - - if (internal_resources.has(res)) { - return "SubResource( " + itos(internal_resources[res]) + " )"; - } else if (res->get_path().length() && res->get_path().find("::") == -1) { - - //external resource - String path = relative_paths ? local_path.path_to_file(res->get_path()) : res->get_path(); - return "Resource( \"" + path + "\" )"; - } else { - ERR_EXPLAIN("Resource was not pre cached for the resource section, bug?"); - ERR_FAIL_V("null"); - //internal resource - } - } - - return "null"; -} - -void ResourceFormatSaverTextInstance::_find_resources(const Variant &p_variant, bool p_main) { - - switch (p_variant.get_type()) { - case Variant::OBJECT: { - - RES res = p_variant.operator RefPtr(); - - if (res.is_null() || external_resources.has(res)) - return; - - if (!p_main && (!bundle_resources) && res->get_path().length() && res->get_path().find("::") == -1) { - int index = external_resources.size(); - external_resources[res] = index; - return; - } - - if (resource_set.has(res)) - return; - - List property_list; - - res->get_property_list(&property_list); - property_list.sort(); - - List::Element *I = property_list.front(); - - while (I) { - - PropertyInfo pi = I->get(); - - if (pi.usage & PROPERTY_USAGE_STORAGE) { - - Variant v = res->get(I->get().name); - _find_resources(v); - } - - I = I->next(); - } - - resource_set.insert(res); //saved after, so the children it needs are available when loaded - saved_resources.push_back(res); - - } break; - case Variant::ARRAY: { - - Array varray = p_variant; - int len = varray.size(); - for (int i = 0; i < len; i++) { - - Variant v = varray.get(i); - _find_resources(v); - } - - } break; - case Variant::DICTIONARY: { - - Dictionary d = p_variant; - List keys; - d.get_key_list(&keys); - for (List::Element *E = keys.front(); E; E = E->next()) { - - Variant v = d[E->get()]; - _find_resources(v); - } - } break; - default: {} - } -} - -static String _valprop(const String &p_name) { - - // Escape and quote strings with extended ASCII or further Unicode characters - // as well as '"', '=' or ' ' (32) - const CharType *cstr = p_name.c_str(); - for (int i = 0; cstr[i]; i++) { - if (cstr[i] == '=' || cstr[i] == '"' || cstr[i] < 33 || cstr[i] > 126) { - return "\"" + p_name.c_escape_multiline() + "\""; - } - } - // Keep as is - return p_name; -} - -Error ResourceFormatSaverTextInstance::save(const String &p_path, const RES &p_resource, uint32_t p_flags) { - - if (p_path.ends_with(".tscn")) { - packed_scene = p_resource; - } - - Error err; - f = FileAccess::open(p_path, FileAccess::WRITE, &err); - ERR_FAIL_COND_V(err, ERR_CANT_OPEN); - FileAccessRef _fref(f); - - local_path = ProjectSettings::get_singleton()->localize_path(p_path); - - relative_paths = p_flags & ResourceSaver::FLAG_RELATIVE_PATHS; - skip_editor = p_flags & ResourceSaver::FLAG_OMIT_EDITOR_PROPERTIES; - bundle_resources = p_flags & ResourceSaver::FLAG_BUNDLE_RESOURCES; - takeover_paths = p_flags & ResourceSaver::FLAG_REPLACE_SUBRESOURCE_PATHS; - if (!p_path.begins_with("res://")) { - takeover_paths = false; - } - - // save resources - _find_resources(p_resource, true); - - if (packed_scene.is_valid()) { - //add instances to external resources if saving a packed scene - for (int i = 0; i < packed_scene->get_state()->get_node_count(); i++) { - if (packed_scene->get_state()->is_node_instance_placeholder(i)) - continue; - - Ref instance = packed_scene->get_state()->get_node_instance(i); - if (instance.is_valid() && !external_resources.has(instance)) { - int index = external_resources.size(); - external_resources[instance] = index; - } - } - } - - ERR_FAIL_COND_V(err != OK, err); - - { - String title = packed_scene.is_valid() ? "[gd_scene " : "[gd_resource "; - if (packed_scene.is_null()) - title += "type=\"" + p_resource->get_class() + "\" "; - int load_steps = saved_resources.size() + external_resources.size(); - /* - if (packed_scene.is_valid()) { - load_steps+=packed_scene->get_node_count(); - } - //no, better to not use load steps from nodes, no point to that - */ - - if (load_steps > 1) { - title += "load_steps=" + itos(load_steps) + " "; - } - title += "format=" + itos(FORMAT_VERSION) + ""; - - f->store_string(title); - f->store_line("]\n"); //one empty line - } - - Vector sorted_er; - sorted_er.resize(external_resources.size()); - - for (Map::Element *E = external_resources.front(); E; E = E->next()) { - - sorted_er.write[E->get()] = E->key(); - } - - for (int i = 0; i < sorted_er.size(); i++) { - String p = sorted_er[i]->get_path(); - - f->store_string("[ext_resource path=\"" + p + "\" type=\"" + sorted_er[i]->get_save_class() + "\" id=" + itos(i + 1) + "]\n"); //bundled - } - - if (external_resources.size()) - f->store_line(String()); //separate - - Set used_indices; - - for (List::Element *E = saved_resources.front(); E; E = E->next()) { - - RES res = E->get(); - if (E->next() && (res->get_path() == "" || res->get_path().find("::") != -1)) { - - if (res->get_subindex() != 0) { - if (used_indices.has(res->get_subindex())) { - res->set_subindex(0); //repeated - } else { - used_indices.insert(res->get_subindex()); - } - } - } - } - - for (List::Element *E = saved_resources.front(); E; E = E->next()) { - - RES res = E->get(); - ERR_CONTINUE(!resource_set.has(res)); - bool main = (E->next() == NULL); - - if (main && packed_scene.is_valid()) - break; //save as a scene - - if (main) { - f->store_line("[resource]"); - } else { - String line = "[sub_resource "; - if (res->get_subindex() == 0) { - int new_subindex = 1; - if (used_indices.size()) { - new_subindex = used_indices.back()->get() + 1; - } - - res->set_subindex(new_subindex); - used_indices.insert(new_subindex); - } - - int idx = res->get_subindex(); - line += "type=\"" + res->get_class() + "\" id=" + itos(idx); - f->store_line(line + "]"); - if (takeover_paths) { - res->set_path(p_path + "::" + itos(idx), true); - } - - internal_resources[res] = idx; -#ifdef TOOLS_ENABLED - res->set_edited(false); -#endif - } - - List property_list; - res->get_property_list(&property_list); - //property_list.sort(); - for (List::Element *PE = property_list.front(); PE; PE = PE->next()) { - - if (skip_editor && PE->get().name.begins_with("__editor")) - continue; - - if (PE->get().usage & PROPERTY_USAGE_STORAGE) { - - String name = PE->get().name; - Variant value = res->get(name); - Variant default_value = ClassDB::class_get_default_property_value(res->get_class(), name); - - if (default_value.get_type() != Variant::NIL && bool(Variant::evaluate(Variant::OP_EQUAL, value, default_value))) { - continue; - } - - if (PE->get().type == Variant::OBJECT && value.is_zero() && !(PE->get().usage & PROPERTY_USAGE_STORE_IF_NULL)) - continue; - - String vars; - VariantWriter::write_to_string(value, vars, _write_resources, this); - f->store_string(_valprop(name) + " = " + vars + "\n"); - } - } - - f->store_string("\n"); - } - - if (packed_scene.is_valid()) { - //if this is a scene, save nodes and connections! - Ref state = packed_scene->get_state(); - for (int i = 0; i < state->get_node_count(); i++) { - - StringName type = state->get_node_type(i); - StringName name = state->get_node_name(i); - int index = state->get_node_index(i); - NodePath path = state->get_node_path(i, true); - NodePath owner = state->get_node_owner_path(i); - Ref instance = state->get_node_instance(i); - String instance_placeholder = state->get_node_instance_placeholder(i); - Vector groups = state->get_node_groups(i); - - String header = "[node"; - header += " name=\"" + String(name) + "\""; - if (type != StringName()) { - header += " type=\"" + String(type) + "\""; - } - if (path != NodePath()) { - header += " parent=\"" + String(path.simplified()) + "\""; - } - if (owner != NodePath() && owner != NodePath(".")) { - header += " owner=\"" + String(owner.simplified()) + "\""; - } - if (index >= 0) { - header += " index=\"" + itos(index) + "\""; - } - - if (groups.size()) { - String sgroups = " groups=[\n"; - for (int j = 0; j < groups.size(); j++) { - sgroups += "\"" + String(groups[j]).c_escape() + "\",\n"; - } - sgroups += "]"; - header += sgroups; - } - - f->store_string(header); - - if (instance_placeholder != String()) { - - String vars; - f->store_string(" instance_placeholder="); - VariantWriter::write_to_string(instance_placeholder, vars, _write_resources, this); - f->store_string(vars); - } - - if (instance.is_valid()) { - - String vars; - f->store_string(" instance="); - VariantWriter::write_to_string(instance, vars, _write_resources, this); - f->store_string(vars); - } - - f->store_line("]"); - - for (int j = 0; j < state->get_node_property_count(i); j++) { - - String vars; - VariantWriter::write_to_string(state->get_node_property_value(i, j), vars, _write_resources, this); - - f->store_string(_valprop(String(state->get_node_property_name(i, j))) + " = " + vars + "\n"); - } - - f->store_line(String()); - } - - for (int i = 0; i < state->get_connection_count(); i++) { - - String connstr = "[connection"; - connstr += " signal=\"" + String(state->get_connection_signal(i)) + "\""; - connstr += " from=\"" + String(state->get_connection_source(i).simplified()) + "\""; - connstr += " to=\"" + String(state->get_connection_target(i).simplified()) + "\""; - connstr += " method=\"" + String(state->get_connection_method(i)) + "\""; - int flags = state->get_connection_flags(i); - if (flags != Object::CONNECT_PERSIST) { - connstr += " flags=" + itos(flags); - } - - Array binds = state->get_connection_binds(i); - f->store_string(connstr); - if (binds.size()) { - String vars; - VariantWriter::write_to_string(binds, vars, _write_resources, this); - f->store_string(" binds= " + vars); - } - - f->store_line("]"); - } - - Vector editable_instances = state->get_editable_instances(); - for (int i = 0; i < editable_instances.size(); i++) { - f->store_line("\n[editable path=\"" + editable_instances[i].operator String() + "\"]"); - } - } - - if (f->get_error() != OK && f->get_error() != ERR_FILE_EOF) { - f->close(); - return ERR_CANT_CREATE; - } - - f->close(); - //memdelete(f); - - return OK; -} - -Error ResourceFormatSaverText::save(const String &p_path, const RES &p_resource, uint32_t p_flags) { - - if (p_path.ends_with(".sct") && p_resource->get_class() != "PackedScene") { - return ERR_FILE_UNRECOGNIZED; - } - - ResourceFormatSaverTextInstance saver; - return saver.save(p_path, p_resource, p_flags); -} - -bool ResourceFormatSaverText::recognize(const RES &p_resource) const { - - return true; // all recognized! -} -void ResourceFormatSaverText::get_recognized_extensions(const RES &p_resource, List *p_extensions) const { - - if (p_resource->get_class() == "PackedScene") - p_extensions->push_back("tscn"); //text scene - else - p_extensions->push_back("tres"); //text resource -} - -ResourceFormatSaverText *ResourceFormatSaverText::singleton = NULL; -ResourceFormatSaverText::ResourceFormatSaverText() { - singleton = this; -} diff --git a/scene/resources/scene_format_text.h b/scene/resources/scene_format_text.h deleted file mode 100644 index 8fedbd0dd6..0000000000 --- a/scene/resources/scene_format_text.h +++ /dev/null @@ -1,183 +0,0 @@ -/*************************************************************************/ -/* scene_format_text.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#ifndef SCENE_FORMAT_TEXT_H -#define SCENE_FORMAT_TEXT_H - -#include "core/io/resource_loader.h" -#include "core/io/resource_saver.h" -#include "core/os/file_access.h" -#include "core/variant_parser.h" -#include "scene/resources/packed_scene.h" - -class ResourceInteractiveLoaderText : public ResourceInteractiveLoader { - - bool translation_remapped; - String local_path; - String res_path; - String error_text; - - FileAccess *f; - - VariantParser::StreamFile stream; - - struct ExtResource { - String path; - String type; - }; - - bool is_scene; - String res_type; - - bool ignore_resource_parsing; - - //Map remaps; - - Map ext_resources; - - int resources_total; - int resource_current; - String resource_type; - - VariantParser::Tag next_tag; - - mutable int lines; - - Map remaps; - //void _printerr(); - - static Error _parse_sub_resources(void *p_self, VariantParser::Stream *p_stream, Ref &r_res, int &line, String &r_err_str) { return reinterpret_cast(p_self)->_parse_sub_resource(p_stream, r_res, line, r_err_str); } - static Error _parse_ext_resources(void *p_self, VariantParser::Stream *p_stream, Ref &r_res, int &line, String &r_err_str) { return reinterpret_cast(p_self)->_parse_ext_resource(p_stream, r_res, line, r_err_str); } - - Error _parse_sub_resource(VariantParser::Stream *p_stream, Ref &r_res, int &line, String &r_err_str); - Error _parse_ext_resource(VariantParser::Stream *p_stream, Ref &r_res, int &line, String &r_err_str); - - // for converter - class DummyResource : public Resource { - public: - }; - - struct DummyReadData { - - Map external_resources; - Map rev_external_resources; - Set resource_set; - Map resource_map; - }; - - static Error _parse_sub_resource_dummys(void *p_self, VariantParser::Stream *p_stream, Ref &r_res, int &line, String &r_err_str) { return _parse_sub_resource_dummy((DummyReadData *)(p_self), p_stream, r_res, line, r_err_str); } - static Error _parse_ext_resource_dummys(void *p_self, VariantParser::Stream *p_stream, Ref &r_res, int &line, String &r_err_str) { return _parse_ext_resource_dummy((DummyReadData *)(p_self), p_stream, r_res, line, r_err_str); } - - static Error _parse_sub_resource_dummy(DummyReadData *p_data, VariantParser::Stream *p_stream, Ref &r_res, int &line, String &r_err_str); - static Error _parse_ext_resource_dummy(DummyReadData *p_data, VariantParser::Stream *p_stream, Ref &r_res, int &line, String &r_err_str); - - VariantParser::ResourceParser rp; - - friend class ResourceFormatLoaderText; - - List resource_cache; - Error error; - - RES resource; - - Ref _parse_node_tag(VariantParser::ResourceParser &parser); - -public: - virtual void set_local_path(const String &p_local_path); - virtual Ref get_resource(); - virtual Error poll(); - virtual int get_stage() const; - virtual int get_stage_count() const; - virtual void set_translation_remapped(bool p_remapped); - - void open(FileAccess *p_f, bool p_skip_first_tag = false); - String recognize(FileAccess *p_f); - void get_dependencies(FileAccess *p_f, List *p_dependencies, bool p_add_types); - Error rename_dependencies(FileAccess *p_f, const String &p_path, const Map &p_map); - - Error save_as_binary(FileAccess *p_f, const String &p_path); - ResourceInteractiveLoaderText(); - ~ResourceInteractiveLoaderText(); -}; - -class ResourceFormatLoaderText : public ResourceFormatLoader { - GDCLASS(ResourceFormatLoaderText, ResourceFormatLoader) -public: - static ResourceFormatLoaderText *singleton; - virtual Ref load_interactive(const String &p_path, const String &p_original_path = "", Error *r_error = NULL); - virtual void get_recognized_extensions_for_type(const String &p_type, List *p_extensions) const; - virtual void get_recognized_extensions(List *p_extensions) const; - virtual bool handles_type(const String &p_type) const; - virtual String get_resource_type(const String &p_path) const; - virtual void get_dependencies(const String &p_path, List *p_dependencies, bool p_add_types = false); - virtual Error rename_dependencies(const String &p_path, const Map &p_map); - - static Error convert_file_to_binary(const String &p_src_path, const String &p_dst_path); - - ResourceFormatLoaderText() { singleton = this; } -}; - -class ResourceFormatSaverTextInstance { - - String local_path; - - Ref packed_scene; - - bool takeover_paths; - bool relative_paths; - bool bundle_resources; - bool skip_editor; - FileAccess *f; - Set resource_set; - List saved_resources; - Map external_resources; - Map internal_resources; - - void _find_resources(const Variant &p_variant, bool p_main = false); - - static String _write_resources(void *ud, const RES &p_resource); - String _write_resource(const RES &res); - -public: - Error save(const String &p_path, const RES &p_resource, uint32_t p_flags = 0); -}; - -class ResourceFormatSaverText : public ResourceFormatSaver { - GDCLASS(ResourceFormatSaverText, ResourceFormatSaver) -public: - static ResourceFormatSaverText *singleton; - virtual Error save(const String &p_path, const RES &p_resource, uint32_t p_flags = 0); - virtual bool recognize(const RES &p_resource) const; - virtual void get_recognized_extensions(const RES &p_resource, List *p_extensions) const; - - ResourceFormatSaverText(); -}; - -#endif // SCENE_FORMAT_TEXT_H diff --git a/scene/resources/shape_line_2d.cpp b/scene/resources/shape_line_2d.cpp deleted file mode 100644 index 4ca535658f..0000000000 --- a/scene/resources/shape_line_2d.cpp +++ /dev/null @@ -1,120 +0,0 @@ -/*************************************************************************/ -/* shape_line_2d.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#include "shape_line_2d.h" -#include "servers/physics_2d_server.h" -#include "servers/visual_server.h" - -bool LineShape2D::_edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const { - - Vector2 point = get_d() * get_normal(); - Vector2 l[2][2] = { { point - get_normal().tangent() * 100, point + get_normal().tangent() * 100 }, { point, point + get_normal() * 30 } }; - - for (int i = 0; i < 2; i++) { - Vector2 closest = Geometry::get_closest_point_to_segment_2d(p_point, l[i]); - if (p_point.distance_to(closest) < p_tolerance) - return true; - } - - return false; -} - -void LineShape2D::_update_shape() { - - Array arr; - arr.push_back(normal); - arr.push_back(d); - Physics2DServer::get_singleton()->shape_set_data(get_rid(), arr); - emit_changed(); -} - -void LineShape2D::set_normal(const Vector2 &p_normal) { - - normal = p_normal; - _update_shape(); -} - -void LineShape2D::set_d(real_t p_d) { - - d = p_d; - _update_shape(); -} - -Vector2 LineShape2D::get_normal() const { - - return normal; -} -real_t LineShape2D::get_d() const { - - return d; -} - -void LineShape2D::draw(const RID &p_to_rid, const Color &p_color) { - - Vector2 point = get_d() * get_normal(); - - Vector2 l1[2] = { point - get_normal().tangent() * 100, point + get_normal().tangent() * 100 }; - VS::get_singleton()->canvas_item_add_line(p_to_rid, l1[0], l1[1], p_color, 3); - Vector2 l2[2] = { point, point + get_normal() * 30 }; - VS::get_singleton()->canvas_item_add_line(p_to_rid, l2[0], l2[1], p_color, 3); -} -Rect2 LineShape2D::get_rect() const { - - Vector2 point = get_d() * get_normal(); - - Vector2 l1[2] = { point - get_normal().tangent() * 100, point + get_normal().tangent() * 100 }; - Vector2 l2[2] = { point, point + get_normal() * 30 }; - Rect2 rect; - rect.position = l1[0]; - rect.expand_to(l1[1]); - rect.expand_to(l2[0]); - rect.expand_to(l2[1]); - return rect; -} - -void LineShape2D::_bind_methods() { - - ClassDB::bind_method(D_METHOD("set_normal", "normal"), &LineShape2D::set_normal); - ClassDB::bind_method(D_METHOD("get_normal"), &LineShape2D::get_normal); - - ClassDB::bind_method(D_METHOD("set_d", "d"), &LineShape2D::set_d); - ClassDB::bind_method(D_METHOD("get_d"), &LineShape2D::get_d); - - ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "normal"), "set_normal", "get_normal"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "d"), "set_d", "get_d"); -} - -LineShape2D::LineShape2D() : - Shape2D(Physics2DServer::get_singleton()->line_shape_create()) { - - normal = Vector2(0, -1); - d = 0; - _update_shape(); -} diff --git a/scene/resources/shape_line_2d.h b/scene/resources/shape_line_2d.h deleted file mode 100644 index dd3dbe3a43..0000000000 --- a/scene/resources/shape_line_2d.h +++ /dev/null @@ -1,62 +0,0 @@ -/*************************************************************************/ -/* shape_line_2d.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#ifndef SHAPE_LINE_2D_H -#define SHAPE_LINE_2D_H - -#include "scene/resources/shape_2d.h" - -class LineShape2D : public Shape2D { - GDCLASS(LineShape2D, Shape2D); - - Vector2 normal; - real_t d; - - void _update_shape(); - -protected: - static void _bind_methods(); - -public: - virtual bool _edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const; - - void set_normal(const Vector2 &p_normal); - void set_d(real_t p_d); - - Vector2 get_normal() const; - real_t get_d() const; - - virtual void draw(const RID &p_to_rid, const Color &p_color); - virtual Rect2 get_rect() const; - - LineShape2D(); -}; - -#endif // SHAPE_LINE_2D_H diff --git a/scene/resources/sky.cpp b/scene/resources/sky.cpp new file mode 100644 index 0000000000..a473fe8b7f --- /dev/null +++ b/scene/resources/sky.cpp @@ -0,0 +1,577 @@ +/*************************************************************************/ +/* sky.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "sky.h" + +#include "core/io/image_loader.h" + +void Sky::set_radiance_size(RadianceSize p_size) { + ERR_FAIL_INDEX(p_size, RADIANCE_SIZE_MAX); + + radiance_size = p_size; + _radiance_changed(); +} + +Sky::RadianceSize Sky::get_radiance_size() const { + + return radiance_size; +} + +void Sky::_bind_methods() { + + ClassDB::bind_method(D_METHOD("set_radiance_size", "size"), &Sky::set_radiance_size); + ClassDB::bind_method(D_METHOD("get_radiance_size"), &Sky::get_radiance_size); + + ADD_PROPERTY(PropertyInfo(Variant::INT, "radiance_size", PROPERTY_HINT_ENUM, "32,64,128,256,512,1024,2048"), "set_radiance_size", "get_radiance_size"); + + BIND_ENUM_CONSTANT(RADIANCE_SIZE_32); + BIND_ENUM_CONSTANT(RADIANCE_SIZE_64); + BIND_ENUM_CONSTANT(RADIANCE_SIZE_128); + BIND_ENUM_CONSTANT(RADIANCE_SIZE_256); + BIND_ENUM_CONSTANT(RADIANCE_SIZE_512); + BIND_ENUM_CONSTANT(RADIANCE_SIZE_1024); + BIND_ENUM_CONSTANT(RADIANCE_SIZE_2048); + BIND_ENUM_CONSTANT(RADIANCE_SIZE_MAX); +} + +Sky::Sky() { + radiance_size = RADIANCE_SIZE_512; +} + +///////////////////////////////////////// + +void PanoramaSky::_radiance_changed() { + + if (panorama.is_valid()) { + static const int size[RADIANCE_SIZE_MAX] = { + 32, 64, 128, 256, 512, 1024, 2048 + }; + VS::get_singleton()->sky_set_texture(sky, panorama->get_rid(), size[get_radiance_size()]); + } +} + +void PanoramaSky::set_panorama(const Ref &p_panorama) { + + panorama = p_panorama; + + if (panorama.is_valid()) { + + _radiance_changed(); + + } else { + VS::get_singleton()->sky_set_texture(sky, RID(), 0); + } +} + +Ref PanoramaSky::get_panorama() const { + + return panorama; +} + +RID PanoramaSky::get_rid() const { + + return sky; +} + +void PanoramaSky::_bind_methods() { + + ClassDB::bind_method(D_METHOD("set_panorama", "texture"), &PanoramaSky::set_panorama); + ClassDB::bind_method(D_METHOD("get_panorama"), &PanoramaSky::get_panorama); + + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "panorama", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_panorama", "get_panorama"); +} + +PanoramaSky::PanoramaSky() { + + sky = VS::get_singleton()->sky_create(); +} + +PanoramaSky::~PanoramaSky() { + + VS::get_singleton()->free(sky); +} +////////////////////////////////// + +void ProceduralSky::_radiance_changed() { + + if (update_queued) + return; //do nothing yet + + static const int size[RADIANCE_SIZE_MAX] = { + 32, 64, 128, 256, 512, 1024, 2048 + }; + VS::get_singleton()->sky_set_texture(sky, texture, size[get_radiance_size()]); +} + +Ref ProceduralSky::_generate_sky() { + + update_queued = false; + + PoolVector imgdata; + + static const int size[TEXTURE_SIZE_MAX] = { + 256, 512, 1024, 2048, 4096 + }; + + int w = size[texture_size]; + int h = w / 2; + + imgdata.resize(w * h * 4); //RGBE + + { + PoolVector::Write dataw = imgdata.write(); + + uint32_t *ptr = (uint32_t *)dataw.ptr(); + + Color sky_top_linear = sky_top_color.to_linear(); + Color sky_horizon_linear = sky_horizon_color.to_linear(); + + Color ground_bottom_linear = ground_bottom_color.to_linear(); + Color ground_horizon_linear = ground_horizon_color.to_linear(); + + //Color sun_linear = sun_color.to_linear(); + + Vector3 sun(0, 0, -1); + + sun = Basis(Vector3(1, 0, 0), Math::deg2rad(sun_latitude)).xform(sun); + sun = Basis(Vector3(0, 1, 0), Math::deg2rad(sun_longitude)).xform(sun); + + sun.normalize(); + + for (int i = 0; i < w; i++) { + + float u = float(i) / (w - 1); + float phi = u * 2.0 * Math_PI; + + for (int j = 0; j < h; j++) { + + float v = float(j) / (h - 1); + float theta = v * Math_PI; + + Vector3 normal( + Math::sin(phi) * Math::sin(theta) * -1.0, + Math::cos(theta), + Math::cos(phi) * Math::sin(theta) * -1.0); + + normal.normalize(); + + float v_angle = Math::acos(CLAMP(normal.y, -1.0, 1.0)); + + Color color; + + if (normal.y < 0) { + //ground + + float c = (v_angle - (Math_PI * 0.5)) / (Math_PI * 0.5); + color = ground_horizon_linear.linear_interpolate(ground_bottom_linear, Math::ease(c, ground_curve)); + color.r *= ground_energy; + color.g *= ground_energy; + color.b *= ground_energy; + } else { + float c = v_angle / (Math_PI * 0.5); + color = sky_horizon_linear.linear_interpolate(sky_top_linear, Math::ease(1.0 - c, sky_curve)); + color.r *= sky_energy; + color.g *= sky_energy; + color.b *= sky_energy; + + float sun_angle = Math::rad2deg(Math::acos(CLAMP(sun.dot(normal), -1.0, 1.0))); + + if (sun_angle < sun_angle_min) { + color = color.blend(sun_color); + } else if (sun_angle < sun_angle_max) { + + float c2 = (sun_angle - sun_angle_min) / (sun_angle_max - sun_angle_min); + c2 = Math::ease(c2, sun_curve); + + color = color.blend(sun_color).linear_interpolate(color, c2); + } + } + + ptr[j * w + i] = color.to_rgbe9995(); + } + } + } + + Ref image; + image.instance(); + image->create(w, h, false, Image::FORMAT_RGBE9995, imgdata); + + return image; +} + +void ProceduralSky::set_sky_top_color(const Color &p_sky_top) { + + sky_top_color = p_sky_top; + _queue_update(); +} + +Color ProceduralSky::get_sky_top_color() const { + + return sky_top_color; +} + +void ProceduralSky::set_sky_horizon_color(const Color &p_sky_horizon) { + + sky_horizon_color = p_sky_horizon; + _queue_update(); +} +Color ProceduralSky::get_sky_horizon_color() const { + + return sky_horizon_color; +} + +void ProceduralSky::set_sky_curve(float p_curve) { + + sky_curve = p_curve; + _queue_update(); +} +float ProceduralSky::get_sky_curve() const { + + return sky_curve; +} + +void ProceduralSky::set_sky_energy(float p_energy) { + + sky_energy = p_energy; + _queue_update(); +} +float ProceduralSky::get_sky_energy() const { + + return sky_energy; +} + +void ProceduralSky::set_ground_bottom_color(const Color &p_ground_bottom) { + + ground_bottom_color = p_ground_bottom; + _queue_update(); +} +Color ProceduralSky::get_ground_bottom_color() const { + + return ground_bottom_color; +} + +void ProceduralSky::set_ground_horizon_color(const Color &p_ground_horizon) { + + ground_horizon_color = p_ground_horizon; + _queue_update(); +} +Color ProceduralSky::get_ground_horizon_color() const { + + return ground_horizon_color; +} + +void ProceduralSky::set_ground_curve(float p_curve) { + + ground_curve = p_curve; + _queue_update(); +} +float ProceduralSky::get_ground_curve() const { + + return ground_curve; +} + +void ProceduralSky::set_ground_energy(float p_energy) { + + ground_energy = p_energy; + _queue_update(); +} +float ProceduralSky::get_ground_energy() const { + + return ground_energy; +} + +void ProceduralSky::set_sun_color(const Color &p_sun) { + + sun_color = p_sun; + _queue_update(); +} +Color ProceduralSky::get_sun_color() const { + + return sun_color; +} + +void ProceduralSky::set_sun_latitude(float p_angle) { + + sun_latitude = p_angle; + _queue_update(); +} +float ProceduralSky::get_sun_latitude() const { + + return sun_latitude; +} + +void ProceduralSky::set_sun_longitude(float p_angle) { + + sun_longitude = p_angle; + _queue_update(); +} +float ProceduralSky::get_sun_longitude() const { + + return sun_longitude; +} + +void ProceduralSky::set_sun_angle_min(float p_angle) { + + sun_angle_min = p_angle; + _queue_update(); +} +float ProceduralSky::get_sun_angle_min() const { + + return sun_angle_min; +} + +void ProceduralSky::set_sun_angle_max(float p_angle) { + + sun_angle_max = p_angle; + _queue_update(); +} +float ProceduralSky::get_sun_angle_max() const { + + return sun_angle_max; +} + +void ProceduralSky::set_sun_curve(float p_curve) { + + sun_curve = p_curve; + _queue_update(); +} +float ProceduralSky::get_sun_curve() const { + + return sun_curve; +} + +void ProceduralSky::set_sun_energy(float p_energy) { + + sun_energy = p_energy; + _queue_update(); +} +float ProceduralSky::get_sun_energy() const { + + return sun_energy; +} + +void ProceduralSky::set_texture_size(TextureSize p_size) { + ERR_FAIL_INDEX(p_size, TEXTURE_SIZE_MAX); + + texture_size = p_size; + _queue_update(); +} +ProceduralSky::TextureSize ProceduralSky::get_texture_size() const { + return texture_size; +} + +RID ProceduralSky::get_rid() const { + return sky; +} + +void ProceduralSky::_update_sky() { + + bool use_thread = true; + if (first_time) { + use_thread = false; + first_time = false; + } +#ifdef NO_THREADS + use_thread = false; +#endif + if (use_thread) { + + if (!sky_thread) { + sky_thread = Thread::create(_thread_function, this); + regen_queued = false; + } else { + regen_queued = true; + } + + } else { + Ref image = _generate_sky(); + VS::get_singleton()->texture_allocate(texture, image->get_width(), image->get_height(), 0, Image::FORMAT_RGBE9995, VS::TEXTURE_TYPE_2D, VS::TEXTURE_FLAG_FILTER | VS::TEXTURE_FLAG_REPEAT); + VS::get_singleton()->texture_set_data(texture, image); + _radiance_changed(); + } +} + +void ProceduralSky::_queue_update() { + + if (update_queued) + return; + + update_queued = true; + call_deferred("_update_sky"); +} + +void ProceduralSky::_thread_done(const Ref &p_image) { + + VS::get_singleton()->texture_allocate(texture, p_image->get_width(), p_image->get_height(), 0, Image::FORMAT_RGBE9995, VS::TEXTURE_TYPE_2D, VS::TEXTURE_FLAG_FILTER | VS::TEXTURE_FLAG_REPEAT); + VS::get_singleton()->texture_set_data(texture, p_image); + _radiance_changed(); + Thread::wait_to_finish(sky_thread); + memdelete(sky_thread); + sky_thread = NULL; + if (regen_queued) { + sky_thread = Thread::create(_thread_function, this); + regen_queued = false; + } +} + +void ProceduralSky::_thread_function(void *p_ud) { + + ProceduralSky *psky = (ProceduralSky *)p_ud; + psky->call_deferred("_thread_done", psky->_generate_sky()); +} + +void ProceduralSky::_bind_methods() { + + ClassDB::bind_method(D_METHOD("_update_sky"), &ProceduralSky::_update_sky); + + ClassDB::bind_method(D_METHOD("set_sky_top_color", "color"), &ProceduralSky::set_sky_top_color); + ClassDB::bind_method(D_METHOD("get_sky_top_color"), &ProceduralSky::get_sky_top_color); + + ClassDB::bind_method(D_METHOD("set_sky_horizon_color", "color"), &ProceduralSky::set_sky_horizon_color); + ClassDB::bind_method(D_METHOD("get_sky_horizon_color"), &ProceduralSky::get_sky_horizon_color); + + ClassDB::bind_method(D_METHOD("set_sky_curve", "curve"), &ProceduralSky::set_sky_curve); + ClassDB::bind_method(D_METHOD("get_sky_curve"), &ProceduralSky::get_sky_curve); + + ClassDB::bind_method(D_METHOD("set_sky_energy", "energy"), &ProceduralSky::set_sky_energy); + ClassDB::bind_method(D_METHOD("get_sky_energy"), &ProceduralSky::get_sky_energy); + + ClassDB::bind_method(D_METHOD("set_ground_bottom_color", "color"), &ProceduralSky::set_ground_bottom_color); + ClassDB::bind_method(D_METHOD("get_ground_bottom_color"), &ProceduralSky::get_ground_bottom_color); + + ClassDB::bind_method(D_METHOD("set_ground_horizon_color", "color"), &ProceduralSky::set_ground_horizon_color); + ClassDB::bind_method(D_METHOD("get_ground_horizon_color"), &ProceduralSky::get_ground_horizon_color); + + ClassDB::bind_method(D_METHOD("set_ground_curve", "curve"), &ProceduralSky::set_ground_curve); + ClassDB::bind_method(D_METHOD("get_ground_curve"), &ProceduralSky::get_ground_curve); + + ClassDB::bind_method(D_METHOD("set_ground_energy", "energy"), &ProceduralSky::set_ground_energy); + ClassDB::bind_method(D_METHOD("get_ground_energy"), &ProceduralSky::get_ground_energy); + + ClassDB::bind_method(D_METHOD("set_sun_color", "color"), &ProceduralSky::set_sun_color); + ClassDB::bind_method(D_METHOD("get_sun_color"), &ProceduralSky::get_sun_color); + + ClassDB::bind_method(D_METHOD("set_sun_latitude", "degrees"), &ProceduralSky::set_sun_latitude); + ClassDB::bind_method(D_METHOD("get_sun_latitude"), &ProceduralSky::get_sun_latitude); + + ClassDB::bind_method(D_METHOD("set_sun_longitude", "degrees"), &ProceduralSky::set_sun_longitude); + ClassDB::bind_method(D_METHOD("get_sun_longitude"), &ProceduralSky::get_sun_longitude); + + ClassDB::bind_method(D_METHOD("set_sun_angle_min", "degrees"), &ProceduralSky::set_sun_angle_min); + ClassDB::bind_method(D_METHOD("get_sun_angle_min"), &ProceduralSky::get_sun_angle_min); + + ClassDB::bind_method(D_METHOD("set_sun_angle_max", "degrees"), &ProceduralSky::set_sun_angle_max); + ClassDB::bind_method(D_METHOD("get_sun_angle_max"), &ProceduralSky::get_sun_angle_max); + + ClassDB::bind_method(D_METHOD("set_sun_curve", "curve"), &ProceduralSky::set_sun_curve); + ClassDB::bind_method(D_METHOD("get_sun_curve"), &ProceduralSky::get_sun_curve); + + ClassDB::bind_method(D_METHOD("set_sun_energy", "energy"), &ProceduralSky::set_sun_energy); + ClassDB::bind_method(D_METHOD("get_sun_energy"), &ProceduralSky::get_sun_energy); + + ClassDB::bind_method(D_METHOD("set_texture_size", "size"), &ProceduralSky::set_texture_size); + ClassDB::bind_method(D_METHOD("get_texture_size"), &ProceduralSky::get_texture_size); + + ClassDB::bind_method(D_METHOD("_thread_done", "image"), &ProceduralSky::_thread_done); + + ADD_GROUP("Sky", "sky_"); + ADD_PROPERTY(PropertyInfo(Variant::COLOR, "sky_top_color"), "set_sky_top_color", "get_sky_top_color"); + ADD_PROPERTY(PropertyInfo(Variant::COLOR, "sky_horizon_color"), "set_sky_horizon_color", "get_sky_horizon_color"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "sky_curve", PROPERTY_HINT_EXP_EASING), "set_sky_curve", "get_sky_curve"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "sky_energy", PROPERTY_HINT_RANGE, "0,64,0.01"), "set_sky_energy", "get_sky_energy"); + + ADD_GROUP("Ground", "ground_"); + ADD_PROPERTY(PropertyInfo(Variant::COLOR, "ground_bottom_color"), "set_ground_bottom_color", "get_ground_bottom_color"); + ADD_PROPERTY(PropertyInfo(Variant::COLOR, "ground_horizon_color"), "set_ground_horizon_color", "get_ground_horizon_color"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "ground_curve", PROPERTY_HINT_EXP_EASING), "set_ground_curve", "get_ground_curve"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "ground_energy", PROPERTY_HINT_RANGE, "0,64,0.01"), "set_ground_energy", "get_ground_energy"); + + ADD_GROUP("Sun", "sun_"); + ADD_PROPERTY(PropertyInfo(Variant::COLOR, "sun_color"), "set_sun_color", "get_sun_color"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "sun_latitude", PROPERTY_HINT_RANGE, "-180,180,0.01"), "set_sun_latitude", "get_sun_latitude"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "sun_longitude", PROPERTY_HINT_RANGE, "-180,180,0.01"), "set_sun_longitude", "get_sun_longitude"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "sun_angle_min", PROPERTY_HINT_RANGE, "0,360,0.01"), "set_sun_angle_min", "get_sun_angle_min"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "sun_angle_max", PROPERTY_HINT_RANGE, "0,360,0.01"), "set_sun_angle_max", "get_sun_angle_max"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "sun_curve", PROPERTY_HINT_EXP_EASING), "set_sun_curve", "get_sun_curve"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "sun_energy", PROPERTY_HINT_RANGE, "0,64,0.01"), "set_sun_energy", "get_sun_energy"); + + ADD_GROUP("Texture", "texture_"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "texture_size", PROPERTY_HINT_ENUM, "256,512,1024,2048,4096"), "set_texture_size", "get_texture_size"); + + BIND_ENUM_CONSTANT(TEXTURE_SIZE_256); + BIND_ENUM_CONSTANT(TEXTURE_SIZE_512); + BIND_ENUM_CONSTANT(TEXTURE_SIZE_1024); + BIND_ENUM_CONSTANT(TEXTURE_SIZE_2048); + BIND_ENUM_CONSTANT(TEXTURE_SIZE_4096); + BIND_ENUM_CONSTANT(TEXTURE_SIZE_MAX); +} + +ProceduralSky::ProceduralSky() { + + sky = VS::get_singleton()->sky_create(); + texture = VS::get_singleton()->texture_create(); + + update_queued = false; + sky_top_color = Color::hex(0xa5d6f1ff); + sky_horizon_color = Color::hex(0xd6eafaff); + sky_curve = 0.09; + sky_energy = 1; + + ground_bottom_color = Color::hex(0x282f36ff); + ground_horizon_color = Color::hex(0x6c655fff); + ground_curve = 0.02; + ground_energy = 1; + + sun_color = Color(1, 1, 1); + sun_latitude = 35; + sun_longitude = 0; + sun_angle_min = 1; + sun_angle_max = 100; + sun_curve = 0.05; + sun_energy = 16; + + texture_size = TEXTURE_SIZE_1024; + sky_thread = NULL; + regen_queued = false; + first_time = true; + + _queue_update(); +} + +ProceduralSky::~ProceduralSky() { + + if (sky_thread) { + Thread::wait_to_finish(sky_thread); + memdelete(sky_thread); + sky_thread = NULL; + } + VS::get_singleton()->free(sky); + VS::get_singleton()->free(texture); +} diff --git a/scene/resources/sky.h b/scene/resources/sky.h new file mode 100644 index 0000000000..3b410396e0 --- /dev/null +++ b/scene/resources/sky.h @@ -0,0 +1,200 @@ +/*************************************************************************/ +/* sky.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef SKY_H +#define SKY_H + +#include "core/os/thread.h" +#include "scene/resources/texture.h" + +class Sky : public Resource { + GDCLASS(Sky, Resource); + +public: + enum RadianceSize { + RADIANCE_SIZE_32, + RADIANCE_SIZE_64, + RADIANCE_SIZE_128, + RADIANCE_SIZE_256, + RADIANCE_SIZE_512, + RADIANCE_SIZE_1024, + RADIANCE_SIZE_2048, + RADIANCE_SIZE_MAX + }; + +private: + RadianceSize radiance_size; + +protected: + static void _bind_methods(); + virtual void _radiance_changed() = 0; + +public: + void set_radiance_size(RadianceSize p_size); + RadianceSize get_radiance_size() const; + Sky(); +}; + +VARIANT_ENUM_CAST(Sky::RadianceSize) + +class PanoramaSky : public Sky { + GDCLASS(PanoramaSky, Sky); + +private: + RID sky; + Ref panorama; + +protected: + static void _bind_methods(); + virtual void _radiance_changed(); + +public: + void set_panorama(const Ref &p_panorama); + Ref get_panorama() const; + + virtual RID get_rid() const; + + PanoramaSky(); + ~PanoramaSky(); +}; + +class ProceduralSky : public Sky { + GDCLASS(ProceduralSky, Sky); + +public: + enum TextureSize { + TEXTURE_SIZE_256, + TEXTURE_SIZE_512, + TEXTURE_SIZE_1024, + TEXTURE_SIZE_2048, + TEXTURE_SIZE_4096, + TEXTURE_SIZE_MAX + }; + +private: + Thread *sky_thread; + Color sky_top_color; + Color sky_horizon_color; + float sky_curve; + float sky_energy; + + Color ground_bottom_color; + Color ground_horizon_color; + float ground_curve; + float ground_energy; + + Color sun_color; + float sun_latitude; + float sun_longitude; + float sun_angle_min; + float sun_angle_max; + float sun_curve; + float sun_energy; + + TextureSize texture_size; + + RID sky; + RID texture; + + bool update_queued; + bool regen_queued; + + bool first_time; + + void _thread_done(const Ref &p_image); + static void _thread_function(void *p_ud); + +protected: + static void _bind_methods(); + virtual void _radiance_changed(); + + Ref _generate_sky(); + void _update_sky(); + + void _queue_update(); + +public: + void set_sky_top_color(const Color &p_sky_top); + Color get_sky_top_color() const; + + void set_sky_horizon_color(const Color &p_sky_horizon); + Color get_sky_horizon_color() const; + + void set_sky_curve(float p_curve); + float get_sky_curve() const; + + void set_sky_energy(float p_energy); + float get_sky_energy() const; + + void set_ground_bottom_color(const Color &p_ground_bottom); + Color get_ground_bottom_color() const; + + void set_ground_horizon_color(const Color &p_ground_horizon); + Color get_ground_horizon_color() const; + + void set_ground_curve(float p_curve); + float get_ground_curve() const; + + void set_ground_energy(float p_energy); + float get_ground_energy() const; + + void set_sun_color(const Color &p_sun); + Color get_sun_color() const; + + void set_sun_latitude(float p_angle); + float get_sun_latitude() const; + + void set_sun_longitude(float p_angle); + float get_sun_longitude() const; + + void set_sun_angle_min(float p_angle); + float get_sun_angle_min() const; + + void set_sun_angle_max(float p_angle); + float get_sun_angle_max() const; + + void set_sun_curve(float p_curve); + float get_sun_curve() const; + + void set_sun_energy(float p_energy); + float get_sun_energy() const; + + void set_texture_size(TextureSize p_size); + TextureSize get_texture_size() const; + + virtual RID get_rid() const; + + ProceduralSky(); + ~ProceduralSky(); +}; + +VARIANT_ENUM_CAST(ProceduralSky::TextureSize) + +#endif // SKY_H diff --git a/scene/resources/sky_box.cpp b/scene/resources/sky_box.cpp deleted file mode 100644 index d9da85310e..0000000000 --- a/scene/resources/sky_box.cpp +++ /dev/null @@ -1,576 +0,0 @@ -/*************************************************************************/ -/* sky_box.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#include "sky_box.h" -#include "core/io/image_loader.h" - -void Sky::set_radiance_size(RadianceSize p_size) { - ERR_FAIL_INDEX(p_size, RADIANCE_SIZE_MAX); - - radiance_size = p_size; - _radiance_changed(); -} - -Sky::RadianceSize Sky::get_radiance_size() const { - - return radiance_size; -} - -void Sky::_bind_methods() { - - ClassDB::bind_method(D_METHOD("set_radiance_size", "size"), &Sky::set_radiance_size); - ClassDB::bind_method(D_METHOD("get_radiance_size"), &Sky::get_radiance_size); - - ADD_PROPERTY(PropertyInfo(Variant::INT, "radiance_size", PROPERTY_HINT_ENUM, "32,64,128,256,512,1024,2048"), "set_radiance_size", "get_radiance_size"); - - BIND_ENUM_CONSTANT(RADIANCE_SIZE_32); - BIND_ENUM_CONSTANT(RADIANCE_SIZE_64); - BIND_ENUM_CONSTANT(RADIANCE_SIZE_128); - BIND_ENUM_CONSTANT(RADIANCE_SIZE_256); - BIND_ENUM_CONSTANT(RADIANCE_SIZE_512); - BIND_ENUM_CONSTANT(RADIANCE_SIZE_1024); - BIND_ENUM_CONSTANT(RADIANCE_SIZE_2048); - BIND_ENUM_CONSTANT(RADIANCE_SIZE_MAX); -} - -Sky::Sky() { - radiance_size = RADIANCE_SIZE_512; -} - -///////////////////////////////////////// - -void PanoramaSky::_radiance_changed() { - - if (panorama.is_valid()) { - static const int size[RADIANCE_SIZE_MAX] = { - 32, 64, 128, 256, 512, 1024, 2048 - }; - VS::get_singleton()->sky_set_texture(sky, panorama->get_rid(), size[get_radiance_size()]); - } -} - -void PanoramaSky::set_panorama(const Ref &p_panorama) { - - panorama = p_panorama; - - if (panorama.is_valid()) { - - _radiance_changed(); - - } else { - VS::get_singleton()->sky_set_texture(sky, RID(), 0); - } -} - -Ref PanoramaSky::get_panorama() const { - - return panorama; -} - -RID PanoramaSky::get_rid() const { - - return sky; -} - -void PanoramaSky::_bind_methods() { - - ClassDB::bind_method(D_METHOD("set_panorama", "texture"), &PanoramaSky::set_panorama); - ClassDB::bind_method(D_METHOD("get_panorama"), &PanoramaSky::get_panorama); - - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "panorama", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_panorama", "get_panorama"); -} - -PanoramaSky::PanoramaSky() { - - sky = VS::get_singleton()->sky_create(); -} - -PanoramaSky::~PanoramaSky() { - - VS::get_singleton()->free(sky); -} -////////////////////////////////// - -void ProceduralSky::_radiance_changed() { - - if (update_queued) - return; //do nothing yet - - static const int size[RADIANCE_SIZE_MAX] = { - 32, 64, 128, 256, 512, 1024, 2048 - }; - VS::get_singleton()->sky_set_texture(sky, texture, size[get_radiance_size()]); -} - -Ref ProceduralSky::_generate_sky() { - - update_queued = false; - - PoolVector imgdata; - - static const int size[TEXTURE_SIZE_MAX] = { - 256, 512, 1024, 2048, 4096 - }; - - int w = size[texture_size]; - int h = w / 2; - - imgdata.resize(w * h * 4); //RGBE - - { - PoolVector::Write dataw = imgdata.write(); - - uint32_t *ptr = (uint32_t *)dataw.ptr(); - - Color sky_top_linear = sky_top_color.to_linear(); - Color sky_horizon_linear = sky_horizon_color.to_linear(); - - Color ground_bottom_linear = ground_bottom_color.to_linear(); - Color ground_horizon_linear = ground_horizon_color.to_linear(); - - //Color sun_linear = sun_color.to_linear(); - - Vector3 sun(0, 0, -1); - - sun = Basis(Vector3(1, 0, 0), Math::deg2rad(sun_latitude)).xform(sun); - sun = Basis(Vector3(0, 1, 0), Math::deg2rad(sun_longitude)).xform(sun); - - sun.normalize(); - - for (int i = 0; i < w; i++) { - - float u = float(i) / (w - 1); - float phi = u * 2.0 * Math_PI; - - for (int j = 0; j < h; j++) { - - float v = float(j) / (h - 1); - float theta = v * Math_PI; - - Vector3 normal( - Math::sin(phi) * Math::sin(theta) * -1.0, - Math::cos(theta), - Math::cos(phi) * Math::sin(theta) * -1.0); - - normal.normalize(); - - float v_angle = Math::acos(CLAMP(normal.y, -1.0, 1.0)); - - Color color; - - if (normal.y < 0) { - //ground - - float c = (v_angle - (Math_PI * 0.5)) / (Math_PI * 0.5); - color = ground_horizon_linear.linear_interpolate(ground_bottom_linear, Math::ease(c, ground_curve)); - color.r *= ground_energy; - color.g *= ground_energy; - color.b *= ground_energy; - } else { - float c = v_angle / (Math_PI * 0.5); - color = sky_horizon_linear.linear_interpolate(sky_top_linear, Math::ease(1.0 - c, sky_curve)); - color.r *= sky_energy; - color.g *= sky_energy; - color.b *= sky_energy; - - float sun_angle = Math::rad2deg(Math::acos(CLAMP(sun.dot(normal), -1.0, 1.0))); - - if (sun_angle < sun_angle_min) { - color = color.blend(sun_color); - } else if (sun_angle < sun_angle_max) { - - float c2 = (sun_angle - sun_angle_min) / (sun_angle_max - sun_angle_min); - c2 = Math::ease(c2, sun_curve); - - color = color.blend(sun_color).linear_interpolate(color, c2); - } - } - - ptr[j * w + i] = color.to_rgbe9995(); - } - } - } - - Ref image; - image.instance(); - image->create(w, h, false, Image::FORMAT_RGBE9995, imgdata); - - return image; -} - -void ProceduralSky::set_sky_top_color(const Color &p_sky_top) { - - sky_top_color = p_sky_top; - _queue_update(); -} - -Color ProceduralSky::get_sky_top_color() const { - - return sky_top_color; -} - -void ProceduralSky::set_sky_horizon_color(const Color &p_sky_horizon) { - - sky_horizon_color = p_sky_horizon; - _queue_update(); -} -Color ProceduralSky::get_sky_horizon_color() const { - - return sky_horizon_color; -} - -void ProceduralSky::set_sky_curve(float p_curve) { - - sky_curve = p_curve; - _queue_update(); -} -float ProceduralSky::get_sky_curve() const { - - return sky_curve; -} - -void ProceduralSky::set_sky_energy(float p_energy) { - - sky_energy = p_energy; - _queue_update(); -} -float ProceduralSky::get_sky_energy() const { - - return sky_energy; -} - -void ProceduralSky::set_ground_bottom_color(const Color &p_ground_bottom) { - - ground_bottom_color = p_ground_bottom; - _queue_update(); -} -Color ProceduralSky::get_ground_bottom_color() const { - - return ground_bottom_color; -} - -void ProceduralSky::set_ground_horizon_color(const Color &p_ground_horizon) { - - ground_horizon_color = p_ground_horizon; - _queue_update(); -} -Color ProceduralSky::get_ground_horizon_color() const { - - return ground_horizon_color; -} - -void ProceduralSky::set_ground_curve(float p_curve) { - - ground_curve = p_curve; - _queue_update(); -} -float ProceduralSky::get_ground_curve() const { - - return ground_curve; -} - -void ProceduralSky::set_ground_energy(float p_energy) { - - ground_energy = p_energy; - _queue_update(); -} -float ProceduralSky::get_ground_energy() const { - - return ground_energy; -} - -void ProceduralSky::set_sun_color(const Color &p_sun) { - - sun_color = p_sun; - _queue_update(); -} -Color ProceduralSky::get_sun_color() const { - - return sun_color; -} - -void ProceduralSky::set_sun_latitude(float p_angle) { - - sun_latitude = p_angle; - _queue_update(); -} -float ProceduralSky::get_sun_latitude() const { - - return sun_latitude; -} - -void ProceduralSky::set_sun_longitude(float p_angle) { - - sun_longitude = p_angle; - _queue_update(); -} -float ProceduralSky::get_sun_longitude() const { - - return sun_longitude; -} - -void ProceduralSky::set_sun_angle_min(float p_angle) { - - sun_angle_min = p_angle; - _queue_update(); -} -float ProceduralSky::get_sun_angle_min() const { - - return sun_angle_min; -} - -void ProceduralSky::set_sun_angle_max(float p_angle) { - - sun_angle_max = p_angle; - _queue_update(); -} -float ProceduralSky::get_sun_angle_max() const { - - return sun_angle_max; -} - -void ProceduralSky::set_sun_curve(float p_curve) { - - sun_curve = p_curve; - _queue_update(); -} -float ProceduralSky::get_sun_curve() const { - - return sun_curve; -} - -void ProceduralSky::set_sun_energy(float p_energy) { - - sun_energy = p_energy; - _queue_update(); -} -float ProceduralSky::get_sun_energy() const { - - return sun_energy; -} - -void ProceduralSky::set_texture_size(TextureSize p_size) { - ERR_FAIL_INDEX(p_size, TEXTURE_SIZE_MAX); - - texture_size = p_size; - _queue_update(); -} -ProceduralSky::TextureSize ProceduralSky::get_texture_size() const { - return texture_size; -} - -RID ProceduralSky::get_rid() const { - return sky; -} - -void ProceduralSky::_update_sky() { - - bool use_thread = true; - if (first_time) { - use_thread = false; - first_time = false; - } -#ifdef NO_THREADS - use_thread = false; -#endif - if (use_thread) { - - if (!sky_thread) { - sky_thread = Thread::create(_thread_function, this); - regen_queued = false; - } else { - regen_queued = true; - } - - } else { - Ref image = _generate_sky(); - VS::get_singleton()->texture_allocate(texture, image->get_width(), image->get_height(), 0, Image::FORMAT_RGBE9995, VS::TEXTURE_TYPE_2D, VS::TEXTURE_FLAG_FILTER | VS::TEXTURE_FLAG_REPEAT); - VS::get_singleton()->texture_set_data(texture, image); - _radiance_changed(); - } -} - -void ProceduralSky::_queue_update() { - - if (update_queued) - return; - - update_queued = true; - call_deferred("_update_sky"); -} - -void ProceduralSky::_thread_done(const Ref &p_image) { - - VS::get_singleton()->texture_allocate(texture, p_image->get_width(), p_image->get_height(), 0, Image::FORMAT_RGBE9995, VS::TEXTURE_TYPE_2D, VS::TEXTURE_FLAG_FILTER | VS::TEXTURE_FLAG_REPEAT); - VS::get_singleton()->texture_set_data(texture, p_image); - _radiance_changed(); - Thread::wait_to_finish(sky_thread); - memdelete(sky_thread); - sky_thread = NULL; - if (regen_queued) { - sky_thread = Thread::create(_thread_function, this); - regen_queued = false; - } -} - -void ProceduralSky::_thread_function(void *p_ud) { - - ProceduralSky *psky = (ProceduralSky *)p_ud; - psky->call_deferred("_thread_done", psky->_generate_sky()); -} - -void ProceduralSky::_bind_methods() { - - ClassDB::bind_method(D_METHOD("_update_sky"), &ProceduralSky::_update_sky); - - ClassDB::bind_method(D_METHOD("set_sky_top_color", "color"), &ProceduralSky::set_sky_top_color); - ClassDB::bind_method(D_METHOD("get_sky_top_color"), &ProceduralSky::get_sky_top_color); - - ClassDB::bind_method(D_METHOD("set_sky_horizon_color", "color"), &ProceduralSky::set_sky_horizon_color); - ClassDB::bind_method(D_METHOD("get_sky_horizon_color"), &ProceduralSky::get_sky_horizon_color); - - ClassDB::bind_method(D_METHOD("set_sky_curve", "curve"), &ProceduralSky::set_sky_curve); - ClassDB::bind_method(D_METHOD("get_sky_curve"), &ProceduralSky::get_sky_curve); - - ClassDB::bind_method(D_METHOD("set_sky_energy", "energy"), &ProceduralSky::set_sky_energy); - ClassDB::bind_method(D_METHOD("get_sky_energy"), &ProceduralSky::get_sky_energy); - - ClassDB::bind_method(D_METHOD("set_ground_bottom_color", "color"), &ProceduralSky::set_ground_bottom_color); - ClassDB::bind_method(D_METHOD("get_ground_bottom_color"), &ProceduralSky::get_ground_bottom_color); - - ClassDB::bind_method(D_METHOD("set_ground_horizon_color", "color"), &ProceduralSky::set_ground_horizon_color); - ClassDB::bind_method(D_METHOD("get_ground_horizon_color"), &ProceduralSky::get_ground_horizon_color); - - ClassDB::bind_method(D_METHOD("set_ground_curve", "curve"), &ProceduralSky::set_ground_curve); - ClassDB::bind_method(D_METHOD("get_ground_curve"), &ProceduralSky::get_ground_curve); - - ClassDB::bind_method(D_METHOD("set_ground_energy", "energy"), &ProceduralSky::set_ground_energy); - ClassDB::bind_method(D_METHOD("get_ground_energy"), &ProceduralSky::get_ground_energy); - - ClassDB::bind_method(D_METHOD("set_sun_color", "color"), &ProceduralSky::set_sun_color); - ClassDB::bind_method(D_METHOD("get_sun_color"), &ProceduralSky::get_sun_color); - - ClassDB::bind_method(D_METHOD("set_sun_latitude", "degrees"), &ProceduralSky::set_sun_latitude); - ClassDB::bind_method(D_METHOD("get_sun_latitude"), &ProceduralSky::get_sun_latitude); - - ClassDB::bind_method(D_METHOD("set_sun_longitude", "degrees"), &ProceduralSky::set_sun_longitude); - ClassDB::bind_method(D_METHOD("get_sun_longitude"), &ProceduralSky::get_sun_longitude); - - ClassDB::bind_method(D_METHOD("set_sun_angle_min", "degrees"), &ProceduralSky::set_sun_angle_min); - ClassDB::bind_method(D_METHOD("get_sun_angle_min"), &ProceduralSky::get_sun_angle_min); - - ClassDB::bind_method(D_METHOD("set_sun_angle_max", "degrees"), &ProceduralSky::set_sun_angle_max); - ClassDB::bind_method(D_METHOD("get_sun_angle_max"), &ProceduralSky::get_sun_angle_max); - - ClassDB::bind_method(D_METHOD("set_sun_curve", "curve"), &ProceduralSky::set_sun_curve); - ClassDB::bind_method(D_METHOD("get_sun_curve"), &ProceduralSky::get_sun_curve); - - ClassDB::bind_method(D_METHOD("set_sun_energy", "energy"), &ProceduralSky::set_sun_energy); - ClassDB::bind_method(D_METHOD("get_sun_energy"), &ProceduralSky::get_sun_energy); - - ClassDB::bind_method(D_METHOD("set_texture_size", "size"), &ProceduralSky::set_texture_size); - ClassDB::bind_method(D_METHOD("get_texture_size"), &ProceduralSky::get_texture_size); - - ClassDB::bind_method(D_METHOD("_thread_done", "image"), &ProceduralSky::_thread_done); - - ADD_GROUP("Sky", "sky_"); - ADD_PROPERTY(PropertyInfo(Variant::COLOR, "sky_top_color"), "set_sky_top_color", "get_sky_top_color"); - ADD_PROPERTY(PropertyInfo(Variant::COLOR, "sky_horizon_color"), "set_sky_horizon_color", "get_sky_horizon_color"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "sky_curve", PROPERTY_HINT_EXP_EASING), "set_sky_curve", "get_sky_curve"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "sky_energy", PROPERTY_HINT_RANGE, "0,64,0.01"), "set_sky_energy", "get_sky_energy"); - - ADD_GROUP("Ground", "ground_"); - ADD_PROPERTY(PropertyInfo(Variant::COLOR, "ground_bottom_color"), "set_ground_bottom_color", "get_ground_bottom_color"); - ADD_PROPERTY(PropertyInfo(Variant::COLOR, "ground_horizon_color"), "set_ground_horizon_color", "get_ground_horizon_color"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "ground_curve", PROPERTY_HINT_EXP_EASING), "set_ground_curve", "get_ground_curve"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "ground_energy", PROPERTY_HINT_RANGE, "0,64,0.01"), "set_ground_energy", "get_ground_energy"); - - ADD_GROUP("Sun", "sun_"); - ADD_PROPERTY(PropertyInfo(Variant::COLOR, "sun_color"), "set_sun_color", "get_sun_color"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "sun_latitude", PROPERTY_HINT_RANGE, "-180,180,0.01"), "set_sun_latitude", "get_sun_latitude"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "sun_longitude", PROPERTY_HINT_RANGE, "-180,180,0.01"), "set_sun_longitude", "get_sun_longitude"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "sun_angle_min", PROPERTY_HINT_RANGE, "0,360,0.01"), "set_sun_angle_min", "get_sun_angle_min"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "sun_angle_max", PROPERTY_HINT_RANGE, "0,360,0.01"), "set_sun_angle_max", "get_sun_angle_max"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "sun_curve", PROPERTY_HINT_EXP_EASING), "set_sun_curve", "get_sun_curve"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "sun_energy", PROPERTY_HINT_RANGE, "0,64,0.01"), "set_sun_energy", "get_sun_energy"); - - ADD_GROUP("Texture", "texture_"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "texture_size", PROPERTY_HINT_ENUM, "256,512,1024,2048,4096"), "set_texture_size", "get_texture_size"); - - BIND_ENUM_CONSTANT(TEXTURE_SIZE_256); - BIND_ENUM_CONSTANT(TEXTURE_SIZE_512); - BIND_ENUM_CONSTANT(TEXTURE_SIZE_1024); - BIND_ENUM_CONSTANT(TEXTURE_SIZE_2048); - BIND_ENUM_CONSTANT(TEXTURE_SIZE_4096); - BIND_ENUM_CONSTANT(TEXTURE_SIZE_MAX); -} - -ProceduralSky::ProceduralSky() { - - sky = VS::get_singleton()->sky_create(); - texture = VS::get_singleton()->texture_create(); - - update_queued = false; - sky_top_color = Color::hex(0xa5d6f1ff); - sky_horizon_color = Color::hex(0xd6eafaff); - sky_curve = 0.09; - sky_energy = 1; - - ground_bottom_color = Color::hex(0x282f36ff); - ground_horizon_color = Color::hex(0x6c655fff); - ground_curve = 0.02; - ground_energy = 1; - - sun_color = Color(1, 1, 1); - sun_latitude = 35; - sun_longitude = 0; - sun_angle_min = 1; - sun_angle_max = 100; - sun_curve = 0.05; - sun_energy = 16; - - texture_size = TEXTURE_SIZE_1024; - sky_thread = NULL; - regen_queued = false; - first_time = true; - - _queue_update(); -} - -ProceduralSky::~ProceduralSky() { - - if (sky_thread) { - Thread::wait_to_finish(sky_thread); - memdelete(sky_thread); - sky_thread = NULL; - } - VS::get_singleton()->free(sky); - VS::get_singleton()->free(texture); -} diff --git a/scene/resources/sky_box.h b/scene/resources/sky_box.h deleted file mode 100644 index af10803b36..0000000000 --- a/scene/resources/sky_box.h +++ /dev/null @@ -1,199 +0,0 @@ -/*************************************************************************/ -/* sky_box.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#ifndef SKY_BOX_H -#define SKY_BOX_H - -#include "core/os/thread.h" -#include "scene/resources/texture.h" -class Sky : public Resource { - GDCLASS(Sky, Resource); - -public: - enum RadianceSize { - RADIANCE_SIZE_32, - RADIANCE_SIZE_64, - RADIANCE_SIZE_128, - RADIANCE_SIZE_256, - RADIANCE_SIZE_512, - RADIANCE_SIZE_1024, - RADIANCE_SIZE_2048, - RADIANCE_SIZE_MAX - }; - -private: - RadianceSize radiance_size; - -protected: - static void _bind_methods(); - virtual void _radiance_changed() = 0; - -public: - void set_radiance_size(RadianceSize p_size); - RadianceSize get_radiance_size() const; - Sky(); -}; - -VARIANT_ENUM_CAST(Sky::RadianceSize) - -class PanoramaSky : public Sky { - GDCLASS(PanoramaSky, Sky); - -private: - RID sky; - Ref panorama; - -protected: - static void _bind_methods(); - virtual void _radiance_changed(); - -public: - void set_panorama(const Ref &p_panorama); - Ref get_panorama() const; - - virtual RID get_rid() const; - - PanoramaSky(); - ~PanoramaSky(); -}; - -class ProceduralSky : public Sky { - GDCLASS(ProceduralSky, Sky); - -public: - enum TextureSize { - TEXTURE_SIZE_256, - TEXTURE_SIZE_512, - TEXTURE_SIZE_1024, - TEXTURE_SIZE_2048, - TEXTURE_SIZE_4096, - TEXTURE_SIZE_MAX - }; - -private: - Thread *sky_thread; - Color sky_top_color; - Color sky_horizon_color; - float sky_curve; - float sky_energy; - - Color ground_bottom_color; - Color ground_horizon_color; - float ground_curve; - float ground_energy; - - Color sun_color; - float sun_latitude; - float sun_longitude; - float sun_angle_min; - float sun_angle_max; - float sun_curve; - float sun_energy; - - TextureSize texture_size; - - RID sky; - RID texture; - - bool update_queued; - bool regen_queued; - - bool first_time; - - void _thread_done(const Ref &p_image); - static void _thread_function(void *p_ud); - -protected: - static void _bind_methods(); - virtual void _radiance_changed(); - - Ref _generate_sky(); - void _update_sky(); - - void _queue_update(); - -public: - void set_sky_top_color(const Color &p_sky_top); - Color get_sky_top_color() const; - - void set_sky_horizon_color(const Color &p_sky_horizon); - Color get_sky_horizon_color() const; - - void set_sky_curve(float p_curve); - float get_sky_curve() const; - - void set_sky_energy(float p_energy); - float get_sky_energy() const; - - void set_ground_bottom_color(const Color &p_ground_bottom); - Color get_ground_bottom_color() const; - - void set_ground_horizon_color(const Color &p_ground_horizon); - Color get_ground_horizon_color() const; - - void set_ground_curve(float p_curve); - float get_ground_curve() const; - - void set_ground_energy(float p_energy); - float get_ground_energy() const; - - void set_sun_color(const Color &p_sun); - Color get_sun_color() const; - - void set_sun_latitude(float p_angle); - float get_sun_latitude() const; - - void set_sun_longitude(float p_angle); - float get_sun_longitude() const; - - void set_sun_angle_min(float p_angle); - float get_sun_angle_min() const; - - void set_sun_angle_max(float p_angle); - float get_sun_angle_max() const; - - void set_sun_curve(float p_curve); - float get_sun_curve() const; - - void set_sun_energy(float p_energy); - float get_sun_energy() const; - - void set_texture_size(TextureSize p_size); - TextureSize get_texture_size() const; - - virtual RID get_rid() const; - - ProceduralSky(); - ~ProceduralSky(); -}; - -VARIANT_ENUM_CAST(ProceduralSky::TextureSize) - -#endif // SKY_BOX_H diff --git a/scene/resources/texture.cpp b/scene/resources/texture.cpp index ff5900cd3e..b60ec9a80d 100644 --- a/scene/resources/texture.cpp +++ b/scene/resources/texture.cpp @@ -34,7 +34,7 @@ #include "core/io/image_loader.h" #include "core/method_bind_ext.gen.inc" #include "core/os/os.h" -#include "scene/resources/bit_mask.h" +#include "scene/resources/bit_map.h" Size2 Texture::get_size() const { diff --git a/scene/resources/texture.h b/scene/resources/texture.h index 4b5b504510..bfea0f9300 100644 --- a/scene/resources/texture.h +++ b/scene/resources/texture.h @@ -37,8 +37,8 @@ #include "core/os/rw_lock.h" #include "core/os/thread_safe.h" #include "core/resource.h" -#include "scene/resources/color_ramp.h" #include "scene/resources/curve.h" +#include "scene/resources/gradient.h" #include "servers/visual_server.h" /** -- cgit v1.2.3 From fe7e11e008598e4bbbe46cf817af2fac999a5326 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Verschelde?= Date: Tue, 12 Feb 2019 22:28:47 +0100 Subject: Modules: Ensure classes match their header filename Renamed: - `modules/mono/mono_gd/gd_mono_class_member.h` -> `i_mono_class_member.h` - `modules/upnp/upnpdevice.h` -> `upnp_device.h` - `modules/websocket/websocket_multiplayer.h` -> `websocket_multiplayer_peer.h` --- modules/mono/mono_gd/gd_mono_class_member.h | 68 ----- modules/mono/mono_gd/gd_mono_field.h | 2 +- modules/mono/mono_gd/gd_mono_method.h | 2 +- modules/mono/mono_gd/gd_mono_property.h | 2 +- modules/mono/mono_gd/i_mono_class_member.h | 68 +++++ modules/upnp/register_types.cpp | 2 +- modules/upnp/upnp.h | 2 +- modules/upnp/upnp_device.cpp | 199 +++++++++++++ modules/upnp/upnp_device.h | 95 ++++++ modules/upnp/upnpdevice.cpp | 199 ------------- modules/upnp/upnpdevice.h | 95 ------ modules/websocket/websocket_client.h | 2 +- modules/websocket/websocket_multiplayer.cpp | 360 ---------------------- modules/websocket/websocket_multiplayer.h | 109 ------- modules/websocket/websocket_multiplayer_peer.cpp | 361 +++++++++++++++++++++++ modules/websocket/websocket_multiplayer_peer.h | 109 +++++++ modules/websocket/websocket_server.h | 2 +- 17 files changed, 839 insertions(+), 838 deletions(-) delete mode 100644 modules/mono/mono_gd/gd_mono_class_member.h create mode 100644 modules/mono/mono_gd/i_mono_class_member.h create mode 100644 modules/upnp/upnp_device.cpp create mode 100644 modules/upnp/upnp_device.h delete mode 100644 modules/upnp/upnpdevice.cpp delete mode 100644 modules/upnp/upnpdevice.h delete mode 100644 modules/websocket/websocket_multiplayer.cpp delete mode 100644 modules/websocket/websocket_multiplayer.h create mode 100644 modules/websocket/websocket_multiplayer_peer.cpp create mode 100644 modules/websocket/websocket_multiplayer_peer.h diff --git a/modules/mono/mono_gd/gd_mono_class_member.h b/modules/mono/mono_gd/gd_mono_class_member.h deleted file mode 100644 index 3058b18c05..0000000000 --- a/modules/mono/mono_gd/gd_mono_class_member.h +++ /dev/null @@ -1,68 +0,0 @@ -/*************************************************************************/ -/* gd_mono_class_member.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#ifndef GD_MONO_CLASS_MEMBER_H -#define GD_MONO_CLASS_MEMBER_H - -#include "gd_mono_header.h" - -#include - -class IMonoClassMember { -public: - enum Visibility { - PRIVATE, - PROTECTED_AND_INTERNAL, // FAM_AND_ASSEM - INTERNAL, // ASSEMBLY - PROTECTED, // FAMILY - PUBLIC - }; - - enum MemberType { - MEMBER_TYPE_FIELD, - MEMBER_TYPE_PROPERTY, - MEMBER_TYPE_METHOD - }; - - virtual ~IMonoClassMember() {} - - virtual MemberType get_member_type() = 0; - - virtual StringName get_name() = 0; - - virtual bool is_static() = 0; - - virtual Visibility get_visibility() = 0; - - virtual bool has_attribute(GDMonoClass *p_attr_class) = 0; - virtual MonoObject *get_attribute(GDMonoClass *p_attr_class) = 0; -}; - -#endif // GD_MONO_CLASS_MEMBER_H diff --git a/modules/mono/mono_gd/gd_mono_field.h b/modules/mono/mono_gd/gd_mono_field.h index a3244101d8..e348583370 100644 --- a/modules/mono/mono_gd/gd_mono_field.h +++ b/modules/mono/mono_gd/gd_mono_field.h @@ -32,8 +32,8 @@ #define GDMONOFIELD_H #include "gd_mono.h" -#include "gd_mono_class_member.h" #include "gd_mono_header.h" +#include "i_mono_class_member.h" class GDMonoField : public IMonoClassMember { diff --git a/modules/mono/mono_gd/gd_mono_method.h b/modules/mono/mono_gd/gd_mono_method.h index fc035d387c..f74cef438d 100644 --- a/modules/mono/mono_gd/gd_mono_method.h +++ b/modules/mono/mono_gd/gd_mono_method.h @@ -32,8 +32,8 @@ #define GD_MONO_METHOD_H #include "gd_mono.h" -#include "gd_mono_class_member.h" #include "gd_mono_header.h" +#include "i_mono_class_member.h" class GDMonoMethod : public IMonoClassMember { diff --git a/modules/mono/mono_gd/gd_mono_property.h b/modules/mono/mono_gd/gd_mono_property.h index d8a9f69ffb..2700c460b0 100644 --- a/modules/mono/mono_gd/gd_mono_property.h +++ b/modules/mono/mono_gd/gd_mono_property.h @@ -32,8 +32,8 @@ #define GD_MONO_PROPERTY_H #include "gd_mono.h" -#include "gd_mono_class_member.h" #include "gd_mono_header.h" +#include "i_mono_class_member.h" class GDMonoProperty : public IMonoClassMember { diff --git a/modules/mono/mono_gd/i_mono_class_member.h b/modules/mono/mono_gd/i_mono_class_member.h new file mode 100644 index 0000000000..553d9edc72 --- /dev/null +++ b/modules/mono/mono_gd/i_mono_class_member.h @@ -0,0 +1,68 @@ +/*************************************************************************/ +/* i_mono_class_member.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef I_MONO_CLASS_MEMBER_H +#define I_MONO_CLASS_MEMBER_H + +#include "gd_mono_header.h" + +#include + +class IMonoClassMember { +public: + enum Visibility { + PRIVATE, + PROTECTED_AND_INTERNAL, // FAM_AND_ASSEM + INTERNAL, // ASSEMBLY + PROTECTED, // FAMILY + PUBLIC + }; + + enum MemberType { + MEMBER_TYPE_FIELD, + MEMBER_TYPE_PROPERTY, + MEMBER_TYPE_METHOD + }; + + virtual ~IMonoClassMember() {} + + virtual MemberType get_member_type() = 0; + + virtual StringName get_name() = 0; + + virtual bool is_static() = 0; + + virtual Visibility get_visibility() = 0; + + virtual bool has_attribute(GDMonoClass *p_attr_class) = 0; + virtual MonoObject *get_attribute(GDMonoClass *p_attr_class) = 0; +}; + +#endif // I_MONO_CLASS_MEMBER_H diff --git a/modules/upnp/register_types.cpp b/modules/upnp/register_types.cpp index abb73a3605..fbf0ee8b97 100644 --- a/modules/upnp/register_types.cpp +++ b/modules/upnp/register_types.cpp @@ -33,7 +33,7 @@ #include "core/error_macros.h" #include "upnp.h" -#include "upnpdevice.h" +#include "upnp_device.h" void register_upnp_types() { diff --git a/modules/upnp/upnp.h b/modules/upnp/upnp.h index b73908724d..011b6d44b3 100644 --- a/modules/upnp/upnp.h +++ b/modules/upnp/upnp.h @@ -33,7 +33,7 @@ #include "core/reference.h" -#include "upnpdevice.h" +#include "upnp_device.h" #include diff --git a/modules/upnp/upnp_device.cpp b/modules/upnp/upnp_device.cpp new file mode 100644 index 0000000000..4d67e3ddc8 --- /dev/null +++ b/modules/upnp/upnp_device.cpp @@ -0,0 +1,199 @@ +/*************************************************************************/ +/* upnp_device.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "upnp_device.h" + +#include "upnp.h" + +#include + +String UPNPDevice::query_external_address() const { + ERR_FAIL_COND_V(!is_valid_gateway(), ""); + + char addr[16]; + int i = UPNP_GetExternalIPAddress( + igd_control_url.utf8().get_data(), + igd_service_type.utf8().get_data(), + (char *)&addr); + + ERR_FAIL_COND_V(i != UPNPCOMMAND_SUCCESS, ""); + + return String(addr); +} + +int UPNPDevice::add_port_mapping(int port, int port_internal, String desc, String proto, int duration) const { + ERR_FAIL_COND_V(!is_valid_gateway(), UPNP::UPNP_RESULT_INVALID_GATEWAY); + ERR_FAIL_COND_V(port < 1 || port > 65535, UPNP::UPNP_RESULT_INVALID_PORT); + ERR_FAIL_COND_V(port_internal < 0 || port_internal > 65535, UPNP::UPNP_RESULT_INVALID_PORT); // Needs to allow 0 because 0 signifies "use external port as internal port" + ERR_FAIL_COND_V(proto != "UDP" && proto != "TCP", UPNP::UPNP_RESULT_INVALID_PROTOCOL); + ERR_FAIL_COND_V(duration < 0, UPNP::UPNP_RESULT_INVALID_DURATION); + + if (port_internal < 1) { + port_internal = port; + } + + int i = UPNP_AddPortMapping( + igd_control_url.utf8().get_data(), + igd_service_type.utf8().get_data(), + itos(port).utf8().get_data(), + itos(port_internal).utf8().get_data(), + igd_our_addr.utf8().get_data(), + desc.empty() ? 0 : desc.utf8().get_data(), + proto.utf8().get_data(), + NULL, // Remote host, always NULL as IGDs don't support it + duration > 0 ? itos(duration).utf8().get_data() : 0); + + ERR_FAIL_COND_V(i != UPNPCOMMAND_SUCCESS, UPNP::upnp_result(i)); + + return UPNP::UPNP_RESULT_SUCCESS; +} + +int UPNPDevice::delete_port_mapping(int port, String proto) const { + ERR_FAIL_COND_V(port < 1 || port > 65535, UPNP::UPNP_RESULT_INVALID_PORT); + ERR_FAIL_COND_V(proto != "UDP" && proto != "TCP", UPNP::UPNP_RESULT_INVALID_PROTOCOL); + + int i = UPNP_DeletePortMapping( + igd_control_url.utf8().get_data(), + igd_service_type.utf8().get_data(), + itos(port).utf8().get_data(), + proto.utf8().get_data(), + NULL // Remote host, always NULL as IGDs don't support it + ); + + ERR_FAIL_COND_V(i != UPNPCOMMAND_SUCCESS, UPNP::upnp_result(i)); + + return UPNP::UPNP_RESULT_SUCCESS; +} + +void UPNPDevice::set_description_url(const String &url) { + description_url = url; +} + +String UPNPDevice::get_description_url() const { + return description_url; +} + +void UPNPDevice::set_service_type(const String &type) { + service_type = type; +} + +String UPNPDevice::get_service_type() const { + return service_type; +} + +void UPNPDevice::set_igd_control_url(const String &url) { + igd_control_url = url; +} + +String UPNPDevice::get_igd_control_url() const { + return igd_control_url; +} + +void UPNPDevice::set_igd_service_type(const String &type) { + igd_service_type = type; +} + +String UPNPDevice::get_igd_service_type() const { + return igd_service_type; +} + +void UPNPDevice::set_igd_our_addr(const String &addr) { + igd_our_addr = addr; +} + +String UPNPDevice::get_igd_our_addr() const { + return igd_our_addr; +} + +void UPNPDevice::set_igd_status(IGDStatus status) { + igd_status = status; +} + +UPNPDevice::IGDStatus UPNPDevice::get_igd_status() const { + return igd_status; +} + +bool UPNPDevice::is_valid_gateway() const { + return igd_status == IGD_STATUS_OK; +} + +void UPNPDevice::_bind_methods() { + ClassDB::bind_method(D_METHOD("is_valid_gateway"), &UPNPDevice::is_valid_gateway); + ClassDB::bind_method(D_METHOD("query_external_address"), &UPNPDevice::query_external_address); + ClassDB::bind_method(D_METHOD("add_port_mapping", "port", "port_internal", "desc", "proto", "duration"), &UPNPDevice::add_port_mapping, DEFVAL(0), DEFVAL(""), DEFVAL("UDP"), DEFVAL(0)); + ClassDB::bind_method(D_METHOD("delete_port_mapping", "port", "proto"), &UPNPDevice::delete_port_mapping, DEFVAL("UDP")); + + ClassDB::bind_method(D_METHOD("set_description_url", "url"), &UPNPDevice::set_description_url); + ClassDB::bind_method(D_METHOD("get_description_url"), &UPNPDevice::get_description_url); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "description_url"), "set_description_url", "get_description_url"); + + ClassDB::bind_method(D_METHOD("set_service_type", "type"), &UPNPDevice::set_service_type); + ClassDB::bind_method(D_METHOD("get_service_type"), &UPNPDevice::get_service_type); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "service_type"), "set_service_type", "get_service_type"); + + ClassDB::bind_method(D_METHOD("set_igd_control_url", "url"), &UPNPDevice::set_igd_control_url); + ClassDB::bind_method(D_METHOD("get_igd_control_url"), &UPNPDevice::get_igd_control_url); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "igd_control_url"), "set_igd_control_url", "get_igd_control_url"); + + ClassDB::bind_method(D_METHOD("set_igd_service_type", "type"), &UPNPDevice::set_igd_service_type); + ClassDB::bind_method(D_METHOD("get_igd_service_type"), &UPNPDevice::get_igd_service_type); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "igd_service_type"), "set_igd_service_type", "get_igd_service_type"); + + ClassDB::bind_method(D_METHOD("set_igd_our_addr", "addr"), &UPNPDevice::set_igd_our_addr); + ClassDB::bind_method(D_METHOD("get_igd_our_addr"), &UPNPDevice::get_igd_our_addr); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "igd_our_addr"), "set_igd_our_addr", "get_igd_our_addr"); + + ClassDB::bind_method(D_METHOD("set_igd_status", "status"), &UPNPDevice::set_igd_status); + ClassDB::bind_method(D_METHOD("get_igd_status"), &UPNPDevice::get_igd_status); + ADD_PROPERTY(PropertyInfo(Variant::INT, "igd_status", PROPERTY_HINT_ENUM), "set_igd_status", "get_igd_status"); + + BIND_ENUM_CONSTANT(IGD_STATUS_OK); + BIND_ENUM_CONSTANT(IGD_STATUS_HTTP_ERROR); + BIND_ENUM_CONSTANT(IGD_STATUS_HTTP_EMPTY); + BIND_ENUM_CONSTANT(IGD_STATUS_NO_URLS); + BIND_ENUM_CONSTANT(IGD_STATUS_NO_IGD); + BIND_ENUM_CONSTANT(IGD_STATUS_DISCONNECTED); + BIND_ENUM_CONSTANT(IGD_STATUS_UNKNOWN_DEVICE); + BIND_ENUM_CONSTANT(IGD_STATUS_INVALID_CONTROL); + BIND_ENUM_CONSTANT(IGD_STATUS_MALLOC_ERROR); + BIND_ENUM_CONSTANT(IGD_STATUS_UNKNOWN_ERROR); +} + +UPNPDevice::UPNPDevice() { + description_url = ""; + service_type = ""; + igd_control_url = ""; + igd_service_type = ""; + igd_our_addr = ""; + igd_status = IGD_STATUS_UNKNOWN_ERROR; +} + +UPNPDevice::~UPNPDevice() { +} diff --git a/modules/upnp/upnp_device.h b/modules/upnp/upnp_device.h new file mode 100644 index 0000000000..09fce6af89 --- /dev/null +++ b/modules/upnp/upnp_device.h @@ -0,0 +1,95 @@ +/*************************************************************************/ +/* upnp_device.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef GODOT_UPNP_DEVICE_H +#define GODOT_UPNP_DEVICE_H + +#include "core/reference.h" + +class UPNPDevice : public Reference { + + GDCLASS(UPNPDevice, Reference); + +public: + enum IGDStatus { + + IGD_STATUS_OK, + IGD_STATUS_HTTP_ERROR, + IGD_STATUS_HTTP_EMPTY, + IGD_STATUS_NO_URLS, + IGD_STATUS_NO_IGD, + IGD_STATUS_DISCONNECTED, + IGD_STATUS_UNKNOWN_DEVICE, + IGD_STATUS_INVALID_CONTROL, + IGD_STATUS_MALLOC_ERROR, + IGD_STATUS_UNKNOWN_ERROR, + }; + + void set_description_url(const String &url); + String get_description_url() const; + + void set_service_type(const String &type); + String get_service_type() const; + + void set_igd_control_url(const String &url); + String get_igd_control_url() const; + + void set_igd_service_type(const String &type); + String get_igd_service_type() const; + + void set_igd_our_addr(const String &addr); + String get_igd_our_addr() const; + + void set_igd_status(IGDStatus status); + IGDStatus get_igd_status() const; + + bool is_valid_gateway() const; + String query_external_address() const; + int add_port_mapping(int port, int port_internal = 0, String desc = "", String proto = "UDP", int duration = 0) const; + int delete_port_mapping(int port, String proto = "UDP") const; + + UPNPDevice(); + ~UPNPDevice(); + +protected: + static void _bind_methods(); + +private: + String description_url; + String service_type; + String igd_control_url; + String igd_service_type; + String igd_our_addr; + IGDStatus igd_status; +}; + +VARIANT_ENUM_CAST(UPNPDevice::IGDStatus) + +#endif // GODOT_UPNP_DEVICE_H diff --git a/modules/upnp/upnpdevice.cpp b/modules/upnp/upnpdevice.cpp deleted file mode 100644 index 2fb2102df9..0000000000 --- a/modules/upnp/upnpdevice.cpp +++ /dev/null @@ -1,199 +0,0 @@ -/*************************************************************************/ -/* upnpdevice.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#include "upnpdevice.h" - -#include "upnp.h" - -#include - -String UPNPDevice::query_external_address() const { - ERR_FAIL_COND_V(!is_valid_gateway(), ""); - - char addr[16]; - int i = UPNP_GetExternalIPAddress( - igd_control_url.utf8().get_data(), - igd_service_type.utf8().get_data(), - (char *)&addr); - - ERR_FAIL_COND_V(i != UPNPCOMMAND_SUCCESS, ""); - - return String(addr); -} - -int UPNPDevice::add_port_mapping(int port, int port_internal, String desc, String proto, int duration) const { - ERR_FAIL_COND_V(!is_valid_gateway(), UPNP::UPNP_RESULT_INVALID_GATEWAY); - ERR_FAIL_COND_V(port < 1 || port > 65535, UPNP::UPNP_RESULT_INVALID_PORT); - ERR_FAIL_COND_V(port_internal < 0 || port_internal > 65535, UPNP::UPNP_RESULT_INVALID_PORT); // Needs to allow 0 because 0 signifies "use external port as internal port" - ERR_FAIL_COND_V(proto != "UDP" && proto != "TCP", UPNP::UPNP_RESULT_INVALID_PROTOCOL); - ERR_FAIL_COND_V(duration < 0, UPNP::UPNP_RESULT_INVALID_DURATION); - - if (port_internal < 1) { - port_internal = port; - } - - int i = UPNP_AddPortMapping( - igd_control_url.utf8().get_data(), - igd_service_type.utf8().get_data(), - itos(port).utf8().get_data(), - itos(port_internal).utf8().get_data(), - igd_our_addr.utf8().get_data(), - desc.empty() ? 0 : desc.utf8().get_data(), - proto.utf8().get_data(), - NULL, // Remote host, always NULL as IGDs don't support it - duration > 0 ? itos(duration).utf8().get_data() : 0); - - ERR_FAIL_COND_V(i != UPNPCOMMAND_SUCCESS, UPNP::upnp_result(i)); - - return UPNP::UPNP_RESULT_SUCCESS; -} - -int UPNPDevice::delete_port_mapping(int port, String proto) const { - ERR_FAIL_COND_V(port < 1 || port > 65535, UPNP::UPNP_RESULT_INVALID_PORT); - ERR_FAIL_COND_V(proto != "UDP" && proto != "TCP", UPNP::UPNP_RESULT_INVALID_PROTOCOL); - - int i = UPNP_DeletePortMapping( - igd_control_url.utf8().get_data(), - igd_service_type.utf8().get_data(), - itos(port).utf8().get_data(), - proto.utf8().get_data(), - NULL // Remote host, always NULL as IGDs don't support it - ); - - ERR_FAIL_COND_V(i != UPNPCOMMAND_SUCCESS, UPNP::upnp_result(i)); - - return UPNP::UPNP_RESULT_SUCCESS; -} - -void UPNPDevice::set_description_url(const String &url) { - description_url = url; -} - -String UPNPDevice::get_description_url() const { - return description_url; -} - -void UPNPDevice::set_service_type(const String &type) { - service_type = type; -} - -String UPNPDevice::get_service_type() const { - return service_type; -} - -void UPNPDevice::set_igd_control_url(const String &url) { - igd_control_url = url; -} - -String UPNPDevice::get_igd_control_url() const { - return igd_control_url; -} - -void UPNPDevice::set_igd_service_type(const String &type) { - igd_service_type = type; -} - -String UPNPDevice::get_igd_service_type() const { - return igd_service_type; -} - -void UPNPDevice::set_igd_our_addr(const String &addr) { - igd_our_addr = addr; -} - -String UPNPDevice::get_igd_our_addr() const { - return igd_our_addr; -} - -void UPNPDevice::set_igd_status(IGDStatus status) { - igd_status = status; -} - -UPNPDevice::IGDStatus UPNPDevice::get_igd_status() const { - return igd_status; -} - -bool UPNPDevice::is_valid_gateway() const { - return igd_status == IGD_STATUS_OK; -} - -void UPNPDevice::_bind_methods() { - ClassDB::bind_method(D_METHOD("is_valid_gateway"), &UPNPDevice::is_valid_gateway); - ClassDB::bind_method(D_METHOD("query_external_address"), &UPNPDevice::query_external_address); - ClassDB::bind_method(D_METHOD("add_port_mapping", "port", "port_internal", "desc", "proto", "duration"), &UPNPDevice::add_port_mapping, DEFVAL(0), DEFVAL(""), DEFVAL("UDP"), DEFVAL(0)); - ClassDB::bind_method(D_METHOD("delete_port_mapping", "port", "proto"), &UPNPDevice::delete_port_mapping, DEFVAL("UDP")); - - ClassDB::bind_method(D_METHOD("set_description_url", "url"), &UPNPDevice::set_description_url); - ClassDB::bind_method(D_METHOD("get_description_url"), &UPNPDevice::get_description_url); - ADD_PROPERTY(PropertyInfo(Variant::STRING, "description_url"), "set_description_url", "get_description_url"); - - ClassDB::bind_method(D_METHOD("set_service_type", "type"), &UPNPDevice::set_service_type); - ClassDB::bind_method(D_METHOD("get_service_type"), &UPNPDevice::get_service_type); - ADD_PROPERTY(PropertyInfo(Variant::STRING, "service_type"), "set_service_type", "get_service_type"); - - ClassDB::bind_method(D_METHOD("set_igd_control_url", "url"), &UPNPDevice::set_igd_control_url); - ClassDB::bind_method(D_METHOD("get_igd_control_url"), &UPNPDevice::get_igd_control_url); - ADD_PROPERTY(PropertyInfo(Variant::STRING, "igd_control_url"), "set_igd_control_url", "get_igd_control_url"); - - ClassDB::bind_method(D_METHOD("set_igd_service_type", "type"), &UPNPDevice::set_igd_service_type); - ClassDB::bind_method(D_METHOD("get_igd_service_type"), &UPNPDevice::get_igd_service_type); - ADD_PROPERTY(PropertyInfo(Variant::STRING, "igd_service_type"), "set_igd_service_type", "get_igd_service_type"); - - ClassDB::bind_method(D_METHOD("set_igd_our_addr", "addr"), &UPNPDevice::set_igd_our_addr); - ClassDB::bind_method(D_METHOD("get_igd_our_addr"), &UPNPDevice::get_igd_our_addr); - ADD_PROPERTY(PropertyInfo(Variant::STRING, "igd_our_addr"), "set_igd_our_addr", "get_igd_our_addr"); - - ClassDB::bind_method(D_METHOD("set_igd_status", "status"), &UPNPDevice::set_igd_status); - ClassDB::bind_method(D_METHOD("get_igd_status"), &UPNPDevice::get_igd_status); - ADD_PROPERTY(PropertyInfo(Variant::INT, "igd_status", PROPERTY_HINT_ENUM), "set_igd_status", "get_igd_status"); - - BIND_ENUM_CONSTANT(IGD_STATUS_OK); - BIND_ENUM_CONSTANT(IGD_STATUS_HTTP_ERROR); - BIND_ENUM_CONSTANT(IGD_STATUS_HTTP_EMPTY); - BIND_ENUM_CONSTANT(IGD_STATUS_NO_URLS); - BIND_ENUM_CONSTANT(IGD_STATUS_NO_IGD); - BIND_ENUM_CONSTANT(IGD_STATUS_DISCONNECTED); - BIND_ENUM_CONSTANT(IGD_STATUS_UNKNOWN_DEVICE); - BIND_ENUM_CONSTANT(IGD_STATUS_INVALID_CONTROL); - BIND_ENUM_CONSTANT(IGD_STATUS_MALLOC_ERROR); - BIND_ENUM_CONSTANT(IGD_STATUS_UNKNOWN_ERROR); -} - -UPNPDevice::UPNPDevice() { - description_url = ""; - service_type = ""; - igd_control_url = ""; - igd_service_type = ""; - igd_our_addr = ""; - igd_status = IGD_STATUS_UNKNOWN_ERROR; -} - -UPNPDevice::~UPNPDevice() { -} diff --git a/modules/upnp/upnpdevice.h b/modules/upnp/upnpdevice.h deleted file mode 100644 index 20fe5c62fe..0000000000 --- a/modules/upnp/upnpdevice.h +++ /dev/null @@ -1,95 +0,0 @@ -/*************************************************************************/ -/* upnpdevice.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#ifndef GODOT_UPNPDEVICE_H -#define GODOT_UPNPDEVICE_H - -#include "core/reference.h" - -class UPNPDevice : public Reference { - - GDCLASS(UPNPDevice, Reference); - -public: - enum IGDStatus { - - IGD_STATUS_OK, - IGD_STATUS_HTTP_ERROR, - IGD_STATUS_HTTP_EMPTY, - IGD_STATUS_NO_URLS, - IGD_STATUS_NO_IGD, - IGD_STATUS_DISCONNECTED, - IGD_STATUS_UNKNOWN_DEVICE, - IGD_STATUS_INVALID_CONTROL, - IGD_STATUS_MALLOC_ERROR, - IGD_STATUS_UNKNOWN_ERROR, - }; - - void set_description_url(const String &url); - String get_description_url() const; - - void set_service_type(const String &type); - String get_service_type() const; - - void set_igd_control_url(const String &url); - String get_igd_control_url() const; - - void set_igd_service_type(const String &type); - String get_igd_service_type() const; - - void set_igd_our_addr(const String &addr); - String get_igd_our_addr() const; - - void set_igd_status(IGDStatus status); - IGDStatus get_igd_status() const; - - bool is_valid_gateway() const; - String query_external_address() const; - int add_port_mapping(int port, int port_internal = 0, String desc = "", String proto = "UDP", int duration = 0) const; - int delete_port_mapping(int port, String proto = "UDP") const; - - UPNPDevice(); - ~UPNPDevice(); - -protected: - static void _bind_methods(); - -private: - String description_url; - String service_type; - String igd_control_url; - String igd_service_type; - String igd_our_addr; - IGDStatus igd_status; -}; - -VARIANT_ENUM_CAST(UPNPDevice::IGDStatus) - -#endif // GODOT_UPNPDEVICE_H diff --git a/modules/websocket/websocket_client.h b/modules/websocket/websocket_client.h index 32db719435..c464d97c7f 100644 --- a/modules/websocket/websocket_client.h +++ b/modules/websocket/websocket_client.h @@ -32,7 +32,7 @@ #define WEBSOCKET_CLIENT_H #include "core/error_list.h" -#include "websocket_multiplayer.h" +#include "websocket_multiplayer_peer.h" #include "websocket_peer.h" class WebSocketClient : public WebSocketMultiplayerPeer { diff --git a/modules/websocket/websocket_multiplayer.cpp b/modules/websocket/websocket_multiplayer.cpp deleted file mode 100644 index 11caac944b..0000000000 --- a/modules/websocket/websocket_multiplayer.cpp +++ /dev/null @@ -1,360 +0,0 @@ -/*************************************************************************/ -/* websocket_multiplayer.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#include "websocket_multiplayer.h" -#include "core/os/os.h" - -WebSocketMultiplayerPeer::WebSocketMultiplayerPeer() { - - _is_multiplayer = false; - _peer_id = 0; - _target_peer = 0; - _refusing = false; - - _current_packet.source = 0; - _current_packet.destination = 0; - _current_packet.size = 0; - _current_packet.data = NULL; -} - -WebSocketMultiplayerPeer::~WebSocketMultiplayerPeer() { - - _clear(); -} - -int WebSocketMultiplayerPeer::_gen_unique_id() const { - - uint32_t hash = 0; - - while (hash == 0 || hash == 1) { - - hash = hash_djb2_one_32( - (uint32_t)OS::get_singleton()->get_ticks_usec()); - hash = hash_djb2_one_32( - (uint32_t)OS::get_singleton()->get_unix_time(), hash); - hash = hash_djb2_one_32( - (uint32_t)OS::get_singleton()->get_data_path().hash64(), hash); - hash = hash_djb2_one_32( - (uint32_t)((uint64_t)this), hash); //rely on aslr heap - hash = hash_djb2_one_32( - (uint32_t)((uint64_t)&hash), hash); //rely on aslr stack - hash = hash & 0x7FFFFFFF; // make it compatible with unsigned, since negatie id is used for exclusion - } - - return hash; -} -void WebSocketMultiplayerPeer::_clear() { - - _peer_map.clear(); - if (_current_packet.data != NULL) - memfree(_current_packet.data); - - for (List::Element *E = _incoming_packets.front(); E; E = E->next()) { - memfree(E->get().data); - E->get().data = NULL; - } - - _incoming_packets.clear(); -} - -void WebSocketMultiplayerPeer::_bind_methods() { - - ClassDB::bind_method(D_METHOD("get_peer", "peer_id"), &WebSocketMultiplayerPeer::get_peer); - - ADD_SIGNAL(MethodInfo("peer_packet", PropertyInfo(Variant::INT, "peer_source"))); -} - -// -// PacketPeer -// -int WebSocketMultiplayerPeer::get_available_packet_count() const { - - ERR_EXPLAIN("Please use get_peer(ID).get_available_packet_count to get available packet count from peers when not using the MultiplayerAPI."); - ERR_FAIL_COND_V(!_is_multiplayer, ERR_UNCONFIGURED); - - return _incoming_packets.size(); -} - -Error WebSocketMultiplayerPeer::get_packet(const uint8_t **r_buffer, int &r_buffer_size) { - - ERR_EXPLAIN("Please use get_peer(ID).get_packet/var to communicate with peers when not using the MultiplayerAPI."); - ERR_FAIL_COND_V(!_is_multiplayer, ERR_UNCONFIGURED); - - r_buffer_size = 0; - - if (_current_packet.data != NULL) { - memfree(_current_packet.data); - _current_packet.data = NULL; - } - - _current_packet = _incoming_packets.front()->get(); - _incoming_packets.pop_front(); - - *r_buffer = _current_packet.data; - r_buffer_size = _current_packet.size; - - return OK; -} - -Error WebSocketMultiplayerPeer::put_packet(const uint8_t *p_buffer, int p_buffer_size) { - - ERR_EXPLAIN("Please use get_peer(ID).put_packet/var to communicate with peers when not using the MultiplayerAPI."); - ERR_FAIL_COND_V(!_is_multiplayer, ERR_UNCONFIGURED); - - PoolVector buffer = _make_pkt(SYS_NONE, get_unique_id(), _target_peer, p_buffer, p_buffer_size); - - if (is_server()) { - return _server_relay(1, _target_peer, &(buffer.read()[0]), buffer.size()); - } else { - return get_peer(1)->put_packet(&(buffer.read()[0]), buffer.size()); - } -} - -// -// NetworkedMultiplayerPeer -// -void WebSocketMultiplayerPeer::set_transfer_mode(TransferMode p_mode) { - - // Websocket uses TCP, reliable -} - -NetworkedMultiplayerPeer::TransferMode WebSocketMultiplayerPeer::get_transfer_mode() const { - - // Websocket uses TCP, reliable - return TRANSFER_MODE_RELIABLE; -} - -void WebSocketMultiplayerPeer::set_target_peer(int p_target_peer) { - - _target_peer = p_target_peer; -} - -int WebSocketMultiplayerPeer::get_packet_peer() const { - - ERR_EXPLAIN("This function is not available when not using the MultiplayerAPI."); - ERR_FAIL_COND_V(!_is_multiplayer, 1); - ERR_FAIL_COND_V(_incoming_packets.size() == 0, 1); - - return _incoming_packets.front()->get().source; -} - -int WebSocketMultiplayerPeer::get_unique_id() const { - - return _peer_id; -} - -void WebSocketMultiplayerPeer::set_refuse_new_connections(bool p_enable) { - - _refusing = p_enable; -} - -bool WebSocketMultiplayerPeer::is_refusing_new_connections() const { - - return _refusing; -} - -void WebSocketMultiplayerPeer::_send_sys(Ref p_peer, uint8_t p_type, int32_t p_peer_id) { - - ERR_FAIL_COND(!p_peer.is_valid()); - ERR_FAIL_COND(!p_peer->is_connected_to_host()); - - PoolVector message = _make_pkt(p_type, 1, 0, (uint8_t *)&p_peer_id, 4); - p_peer->put_packet(&(message.read()[0]), message.size()); -} - -PoolVector WebSocketMultiplayerPeer::_make_pkt(uint32_t p_type, int32_t p_from, int32_t p_to, const uint8_t *p_data, uint32_t p_data_size) { - - PoolVector out; - out.resize(PROTO_SIZE + p_data_size); - - PoolVector::Write w = out.write(); - copymem(&w[0], &p_type, 1); - copymem(&w[1], &p_from, 4); - copymem(&w[5], &p_to, 4); - copymem(&w[PROTO_SIZE], p_data, p_data_size); - - return out; -} - -void WebSocketMultiplayerPeer::_send_add(int32_t p_peer_id) { - - // First of all, confirm the ID! - _send_sys(get_peer(p_peer_id), SYS_ID, p_peer_id); - - // Then send the server peer (which will trigger connection_succeded in client) - _send_sys(get_peer(p_peer_id), SYS_ADD, 1); - - for (Map >::Element *E = _peer_map.front(); E; E = E->next()) { - uint32_t id = E->key(); - if (p_peer_id == id) - continue; // Skip the newwly added peer (already confirmed) - - // Send new peer to others - _send_sys(get_peer(id), SYS_ADD, p_peer_id); - // Send others to new peer - _send_sys(get_peer(p_peer_id), SYS_ADD, id); - } -} - -void WebSocketMultiplayerPeer::_send_del(int32_t p_peer_id) { - for (Map >::Element *E = _peer_map.front(); E; E = E->next()) { - uint32_t id = E->key(); - if (p_peer_id != id) - _send_sys(get_peer(id), SYS_DEL, p_peer_id); - } -} - -void WebSocketMultiplayerPeer::_store_pkt(int32_t p_source, int32_t p_dest, const uint8_t *p_data, uint32_t p_data_size) { - Packet packet; - packet.data = (uint8_t *)memalloc(p_data_size); - packet.size = p_data_size; - packet.source = p_source; - packet.destination = p_dest; - copymem(packet.data, &p_data[PROTO_SIZE], p_data_size); - _incoming_packets.push_back(packet); - emit_signal("peer_packet", p_source); -} - -Error WebSocketMultiplayerPeer::_server_relay(int32_t p_from, int32_t p_to, const uint8_t *p_buffer, uint32_t p_buffer_size) { - if (p_to == 1) { - - return OK; // Will not send to self - - } else if (p_to == 0) { - - for (Map >::Element *E = _peer_map.front(); E; E = E->next()) { - if (E->key() != p_from) - E->get()->put_packet(p_buffer, p_buffer_size); - } - return OK; // Sent to all but sender - - } else if (p_to < 0) { - - for (Map >::Element *E = _peer_map.front(); E; E = E->next()) { - if (E->key() != p_from && E->key() != -p_to) - E->get()->put_packet(p_buffer, p_buffer_size); - } - return OK; // Sent to all but sender and excluded - - } else { - - ERR_FAIL_COND_V(p_to == p_from, FAILED); - - return get_peer(p_to)->put_packet(p_buffer, p_buffer_size); // Sending to specific peer - } -} - -void WebSocketMultiplayerPeer::_process_multiplayer(Ref p_peer, uint32_t p_peer_id) { - - ERR_FAIL_COND(!p_peer.is_valid()); - - const uint8_t *in_buffer; - int size = 0; - int data_size = 0; - - Error err = p_peer->get_packet(&in_buffer, size); - - ERR_FAIL_COND(err != OK); - ERR_FAIL_COND(size < PROTO_SIZE); - - data_size = size - PROTO_SIZE; - - uint8_t type = 0; - int32_t from = 0; - int32_t to = 0; - copymem(&type, in_buffer, 1); - copymem(&from, &in_buffer[1], 4); - copymem(&to, &in_buffer[5], 4); - - if (is_server()) { // Server can resend - - ERR_FAIL_COND(type != SYS_NONE); // Only server sends sys messages - ERR_FAIL_COND(from != p_peer_id); // Someone is cheating - - _server_relay(from, to, in_buffer, size); // Relay if needed - - if (to == 1) { // This is for the server - - _store_pkt(from, to, in_buffer, data_size); - - } else if (to == 0) { - - // Broadcast, for us too - _store_pkt(from, to, in_buffer, data_size); - - } else if (to < 0) { - - // All but one, for us if not excluded - if (_peer_id != -(int32_t)p_peer_id) - _store_pkt(from, to, in_buffer, data_size); - - } else { - - // Send to specific peer - ERR_FAIL_COND(!_peer_map.has(to)); - get_peer(to)->put_packet(in_buffer, size); - } - - } else { - - if (type == SYS_NONE) { // Payload message - - _store_pkt(from, to, in_buffer, data_size); - return; - } - - // System message - ERR_FAIL_COND(data_size < 4); - int id = 0; - copymem(&id, &in_buffer[PROTO_SIZE], 4); - - switch (type) { - - case SYS_ADD: // Add peer - _peer_map[id] = Ref(); - emit_signal("peer_connected", id); - if (id == 1) // We just connected to the server - emit_signal("connection_succeeded"); - break; - - case SYS_DEL: // Remove peer - _peer_map.erase(id); - emit_signal("peer_disconnected", id); - break; - case SYS_ID: // Helo, server assigned ID - _peer_id = id; - break; - default: - ERR_EXPLAIN("Invalid multiplayer message"); - ERR_FAIL(); - break; - } - } -} diff --git a/modules/websocket/websocket_multiplayer.h b/modules/websocket/websocket_multiplayer.h deleted file mode 100644 index 1aecad97a0..0000000000 --- a/modules/websocket/websocket_multiplayer.h +++ /dev/null @@ -1,109 +0,0 @@ -/*************************************************************************/ -/* websocket_multiplayer.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#ifndef WEBSOCKET_MULTIPLAYER_PEER_H -#define WEBSOCKET_MULTIPLAYER_PEER_H - -#include "core/error_list.h" -#include "core/io/networked_multiplayer_peer.h" -#include "core/list.h" -#include "websocket_peer.h" - -class WebSocketMultiplayerPeer : public NetworkedMultiplayerPeer { - - GDCLASS(WebSocketMultiplayerPeer, NetworkedMultiplayerPeer); - -private: - PoolVector _make_pkt(uint32_t p_type, int32_t p_from, int32_t p_to, const uint8_t *p_data, uint32_t p_data_size); - void _store_pkt(int32_t p_source, int32_t p_dest, const uint8_t *p_data, uint32_t p_data_size); - Error _server_relay(int32_t p_from, int32_t p_to, const uint8_t *p_buffer, uint32_t p_buffer_size); - -protected: - enum { - SYS_NONE = 0, - SYS_ADD = 1, - SYS_DEL = 2, - SYS_ID = 3, - - PROTO_SIZE = 9 - }; - - struct Packet { - int source; - int destination; - uint8_t *data; - uint32_t size; - }; - - List _incoming_packets; - Map > _peer_map; - Packet _current_packet; - - bool _is_multiplayer; - int _target_peer; - int _peer_id; - int _refusing; - - static void _bind_methods(); - - void _send_add(int32_t p_peer_id); - void _send_sys(Ref p_peer, uint8_t p_type, int32_t p_peer_id); - void _send_del(int32_t p_peer_id); - int _gen_unique_id() const; - -public: - /* NetworkedMultiplayerPeer */ - void set_transfer_mode(TransferMode p_mode); - TransferMode get_transfer_mode() const; - void set_target_peer(int p_peer_id); - int get_packet_peer() const; - int get_unique_id() const; - virtual bool is_server() const = 0; - void set_refuse_new_connections(bool p_enable); - bool is_refusing_new_connections() const; - virtual ConnectionStatus get_connection_status() const = 0; - - /* PacketPeer */ - virtual int get_available_packet_count() const; - virtual int get_max_packet_size() const = 0; - virtual Error get_packet(const uint8_t **r_buffer, int &r_buffer_size); - virtual Error put_packet(const uint8_t *p_buffer, int p_buffer_size); - - /* WebSocketPeer */ - virtual Ref get_peer(int p_peer_id) const = 0; - - void _process_multiplayer(Ref p_peer, uint32_t p_peer_id); - void _clear(); - - WebSocketMultiplayerPeer(); - ~WebSocketMultiplayerPeer(); -}; - -#endif // WEBSOCKET_MULTIPLAYER_PEER_H diff --git a/modules/websocket/websocket_multiplayer_peer.cpp b/modules/websocket/websocket_multiplayer_peer.cpp new file mode 100644 index 0000000000..a48738b6a4 --- /dev/null +++ b/modules/websocket/websocket_multiplayer_peer.cpp @@ -0,0 +1,361 @@ +/*************************************************************************/ +/* websocket_multiplayer_peer.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "websocket_multiplayer_peer.h" + +#include "core/os/os.h" + +WebSocketMultiplayerPeer::WebSocketMultiplayerPeer() { + + _is_multiplayer = false; + _peer_id = 0; + _target_peer = 0; + _refusing = false; + + _current_packet.source = 0; + _current_packet.destination = 0; + _current_packet.size = 0; + _current_packet.data = NULL; +} + +WebSocketMultiplayerPeer::~WebSocketMultiplayerPeer() { + + _clear(); +} + +int WebSocketMultiplayerPeer::_gen_unique_id() const { + + uint32_t hash = 0; + + while (hash == 0 || hash == 1) { + + hash = hash_djb2_one_32( + (uint32_t)OS::get_singleton()->get_ticks_usec()); + hash = hash_djb2_one_32( + (uint32_t)OS::get_singleton()->get_unix_time(), hash); + hash = hash_djb2_one_32( + (uint32_t)OS::get_singleton()->get_data_path().hash64(), hash); + hash = hash_djb2_one_32( + (uint32_t)((uint64_t)this), hash); //rely on aslr heap + hash = hash_djb2_one_32( + (uint32_t)((uint64_t)&hash), hash); //rely on aslr stack + hash = hash & 0x7FFFFFFF; // make it compatible with unsigned, since negatie id is used for exclusion + } + + return hash; +} +void WebSocketMultiplayerPeer::_clear() { + + _peer_map.clear(); + if (_current_packet.data != NULL) + memfree(_current_packet.data); + + for (List::Element *E = _incoming_packets.front(); E; E = E->next()) { + memfree(E->get().data); + E->get().data = NULL; + } + + _incoming_packets.clear(); +} + +void WebSocketMultiplayerPeer::_bind_methods() { + + ClassDB::bind_method(D_METHOD("get_peer", "peer_id"), &WebSocketMultiplayerPeer::get_peer); + + ADD_SIGNAL(MethodInfo("peer_packet", PropertyInfo(Variant::INT, "peer_source"))); +} + +// +// PacketPeer +// +int WebSocketMultiplayerPeer::get_available_packet_count() const { + + ERR_EXPLAIN("Please use get_peer(ID).get_available_packet_count to get available packet count from peers when not using the MultiplayerAPI."); + ERR_FAIL_COND_V(!_is_multiplayer, ERR_UNCONFIGURED); + + return _incoming_packets.size(); +} + +Error WebSocketMultiplayerPeer::get_packet(const uint8_t **r_buffer, int &r_buffer_size) { + + ERR_EXPLAIN("Please use get_peer(ID).get_packet/var to communicate with peers when not using the MultiplayerAPI."); + ERR_FAIL_COND_V(!_is_multiplayer, ERR_UNCONFIGURED); + + r_buffer_size = 0; + + if (_current_packet.data != NULL) { + memfree(_current_packet.data); + _current_packet.data = NULL; + } + + _current_packet = _incoming_packets.front()->get(); + _incoming_packets.pop_front(); + + *r_buffer = _current_packet.data; + r_buffer_size = _current_packet.size; + + return OK; +} + +Error WebSocketMultiplayerPeer::put_packet(const uint8_t *p_buffer, int p_buffer_size) { + + ERR_EXPLAIN("Please use get_peer(ID).put_packet/var to communicate with peers when not using the MultiplayerAPI."); + ERR_FAIL_COND_V(!_is_multiplayer, ERR_UNCONFIGURED); + + PoolVector buffer = _make_pkt(SYS_NONE, get_unique_id(), _target_peer, p_buffer, p_buffer_size); + + if (is_server()) { + return _server_relay(1, _target_peer, &(buffer.read()[0]), buffer.size()); + } else { + return get_peer(1)->put_packet(&(buffer.read()[0]), buffer.size()); + } +} + +// +// NetworkedMultiplayerPeer +// +void WebSocketMultiplayerPeer::set_transfer_mode(TransferMode p_mode) { + + // Websocket uses TCP, reliable +} + +NetworkedMultiplayerPeer::TransferMode WebSocketMultiplayerPeer::get_transfer_mode() const { + + // Websocket uses TCP, reliable + return TRANSFER_MODE_RELIABLE; +} + +void WebSocketMultiplayerPeer::set_target_peer(int p_target_peer) { + + _target_peer = p_target_peer; +} + +int WebSocketMultiplayerPeer::get_packet_peer() const { + + ERR_EXPLAIN("This function is not available when not using the MultiplayerAPI."); + ERR_FAIL_COND_V(!_is_multiplayer, 1); + ERR_FAIL_COND_V(_incoming_packets.size() == 0, 1); + + return _incoming_packets.front()->get().source; +} + +int WebSocketMultiplayerPeer::get_unique_id() const { + + return _peer_id; +} + +void WebSocketMultiplayerPeer::set_refuse_new_connections(bool p_enable) { + + _refusing = p_enable; +} + +bool WebSocketMultiplayerPeer::is_refusing_new_connections() const { + + return _refusing; +} + +void WebSocketMultiplayerPeer::_send_sys(Ref p_peer, uint8_t p_type, int32_t p_peer_id) { + + ERR_FAIL_COND(!p_peer.is_valid()); + ERR_FAIL_COND(!p_peer->is_connected_to_host()); + + PoolVector message = _make_pkt(p_type, 1, 0, (uint8_t *)&p_peer_id, 4); + p_peer->put_packet(&(message.read()[0]), message.size()); +} + +PoolVector WebSocketMultiplayerPeer::_make_pkt(uint32_t p_type, int32_t p_from, int32_t p_to, const uint8_t *p_data, uint32_t p_data_size) { + + PoolVector out; + out.resize(PROTO_SIZE + p_data_size); + + PoolVector::Write w = out.write(); + copymem(&w[0], &p_type, 1); + copymem(&w[1], &p_from, 4); + copymem(&w[5], &p_to, 4); + copymem(&w[PROTO_SIZE], p_data, p_data_size); + + return out; +} + +void WebSocketMultiplayerPeer::_send_add(int32_t p_peer_id) { + + // First of all, confirm the ID! + _send_sys(get_peer(p_peer_id), SYS_ID, p_peer_id); + + // Then send the server peer (which will trigger connection_succeded in client) + _send_sys(get_peer(p_peer_id), SYS_ADD, 1); + + for (Map >::Element *E = _peer_map.front(); E; E = E->next()) { + uint32_t id = E->key(); + if (p_peer_id == id) + continue; // Skip the newwly added peer (already confirmed) + + // Send new peer to others + _send_sys(get_peer(id), SYS_ADD, p_peer_id); + // Send others to new peer + _send_sys(get_peer(p_peer_id), SYS_ADD, id); + } +} + +void WebSocketMultiplayerPeer::_send_del(int32_t p_peer_id) { + for (Map >::Element *E = _peer_map.front(); E; E = E->next()) { + uint32_t id = E->key(); + if (p_peer_id != id) + _send_sys(get_peer(id), SYS_DEL, p_peer_id); + } +} + +void WebSocketMultiplayerPeer::_store_pkt(int32_t p_source, int32_t p_dest, const uint8_t *p_data, uint32_t p_data_size) { + Packet packet; + packet.data = (uint8_t *)memalloc(p_data_size); + packet.size = p_data_size; + packet.source = p_source; + packet.destination = p_dest; + copymem(packet.data, &p_data[PROTO_SIZE], p_data_size); + _incoming_packets.push_back(packet); + emit_signal("peer_packet", p_source); +} + +Error WebSocketMultiplayerPeer::_server_relay(int32_t p_from, int32_t p_to, const uint8_t *p_buffer, uint32_t p_buffer_size) { + if (p_to == 1) { + + return OK; // Will not send to self + + } else if (p_to == 0) { + + for (Map >::Element *E = _peer_map.front(); E; E = E->next()) { + if (E->key() != p_from) + E->get()->put_packet(p_buffer, p_buffer_size); + } + return OK; // Sent to all but sender + + } else if (p_to < 0) { + + for (Map >::Element *E = _peer_map.front(); E; E = E->next()) { + if (E->key() != p_from && E->key() != -p_to) + E->get()->put_packet(p_buffer, p_buffer_size); + } + return OK; // Sent to all but sender and excluded + + } else { + + ERR_FAIL_COND_V(p_to == p_from, FAILED); + + return get_peer(p_to)->put_packet(p_buffer, p_buffer_size); // Sending to specific peer + } +} + +void WebSocketMultiplayerPeer::_process_multiplayer(Ref p_peer, uint32_t p_peer_id) { + + ERR_FAIL_COND(!p_peer.is_valid()); + + const uint8_t *in_buffer; + int size = 0; + int data_size = 0; + + Error err = p_peer->get_packet(&in_buffer, size); + + ERR_FAIL_COND(err != OK); + ERR_FAIL_COND(size < PROTO_SIZE); + + data_size = size - PROTO_SIZE; + + uint8_t type = 0; + int32_t from = 0; + int32_t to = 0; + copymem(&type, in_buffer, 1); + copymem(&from, &in_buffer[1], 4); + copymem(&to, &in_buffer[5], 4); + + if (is_server()) { // Server can resend + + ERR_FAIL_COND(type != SYS_NONE); // Only server sends sys messages + ERR_FAIL_COND(from != p_peer_id); // Someone is cheating + + _server_relay(from, to, in_buffer, size); // Relay if needed + + if (to == 1) { // This is for the server + + _store_pkt(from, to, in_buffer, data_size); + + } else if (to == 0) { + + // Broadcast, for us too + _store_pkt(from, to, in_buffer, data_size); + + } else if (to < 0) { + + // All but one, for us if not excluded + if (_peer_id != -(int32_t)p_peer_id) + _store_pkt(from, to, in_buffer, data_size); + + } else { + + // Send to specific peer + ERR_FAIL_COND(!_peer_map.has(to)); + get_peer(to)->put_packet(in_buffer, size); + } + + } else { + + if (type == SYS_NONE) { // Payload message + + _store_pkt(from, to, in_buffer, data_size); + return; + } + + // System message + ERR_FAIL_COND(data_size < 4); + int id = 0; + copymem(&id, &in_buffer[PROTO_SIZE], 4); + + switch (type) { + + case SYS_ADD: // Add peer + _peer_map[id] = Ref(); + emit_signal("peer_connected", id); + if (id == 1) // We just connected to the server + emit_signal("connection_succeeded"); + break; + + case SYS_DEL: // Remove peer + _peer_map.erase(id); + emit_signal("peer_disconnected", id); + break; + case SYS_ID: // Helo, server assigned ID + _peer_id = id; + break; + default: + ERR_EXPLAIN("Invalid multiplayer message"); + ERR_FAIL(); + break; + } + } +} diff --git a/modules/websocket/websocket_multiplayer_peer.h b/modules/websocket/websocket_multiplayer_peer.h new file mode 100644 index 0000000000..b050449ee0 --- /dev/null +++ b/modules/websocket/websocket_multiplayer_peer.h @@ -0,0 +1,109 @@ +/*************************************************************************/ +/* websocket_multiplayer_peer.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef WEBSOCKET_MULTIPLAYER_PEER_H +#define WEBSOCKET_MULTIPLAYER_PEER_H + +#include "core/error_list.h" +#include "core/io/networked_multiplayer_peer.h" +#include "core/list.h" +#include "websocket_peer.h" + +class WebSocketMultiplayerPeer : public NetworkedMultiplayerPeer { + + GDCLASS(WebSocketMultiplayerPeer, NetworkedMultiplayerPeer); + +private: + PoolVector _make_pkt(uint32_t p_type, int32_t p_from, int32_t p_to, const uint8_t *p_data, uint32_t p_data_size); + void _store_pkt(int32_t p_source, int32_t p_dest, const uint8_t *p_data, uint32_t p_data_size); + Error _server_relay(int32_t p_from, int32_t p_to, const uint8_t *p_buffer, uint32_t p_buffer_size); + +protected: + enum { + SYS_NONE = 0, + SYS_ADD = 1, + SYS_DEL = 2, + SYS_ID = 3, + + PROTO_SIZE = 9 + }; + + struct Packet { + int source; + int destination; + uint8_t *data; + uint32_t size; + }; + + List _incoming_packets; + Map > _peer_map; + Packet _current_packet; + + bool _is_multiplayer; + int _target_peer; + int _peer_id; + int _refusing; + + static void _bind_methods(); + + void _send_add(int32_t p_peer_id); + void _send_sys(Ref p_peer, uint8_t p_type, int32_t p_peer_id); + void _send_del(int32_t p_peer_id); + int _gen_unique_id() const; + +public: + /* NetworkedMultiplayerPeer */ + void set_transfer_mode(TransferMode p_mode); + TransferMode get_transfer_mode() const; + void set_target_peer(int p_peer_id); + int get_packet_peer() const; + int get_unique_id() const; + virtual bool is_server() const = 0; + void set_refuse_new_connections(bool p_enable); + bool is_refusing_new_connections() const; + virtual ConnectionStatus get_connection_status() const = 0; + + /* PacketPeer */ + virtual int get_available_packet_count() const; + virtual int get_max_packet_size() const = 0; + virtual Error get_packet(const uint8_t **r_buffer, int &r_buffer_size); + virtual Error put_packet(const uint8_t *p_buffer, int p_buffer_size); + + /* WebSocketPeer */ + virtual Ref get_peer(int p_peer_id) const = 0; + + void _process_multiplayer(Ref p_peer, uint32_t p_peer_id); + void _clear(); + + WebSocketMultiplayerPeer(); + ~WebSocketMultiplayerPeer(); +}; + +#endif // WEBSOCKET_MULTIPLAYER_PEER_H diff --git a/modules/websocket/websocket_server.h b/modules/websocket/websocket_server.h index 3f3e46db5a..7a94c4047b 100644 --- a/modules/websocket/websocket_server.h +++ b/modules/websocket/websocket_server.h @@ -32,7 +32,7 @@ #define WEBSOCKET_H #include "core/reference.h" -#include "websocket_multiplayer.h" +#include "websocket_multiplayer_peer.h" #include "websocket_peer.h" class WebSocketServer : public WebSocketMultiplayerPeer { -- cgit v1.2.3