diff options
45 files changed, 1893 insertions, 57 deletions
diff --git a/.gitignore b/.gitignore index d7b988c464..a7ac2d2fc7 100644 --- a/.gitignore +++ b/.gitignore @@ -84,6 +84,8 @@ platform/android/libs/play_licensing/gen/* *.suo *.user *.sln.docstates +*.sln +*.vcxproj* # Build results [Dd]ebug/ diff --git a/core/list.h b/core/list.h index 6deb150ef6..018abca940 100644 --- a/core/list.h +++ b/core/list.h @@ -518,10 +518,16 @@ public: if (value->prev_ptr) { value->prev_ptr->next_ptr = value->next_ptr; - }; + } + else { + _data->first = value->next_ptr; + } if (value->next_ptr) { value->next_ptr->prev_ptr = value->prev_ptr; - }; + } + else { + _data->last = value->prev_ptr; + } value->next_ptr = where; if (!where) { diff --git a/core/math/vector3.h b/core/math/vector3.h index d27b611379..8a3cca8f33 100644 --- a/core/math/vector3.h +++ b/core/math/vector3.h @@ -40,11 +40,11 @@ struct Vector3 { enum Axis { AXIS_X, AXIS_Y, - AXIS_Z, + AXIS_Z, }; union { - + #ifdef USE_QUAD_VECTORS struct { @@ -52,7 +52,7 @@ struct Vector3 { real_t y; real_t z; real_t _unused; - }; + }; real_t coord[4]; #else @@ -61,18 +61,18 @@ struct Vector3 { real_t y; real_t z; }; - + real_t coord[3]; #endif }; _FORCE_INLINE_ const real_t& operator[](int p_axis) const { - + return coord[p_axis]; } _FORCE_INLINE_ real_t& operator[](int p_axis) { - + return coord[p_axis]; } @@ -84,7 +84,7 @@ struct Vector3 { _FORCE_INLINE_ real_t length() const; _FORCE_INLINE_ real_t length_squared() const; - + _FORCE_INLINE_ void normalize(); _FORCE_INLINE_ Vector3 normalized() const; _FORCE_INLINE_ Vector3 inverse() const; @@ -107,6 +107,8 @@ struct Vector3 { _FORCE_INLINE_ real_t dot(const Vector3& p_b) const; _FORCE_INLINE_ Vector3 abs() const; + _FORCE_INLINE_ Vector3 floor() const; + _FORCE_INLINE_ Vector3 ceil() const; _FORCE_INLINE_ real_t distance_to(const Vector3& p_b) const; _FORCE_INLINE_ real_t distance_squared_to(const Vector3& p_b) const; @@ -172,7 +174,17 @@ real_t Vector3::dot(const Vector3& p_b) const { Vector3 Vector3::abs() const { return Vector3( Math::abs(x), Math::abs(y), Math::abs(z) ); -} +} + +Vector3 Vector3::floor() const { + + return Vector3( Math::floor(x), Math::floor(y), Math::floor(z) ); +} + +Vector3 Vector3::ceil() const { + + return Vector3( Math::ceil(x), Math::ceil(y), Math::ceil(z) ); +} Vector3 Vector3::linear_interpolate(const Vector3& p_b,float p_t) const { @@ -301,7 +313,7 @@ bool Vector3::operator<(const Vector3& p_v) const { return y<p_v.y; } else return x<p_v.x; - + } bool Vector3::operator<=(const Vector3& p_v) const { diff --git a/core/variant_call.cpp b/core/variant_call.cpp index 4cca3420a1..222618ffa0 100644 --- a/core/variant_call.cpp +++ b/core/variant_call.cpp @@ -359,6 +359,8 @@ static void _call_##m_type##_##m_method(Variant& r_ret,Variant& p_self,const Var VCALL_LOCALMEM1R(Vector3, dot); VCALL_LOCALMEM1R(Vector3, cross); VCALL_LOCALMEM0R(Vector3, abs); + VCALL_LOCALMEM0R(Vector3, floor); + VCALL_LOCALMEM0R(Vector3, ceil); VCALL_LOCALMEM1R(Vector3, distance_to); VCALL_LOCALMEM1R(Vector3, distance_squared_to); VCALL_LOCALMEM1R(Vector3, slide); @@ -753,7 +755,7 @@ static void _call_##m_type##_##m_method(Variant& r_ret,Variant& p_self,const Var } static void Matrix32_init2(Variant& r_ret,const Variant** p_args) { - + Matrix32 m(*p_args[0], *p_args[1]); r_ret=m; } @@ -1133,7 +1135,7 @@ void Variant::get_method_list(List<MethodInfo> *p_list) const { if (fd.returns) ret.name="ret"; mi.return_val=ret; -#endif +#endif p_list->push_back(mi); } @@ -1336,6 +1338,8 @@ _VariantCall::addfunc(Variant::m_vtype,Variant::m_ret,_SCS(#m_method),VCALL(m_cl ADDFUNC1(VECTOR3,REAL,Vector3,dot,VECTOR3,"b",varray()); ADDFUNC1(VECTOR3,VECTOR3,Vector3,cross,VECTOR3,"b",varray()); ADDFUNC0(VECTOR3,VECTOR3,Vector3,abs,varray()); + ADDFUNC0(VECTOR3,VECTOR3,Vector3,floor,varray()); + ADDFUNC0(VECTOR3,VECTOR3,Vector3,ceil,varray()); ADDFUNC1(VECTOR3,REAL,Vector3,distance_to,VECTOR3,"b",varray()); ADDFUNC1(VECTOR3,REAL,Vector3,distance_squared_to,VECTOR3,"b",varray()); ADDFUNC1(VECTOR3,VECTOR3,Vector3,slide,VECTOR3,"by",varray()); @@ -1535,10 +1539,10 @@ _VariantCall::addfunc(Variant::m_vtype,Variant::m_ret,_SCS(#m_method),VCALL(m_cl ADDFUNC1(TRANSFORM,NIL,Transform,xform,NIL,"v",varray()); ADDFUNC1(TRANSFORM,NIL,Transform,xform_inv,NIL,"v",varray()); -#ifdef DEBUG_ENABLED +#ifdef DEBUG_ENABLED _VariantCall::type_funcs[Variant::TRANSFORM].functions["xform"].returns=true; _VariantCall::type_funcs[Variant::TRANSFORM].functions["xform_inv"].returns=true; -#endif +#endif ADDFUNC0(INPUT_EVENT,BOOL,InputEvent,is_pressed,varray()); ADDFUNC1(INPUT_EVENT,BOOL,InputEvent,is_action,STRING,"action",varray()); @@ -1635,9 +1639,3 @@ void unregister_variant_methods() { } - - - - - - diff --git a/demos/3d/platformer/enemy.gd b/demos/3d/platformer/enemy.gd index cbbb2fe725..9b2e95a96d 100644 --- a/demos/3d/platformer/enemy.gd +++ b/demos/3d/platformer/enemy.gd @@ -91,4 +91,5 @@ func _ready(): # Initalization here pass - +func _die(): + queue_free() diff --git a/demos/3d/platformer/enemy.scn b/demos/3d/platformer/enemy.scn Binary files differindex 06d725061d..083582a85a 100644 --- a/demos/3d/platformer/enemy.scn +++ b/demos/3d/platformer/enemy.scn diff --git a/drivers/gl_context/glew.c b/drivers/gl_context/glew.c index fc0aa28a72..962e82b657 100644 --- a/drivers/gl_context/glew.c +++ b/drivers/gl_context/glew.c @@ -1,3 +1,7 @@ +#ifdef __HAIKU__ + #undef GLEW_ENABLED +#endif + #ifdef GLEW_ENABLED /* ** The OpenGL Extension Wrangler Library diff --git a/drivers/unix/os_unix.cpp b/drivers/unix/os_unix.cpp index 96f90e6be1..8617061ad4 100644 --- a/drivers/unix/os_unix.cpp +++ b/drivers/unix/os_unix.cpp @@ -243,7 +243,7 @@ OS::Date OS_Unix::get_date(bool utc) const { lt=localtime(&t); Date ret; ret.year=1900+lt->tm_year; - ret.month=(Month)lt->tm_mon; + ret.month=(Month)(lt->tm_mon + 1); ret.day=lt->tm_mday; ret.weekday=(Weekday)lt->tm_wday; ret.dst=lt->tm_isdst; diff --git a/drivers/unix/packet_peer_udp_posix.cpp b/drivers/unix/packet_peer_udp_posix.cpp index 26a0b29228..94b4c35923 100644 --- a/drivers/unix/packet_peer_udp_posix.cpp +++ b/drivers/unix/packet_peer_udp_posix.cpp @@ -13,7 +13,11 @@ #include <stdio.h> #ifndef NO_FCNTL -#include <sys/fcntl.h> + #ifdef __HAIKU__ + #include <fcntl.h> + #else + #include <sys/fcntl.h> + #endif #else #include <sys/ioctl.h> #endif diff --git a/drivers/unix/stream_peer_tcp_posix.cpp b/drivers/unix/stream_peer_tcp_posix.cpp index 2301d8b6c4..5aa3915893 100644 --- a/drivers/unix/stream_peer_tcp_posix.cpp +++ b/drivers/unix/stream_peer_tcp_posix.cpp @@ -39,7 +39,11 @@ #include <netdb.h> #include <sys/types.h> #ifndef NO_FCNTL -#include <sys/fcntl.h> + #ifdef __HAIKU__ + #include <fcntl.h> + #else + #include <sys/fcntl.h> + #endif #else #include <sys/ioctl.h> #endif diff --git a/drivers/unix/tcp_server_posix.cpp b/drivers/unix/tcp_server_posix.cpp index 4f9ee62cde..aaca0fe0d8 100644 --- a/drivers/unix/tcp_server_posix.cpp +++ b/drivers/unix/tcp_server_posix.cpp @@ -41,7 +41,11 @@ #include <netdb.h> #include <sys/types.h> #ifndef NO_FCNTL -#include <sys/fcntl.h> + #ifdef __HAIKU__ + #include <fcntl.h> + #else + #include <sys/fcntl.h> + #endif #else #include <sys/ioctl.h> #endif diff --git a/main/main.cpp b/main/main.cpp index 6f7a56b052..9cd190a0e8 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -1544,9 +1544,9 @@ bool Main::iteration() { OS::get_singleton()->delay_usec( OS::get_singleton()->get_frame_delay()*1000 ); } - int taret_fps = OS::get_singleton()->get_target_fps(); - if (taret_fps>0) { - uint64_t time_step = 1000000L/taret_fps; + int target_fps = OS::get_singleton()->get_target_fps(); + if (target_fps>0) { + uint64_t time_step = 1000000L/target_fps; target_ticks += time_step; uint64_t current_ticks = OS::get_singleton()->get_ticks_usec(); if (current_ticks<target_ticks) OS::get_singleton()->delay_usec(target_ticks-current_ticks); diff --git a/modules/gridmap/grid_map_editor_plugin.cpp b/modules/gridmap/grid_map_editor_plugin.cpp index 3d56b04cac..e4559ca100 100644 --- a/modules/gridmap/grid_map_editor_plugin.cpp +++ b/modules/gridmap/grid_map_editor_plugin.cpp @@ -220,7 +220,9 @@ void GridMapEditor::_menu_option(int p_option) { } break; - + case MENU_OPTION_GRIDMAP_SETTINGS: { + settings_dialog->popup_centered(settings_vbc->get_combined_minimum_size() + Size2(50, 50)); + } break; } } @@ -304,7 +306,7 @@ bool GridMapEditor::do_input_action(Camera* p_camera,const Point2& p_point,bool p.d=edit_floor[edit_axis]*node->get_cell_size(); Vector3 inters; - if (!p.intersects_segment(from,from+normal*500,&inters)) + if (!p.intersects_segment(from, from + normal * settings_pick_distance->get_val(), &inters)) return false; @@ -1249,6 +1251,24 @@ GridMapEditor::GridMapEditor(EditorNode *p_editor) { //options->get_popup()->add_separator(); //options->get_popup()->add_item("Configure",MENU_OPTION_CONFIGURE); + options->get_popup()->add_separator(); + options->get_popup()->add_item("Settings", MENU_OPTION_GRIDMAP_SETTINGS); + + settings_dialog = memnew(ConfirmationDialog); + settings_dialog->set_title("GridMap Settings"); + add_child(settings_dialog); + settings_vbc = memnew(VBoxContainer); + settings_vbc->set_custom_minimum_size(Size2(200, 0)); + settings_dialog->add_child(settings_vbc); + settings_dialog->set_child_rect(settings_vbc); + + settings_pick_distance = memnew(SpinBox); + settings_pick_distance->set_max(10000.0f); + settings_pick_distance->set_min(500.0f); + settings_pick_distance->set_step(1.0f); + settings_pick_distance->set_val(EDITOR_DEF("gridmap_editor/pick_distance", 5000.0)); + settings_vbc->add_margin_child("Pick Distance:", settings_pick_distance); + clip_mode=CLIP_DISABLED; options->get_popup()->connect("item_pressed", this,"_menu_option"); diff --git a/modules/gridmap/grid_map_editor_plugin.h b/modules/gridmap/grid_map_editor_plugin.h index 26fe8f20dc..03b2d4226e 100644 --- a/modules/gridmap/grid_map_editor_plugin.h +++ b/modules/gridmap/grid_map_editor_plugin.h @@ -78,6 +78,9 @@ class GridMapEditor : public VBoxContainer { ToolButton *mode_thumbnail; ToolButton *mode_list; HBoxContainer *spatial_editor_hb; + ConfirmationDialog *settings_dialog; + VBoxContainer *settings_vbc; + SpinBox *settings_pick_distance; struct SetItem { @@ -165,8 +168,8 @@ class GridMapEditor : public VBoxContainer { MENU_OPTION_SELECTION_MAKE_AREA, MENU_OPTION_SELECTION_MAKE_EXTERIOR_CONNECTOR, MENU_OPTION_SELECTION_CLEAR, - MENU_OPTION_REMOVE_AREA - + MENU_OPTION_REMOVE_AREA, + MENU_OPTION_GRIDMAP_SETTINGS }; diff --git a/platform/android/java/src/com/android/godot/payments/PaymentsManager.java b/platform/android/java/src/com/android/godot/payments/PaymentsManager.java index fd1a62738a..5bf86d0b69 100644 --- a/platform/android/java/src/com/android/godot/payments/PaymentsManager.java +++ b/platform/android/java/src/com/android/godot/payments/PaymentsManager.java @@ -47,8 +47,10 @@ public class PaymentsManager { } public PaymentsManager initService(){ + Intent intent = new Intent("com.android.vending.billing.InAppBillingService.BIND"); + intent.setPackage("com.android.vending"); activity.bindService( - new Intent("com.android.vending.billing.InAppBillingService.BIND"), + intent, mServiceConn, Context.BIND_AUTO_CREATE); return this; diff --git a/platform/haiku/SCsub b/platform/haiku/SCsub new file mode 100644 index 0000000000..859095fa5a --- /dev/null +++ b/platform/haiku/SCsub @@ -0,0 +1,16 @@ +Import('env') + +common_haiku = [ + 'os_haiku.cpp', + 'context_gl_haiku.cpp', + 'haiku_application.cpp', + 'haiku_direct_window.cpp', + 'haiku_gl_view.cpp', + 'key_mapping_haiku.cpp', + 'audio_driver_media_kit.cpp' +] + +env.Program( + '#bin/godot', + ['godot_haiku.cpp'] + common_haiku +) diff --git a/platform/haiku/audio_driver_media_kit.cpp b/platform/haiku/audio_driver_media_kit.cpp new file mode 100644 index 0000000000..3fabe4f96f --- /dev/null +++ b/platform/haiku/audio_driver_media_kit.cpp @@ -0,0 +1,143 @@ +/*************************************************************************/ +/* audio_driver_media_kit.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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_driver_media_kit.h" + +#ifdef MEDIA_KIT_ENABLED + +#include "globals.h" + +int32_t* AudioDriverMediaKit::samples_in = NULL; + +Error AudioDriverMediaKit::init() { + active = false; + + mix_rate = 44100; + output_format = OUTPUT_STEREO; + channels = 2; + + int latency = GLOBAL_DEF("audio/output_latency", 25); + buffer_size = nearest_power_of_2(latency * mix_rate / 1000); + samples_in = memnew_arr(int32_t, buffer_size * channels); + + media_raw_audio_format format; + format = media_raw_audio_format::wildcard; + format.frame_rate = mix_rate; + format.channel_count = channels; + format.format = media_raw_audio_format::B_AUDIO_INT; + format.byte_order = B_MEDIA_LITTLE_ENDIAN; + format.buffer_size = buffer_size * sizeof(int32_t) * channels; + + player = new BSoundPlayer( + &format, + "godot_sound_server", + AudioDriverMediaKit::PlayBuffer, + NULL, + this + ); + + if (player->InitCheck() != B_OK) { + fprintf(stderr, "MediaKit ERR: can not create a BSoundPlayer instance\n"); + ERR_FAIL_COND_V(player == NULL, ERR_CANT_OPEN); + } + + mutex = Mutex::create(); + player->Start(); + + return OK; +} + +void AudioDriverMediaKit::PlayBuffer(void* cookie, void* buffer, size_t size, const media_raw_audio_format& format) { + AudioDriverMediaKit* ad = (AudioDriverMediaKit*) cookie; + int32_t* buf = (int32_t*) buffer; + + if (!ad->active) { + for (unsigned int i = 0; i < ad->buffer_size * ad->channels; i++) { + AudioDriverMediaKit::samples_in[i] = 0; + } + } else { + ad->lock(); + ad->audio_server_process(ad->buffer_size, AudioDriverMediaKit::samples_in); + ad->unlock(); + } + + for (unsigned int i = 0; i < ad->buffer_size * ad->channels; i++) { + buf[i] = AudioDriverMediaKit::samples_in[i]; + } +} + +void AudioDriverMediaKit::start() { + active = true; +} + +int AudioDriverMediaKit::get_mix_rate() const { + return mix_rate; +} + +AudioDriverSW::OutputFormat AudioDriverMediaKit::get_output_format() const { + return output_format; +} + +void AudioDriverMediaKit::lock() { + if (!mutex) + return; + + mutex->lock(); +} + +void AudioDriverMediaKit::unlock() { + if (!mutex) + return; + + mutex->unlock(); +} + +void AudioDriverMediaKit::finish() { + if (player) + delete player; + + if (samples_in) { + memdelete_arr(samples_in); + }; + + if (mutex) { + memdelete(mutex); + mutex = NULL; + } +} + +AudioDriverMediaKit::AudioDriverMediaKit() { + mutex = NULL; + player = NULL; +} + +AudioDriverMediaKit::~AudioDriverMediaKit() { + +} + +#endif diff --git a/platform/haiku/audio_driver_media_kit.h b/platform/haiku/audio_driver_media_kit.h new file mode 100644 index 0000000000..a23ec447f1 --- /dev/null +++ b/platform/haiku/audio_driver_media_kit.h @@ -0,0 +1,72 @@ +/*************************************************************************/ +/* audio_driver_media_kit.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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 "servers/audio/audio_server_sw.h" + +#ifdef MEDIA_KIT_ENABLED + +#include "core/os/thread.h" +#include "core/os/mutex.h" + +#include <kernel/image.h> // needed for image_id +#include <SoundPlayer.h> + +class AudioDriverMediaKit : public AudioDriverSW { + Mutex* mutex; + + BSoundPlayer* player; + static int32_t* samples_in; + + static void PlayBuffer(void* cookie, void* buffer, size_t size, const media_raw_audio_format& format); + + unsigned int mix_rate; + OutputFormat output_format; + unsigned int buffer_size; + int channels; + + bool active; + +public: + + const char* get_name() const { + return "MediaKit"; + }; + + virtual Error init(); + virtual void start(); + virtual int get_mix_rate() const; + virtual OutputFormat get_output_format() const; + virtual void lock(); + virtual void unlock(); + virtual void finish(); + + AudioDriverMediaKit(); + ~AudioDriverMediaKit(); +}; + +#endif diff --git a/platform/haiku/context_gl_haiku.cpp b/platform/haiku/context_gl_haiku.cpp new file mode 100644 index 0000000000..21107a52a4 --- /dev/null +++ b/platform/haiku/context_gl_haiku.cpp @@ -0,0 +1,43 @@ +#include "context_gl_haiku.h" + +#if defined(OPENGL_ENABLED) || defined(LEGACYGL_ENABLED) + +ContextGL_Haiku::ContextGL_Haiku(HaikuDirectWindow* p_window) { + window = p_window; + + uint32 type = BGL_RGB | BGL_DOUBLE | BGL_DEPTH; + view = new HaikuGLView(window->Bounds(), type); +} + +ContextGL_Haiku::~ContextGL_Haiku() { + delete view; +} + +Error ContextGL_Haiku::initialize() { + window->AddChild(view); + window->SetHaikuGLView(view); + + return OK; +} + +void ContextGL_Haiku::release_current() { + view->UnlockGL(); +} + +void ContextGL_Haiku::make_current() { + view->LockGL(); +} + +void ContextGL_Haiku::swap_buffers() { + view->SwapBuffers(); +} + +int ContextGL_Haiku::get_window_width() { + return window->Bounds().IntegerWidth(); +} + +int ContextGL_Haiku::get_window_height() { + return window->Bounds().IntegerHeight(); +} + +#endif diff --git a/platform/haiku/context_gl_haiku.h b/platform/haiku/context_gl_haiku.h new file mode 100644 index 0000000000..e37fe14970 --- /dev/null +++ b/platform/haiku/context_gl_haiku.h @@ -0,0 +1,29 @@ +#ifndef CONTEXT_GL_HAIKU_H +#define CONTEXT_GL_HAIKU_H + +#if defined(OPENGL_ENABLED) || defined(LEGACYGL_ENABLED) + +#include "drivers/gl_context/context_gl.h" + +#include "haiku_direct_window.h" +#include "haiku_gl_view.h" + +class ContextGL_Haiku : public ContextGL { +private: + HaikuGLView* view; + HaikuDirectWindow* window; + +public: + ContextGL_Haiku(HaikuDirectWindow* p_window); + ~ContextGL_Haiku(); + + virtual Error initialize(); + virtual void release_current(); + virtual void make_current(); + virtual void swap_buffers(); + virtual int get_window_width(); + virtual int get_window_height(); +}; + +#endif +#endif diff --git a/platform/haiku/detect.py b/platform/haiku/detect.py new file mode 100644 index 0000000000..b5fd550442 --- /dev/null +++ b/platform/haiku/detect.py @@ -0,0 +1,61 @@ +import os +import sys + +def is_active(): + return True + +def get_name(): + return "Haiku" + +def can_build(): + if (os.name != "posix"): + return False + + if (sys.platform == "darwin"): + return False + + return True + +def get_opts(): + return [ + ('debug_release', 'Add debug symbols to release version','no') + ] + +def get_flags(): + return [ + ('builtin_zlib', 'no') + ] + +def configure(env): + is64 = sys.maxsize > 2**32 + + if (env["bits"]=="default"): + if (is64): + env["bits"]="64" + else: + env["bits"]="32" + + env.Append(CPPPATH = ['#platform/haiku']) + + env["CC"] = "gcc" + env["CXX"] = "g++" + + if (env["target"]=="release"): + if (env["debug_release"]=="yes"): + env.Append(CCFLAGS=['-g2']) + else: + env.Append(CCFLAGS=['-O3','-ffast-math']) + elif (env["target"]=="release_debug"): + env.Append(CCFLAGS=['-O2','-ffast-math','-DDEBUG_ENABLED']) + elif (env["target"]=="debug"): + env.Append(CCFLAGS=['-g2', '-Wall','-DDEBUG_ENABLED','-DDEBUG_MEMORY_ENABLED']) + + #env.Append(CCFLAGS=['-DFREETYPE_ENABLED']) + env.Append(CPPFLAGS = ['-DGLEW_ENABLED', '-DOPENGL_ENABLED', '-DMEDIA_KIT_ENABLED']) + env.Append(CPPFLAGS = ['-DUNIX_ENABLED', '-DGLES2_ENABLED', '-DGLES_OVER_GL']) + env.Append(LIBS = ['be', 'game', 'media', 'network', 'bnetapi', 'z', 'GL', 'GLEW']) + + import methods + env.Append(BUILDERS = {'GLSL120' : env.Builder(action = methods.build_legacygl_headers, suffix = 'glsl.h',src_suffix = '.glsl')}) + env.Append(BUILDERS = {'GLSL' : env.Builder(action = methods.build_glsl_headers, suffix = 'glsl.h',src_suffix = '.glsl')}) + env.Append(BUILDERS = {'GLSL120GLES' : env.Builder(action = methods.build_gles2_headers, suffix = 'glsl.h',src_suffix = '.glsl')}) diff --git a/platform/haiku/godot_haiku.cpp b/platform/haiku/godot_haiku.cpp new file mode 100644 index 0000000000..b4e5e50891 --- /dev/null +++ b/platform/haiku/godot_haiku.cpp @@ -0,0 +1,19 @@ +#include "main/main.h" +#include "os_haiku.h" + +int main(int argc, char* argv[]) { + OS_Haiku os; + + Error error = Main::setup(argv[0], argc-1, &argv[1]); + if (error != OK) { + return 255; + } + + if (Main::start()) { + os.run(); + } + + Main::cleanup(); + + return os.get_exit_code(); +} diff --git a/platform/haiku/haiku_application.cpp b/platform/haiku/haiku_application.cpp new file mode 100644 index 0000000000..ea20d73729 --- /dev/null +++ b/platform/haiku/haiku_application.cpp @@ -0,0 +1,7 @@ +#include "haiku_application.h" + +HaikuApplication::HaikuApplication() + : BApplication("application/x-vnd.Godot") +{ + +} diff --git a/platform/haiku/haiku_application.h b/platform/haiku/haiku_application.h new file mode 100644 index 0000000000..a64b01c94d --- /dev/null +++ b/platform/haiku/haiku_application.h @@ -0,0 +1,13 @@ +#ifndef HAIKU_APPLICATION_H +#define HAIKU_APPLICATION_H + +#include <kernel/image.h> // needed for image_id +#include <Application.h> + +class HaikuApplication : public BApplication +{ +public: + HaikuApplication(); +}; + +#endif diff --git a/platform/haiku/haiku_direct_window.cpp b/platform/haiku/haiku_direct_window.cpp new file mode 100644 index 0000000000..3914ee272a --- /dev/null +++ b/platform/haiku/haiku_direct_window.cpp @@ -0,0 +1,344 @@ +#include <UnicodeChar.h> + +#include "main/main.h" +#include "os/keyboard.h" +#include "haiku_direct_window.h" +#include "key_mapping_haiku.h" + +HaikuDirectWindow::HaikuDirectWindow(BRect p_frame) + : BDirectWindow(p_frame, "Godot", B_TITLED_WINDOW, B_QUIT_ON_WINDOW_CLOSE) +{ + last_mouse_pos_valid = false; + last_buttons_state = 0; + last_button_mask = 0; + last_key_modifier_state = 0; +} + + +HaikuDirectWindow::~HaikuDirectWindow() { + if (update_runner) { + delete update_runner; + } +} + +void HaikuDirectWindow::SetHaikuGLView(HaikuGLView* p_view) { + view = p_view; +} + +void HaikuDirectWindow::StartMessageRunner() { + update_runner = new BMessageRunner(BMessenger(this), + new BMessage(REDRAW_MSG), 1000000/30 /* 30 fps */); +} + +void HaikuDirectWindow::StopMessageRunner() { + delete update_runner; +} + +void HaikuDirectWindow::SetInput(InputDefault* p_input) { + input = p_input; +} + +void HaikuDirectWindow::SetMainLoop(MainLoop* p_main_loop) { + main_loop = p_main_loop; +} + +bool HaikuDirectWindow::QuitRequested() { + main_loop->notification(MainLoop::NOTIFICATION_WM_QUIT_REQUEST); + return false; +} + +void HaikuDirectWindow::DirectConnected(direct_buffer_info* info) { + view->DirectConnected(info); + view->EnableDirectMode(true); +} + +void HaikuDirectWindow::MessageReceived(BMessage* message) { + switch (message->what) { + case REDRAW_MSG: + if (Main::iteration() == true) { + view->EnableDirectMode(false); + Quit(); + } + break; + + default: + BDirectWindow::MessageReceived(message); + } +} + +void HaikuDirectWindow::DispatchMessage(BMessage* message, BHandler* handler) { + switch (message->what) { + case B_MOUSE_DOWN: + case B_MOUSE_UP: + HandleMouseButton(message); + break; + + case B_MOUSE_MOVED: + HandleMouseMoved(message); + break; + + case B_MOUSE_WHEEL_CHANGED: + HandleMouseWheelChanged(message); + break; + + case B_KEY_DOWN: + case B_KEY_UP: + HandleKeyboardEvent(message); + break; + + case B_MODIFIERS_CHANGED: + HandleKeyboardModifierEvent(message); + break; + + case B_WINDOW_RESIZED: + HandleWindowResized(message); + break; + + case LOCKGL_MSG: + view->LockGL(); + break; + + case UNLOCKGL_MSG: + view->UnlockGL(); + break; + + default: + BDirectWindow::DispatchMessage(message, handler); + } +} + +void HaikuDirectWindow::HandleMouseButton(BMessage* message) { + BPoint where; + if (message->FindPoint("where", &where) != B_OK) { + return; + } + + uint32 modifiers = message->FindInt32("modifiers"); + uint32 buttons = message->FindInt32("buttons"); + uint32 button = buttons ^ last_buttons_state; + last_buttons_state = buttons; + + // TODO: implement the mouse_mode checks + //if (mouse_mode == MOUSE_MODE_CAPTURED) { + // event.xbutton.x=last_mouse_pos.x; + // event.xbutton.y=last_mouse_pos.y; + //} + + InputEvent mouse_event; + mouse_event.ID = ++event_id; + mouse_event.type = InputEvent::MOUSE_BUTTON; + mouse_event.device = 0; + + mouse_event.mouse_button.mod = GetKeyModifierState(modifiers); + mouse_event.mouse_button.button_mask = GetMouseButtonState(buttons); + mouse_event.mouse_button.x = where.x; + mouse_event.mouse_button.y = where.y; + mouse_event.mouse_button.global_x = where.x; + mouse_event.mouse_button.global_y = where.y; + + switch (button) { + default: + case B_PRIMARY_MOUSE_BUTTON: + mouse_event.mouse_button.button_index = 1; + break; + + case B_SECONDARY_MOUSE_BUTTON: + mouse_event.mouse_button.button_index = 2; + break; + + case B_TERTIARY_MOUSE_BUTTON: + mouse_event.mouse_button.button_index = 3; + break; + } + + mouse_event.mouse_button.pressed = (message->what == B_MOUSE_DOWN); + + if (message->what == B_MOUSE_DOWN && mouse_event.mouse_button.button_index == 1) { + int32 clicks = message->FindInt32("clicks"); + + if (clicks > 1) { + mouse_event.mouse_button.doubleclick=true; + } + } + + input->parse_input_event(mouse_event); +} + +void HaikuDirectWindow::HandleMouseMoved(BMessage* message) { + BPoint where; + if (message->FindPoint("where", &where) != B_OK) { + return; + } + + Point2i pos(where.x, where.y); + uint32 modifiers = message->FindInt32("modifiers"); + uint32 buttons = message->FindInt32("buttons"); + + if (!last_mouse_pos_valid) { + last_mouse_position = pos; + last_mouse_pos_valid = true; + } + + Point2i rel = pos - last_mouse_position; + + InputEvent motion_event; + motion_event.ID = ++event_id; + motion_event.type = InputEvent::MOUSE_MOTION; + motion_event.device = 0; + + motion_event.mouse_motion.mod = GetKeyModifierState(modifiers); + motion_event.mouse_motion.button_mask = GetMouseButtonState(buttons); + motion_event.mouse_motion.x = pos.x; + motion_event.mouse_motion.y = pos.y; + input->set_mouse_pos(pos); + motion_event.mouse_motion.global_x = pos.x; + motion_event.mouse_motion.global_y = pos.y; + motion_event.mouse_motion.speed_x = input->get_mouse_speed().x; + motion_event.mouse_motion.speed_y = input->get_mouse_speed().y; + + motion_event.mouse_motion.relative_x = rel.x; + motion_event.mouse_motion.relative_y = rel.y; + + last_mouse_position = pos; + + input->parse_input_event(motion_event); +} + +void HaikuDirectWindow::HandleMouseWheelChanged(BMessage* message) { + float wheel_delta_y = 0; + if (message->FindFloat("be:wheel_delta_y", &wheel_delta_y) != B_OK) { + return; + } + + InputEvent mouse_event; + mouse_event.ID = ++event_id; + mouse_event.type = InputEvent::MOUSE_BUTTON; + mouse_event.device = 0; + + mouse_event.mouse_button.button_index = wheel_delta_y < 0 ? 4 : 5; + mouse_event.mouse_button.mod = GetKeyModifierState(last_key_modifier_state); + mouse_event.mouse_button.button_mask = last_button_mask; + mouse_event.mouse_button.x = last_mouse_position.x; + mouse_event.mouse_button.y = last_mouse_position.y; + mouse_event.mouse_button.global_x = last_mouse_position.x; + mouse_event.mouse_button.global_y = last_mouse_position.y; + + mouse_event.mouse_button.pressed = true; + input->parse_input_event(mouse_event); + + mouse_event.ID = ++event_id; + mouse_event.mouse_button.pressed = false; + input->parse_input_event(mouse_event); +} + +void HaikuDirectWindow::HandleKeyboardEvent(BMessage* message) { + int32 raw_char = 0; + int32 key = 0; + int32 modifiers = 0; + + if (message->FindInt32("raw_char", &raw_char) != B_OK) { + return; + } + + if (message->FindInt32("key", &key) != B_OK) { + return; + } + + if (message->FindInt32("modifiers", &modifiers) != B_OK) { + return; + } + + InputEvent event; + event.ID = ++event_id; + event.type = InputEvent::KEY; + event.device = 0; + event.key.mod = GetKeyModifierState(modifiers); + event.key.pressed = (message->what == B_KEY_DOWN); + event.key.scancode = KeyMappingHaiku::get_keysym(raw_char, key); + event.key.echo = message->HasInt32("be:key_repeat"); + event.key.unicode = 0; + + const char* bytes = NULL; + if (message->FindString("bytes", &bytes) == B_OK) { + event.key.unicode = BUnicodeChar::FromUTF8(&bytes); + } + + //make it consistent accross platforms. + if (event.key.scancode==KEY_BACKTAB) { + event.key.scancode=KEY_TAB; + event.key.mod.shift=true; + } + + input->parse_input_event(event); +} + +void HaikuDirectWindow::HandleKeyboardModifierEvent(BMessage* message) { + int32 old_modifiers = 0; + int32 modifiers = 0; + + if (message->FindInt32("be:old_modifiers", &old_modifiers) != B_OK) { + return; + } + + if (message->FindInt32("modifiers", &modifiers) != B_OK) { + return; + } + + int32 key = old_modifiers ^ modifiers; + + InputEvent event; + event.ID = ++event_id; + event.type = InputEvent::KEY; + event.device = 0; + event.key.mod = GetKeyModifierState(modifiers); + event.key.pressed = ((modifiers & key) != 0); + event.key.scancode = KeyMappingHaiku::get_modifier_keysym(key); + event.key.echo = false; + event.key.unicode = 0; + + input->parse_input_event(event); +} + +void HaikuDirectWindow::HandleWindowResized(BMessage* message) { + int32 width = 0; + int32 height = 0; + + if ((message->FindInt32("width", &width) != B_OK) || (message->FindInt32("height", &height) != B_OK)) { + return; + } + + current_video_mode->width = width; + current_video_mode->height = height; +} + +inline InputModifierState HaikuDirectWindow::GetKeyModifierState(uint32 p_state) { + last_key_modifier_state = p_state; + InputModifierState state; + + state.shift = (p_state & B_SHIFT_KEY) != 0; + state.control = (p_state & B_CONTROL_KEY) != 0; + state.alt = (p_state & B_OPTION_KEY) != 0; + state.meta = (p_state & B_COMMAND_KEY) != 0; + + return state; +} + +inline int HaikuDirectWindow::GetMouseButtonState(uint32 p_state) { + int state = 0; + + if (p_state & B_PRIMARY_MOUSE_BUTTON) { + state |= 1 << 0; + } + + if (p_state & B_SECONDARY_MOUSE_BUTTON) { + state |= 1 << 1; + } + + if (p_state & B_TERTIARY_MOUSE_BUTTON) { + state |= 1 << 2; + } + + last_button_mask = state; + + return state; +} diff --git a/platform/haiku/haiku_direct_window.h b/platform/haiku/haiku_direct_window.h new file mode 100644 index 0000000000..f0398df505 --- /dev/null +++ b/platform/haiku/haiku_direct_window.h @@ -0,0 +1,60 @@ +#ifndef HAIKU_DIRECT_WINDOW_H +#define HAIKU_DIRECT_WINDOW_H + +#include <kernel/image.h> // needed for image_id +#include <DirectWindow.h> + +#include "core/os/os.h" +#include "main/input_default.h" + +#include "haiku_gl_view.h" + +#define REDRAW_MSG 'rdrw' +#define LOCKGL_MSG 'glck' +#define UNLOCKGL_MSG 'ulck' + +class HaikuDirectWindow : public BDirectWindow +{ +private: + unsigned int event_id; + Point2i last_mouse_position; + bool last_mouse_pos_valid; + uint32 last_buttons_state; + uint32 last_key_modifier_state; + int last_button_mask; + OS::VideoMode* current_video_mode; + + MainLoop* main_loop; + InputDefault* input; + HaikuGLView* view; + BMessageRunner* update_runner; + + void HandleMouseButton(BMessage* message); + void HandleMouseMoved(BMessage* message); + void HandleMouseWheelChanged(BMessage* message); + void HandleWindowResized(BMessage* message); + void HandleKeyboardEvent(BMessage* message); + void HandleKeyboardModifierEvent(BMessage* message); + inline InputModifierState GetKeyModifierState(uint32 p_state); + inline int GetMouseButtonState(uint32 p_state); + +public: + HaikuDirectWindow(BRect p_frame); + ~HaikuDirectWindow(); + + void SetHaikuGLView(HaikuGLView* p_view); + void StartMessageRunner(); + void StopMessageRunner(); + void SetInput(InputDefault* p_input); + void SetMainLoop(MainLoop* p_main_loop); + inline void SetVideoMode(OS::VideoMode* video_mode) { current_video_mode = video_mode; }; + virtual bool QuitRequested(); + virtual void DirectConnected(direct_buffer_info* info); + virtual void MessageReceived(BMessage* message); + virtual void DispatchMessage(BMessage* message, BHandler* handler); + + inline Point2i GetLastMousePosition() { return last_mouse_position; }; + inline int GetLastButtonMask() { return last_button_mask; }; +}; + +#endif diff --git a/platform/haiku/haiku_gl_view.cpp b/platform/haiku/haiku_gl_view.cpp new file mode 100644 index 0000000000..481d6098a7 --- /dev/null +++ b/platform/haiku/haiku_gl_view.cpp @@ -0,0 +1,18 @@ +#include "main/main.h" +#include "haiku_gl_view.h" + +HaikuGLView::HaikuGLView(BRect frame, uint32 type) + : BGLView(frame, "GodotGLView", B_FOLLOW_ALL_SIDES, 0, type) +{ +} + +void HaikuGLView::AttachedToWindow(void) { + LockGL(); + BGLView::AttachedToWindow(); + UnlockGL(); + MakeFocus(); +} + +void HaikuGLView::Draw(BRect updateRect) { + Main::force_redraw(); +} diff --git a/platform/haiku/haiku_gl_view.h b/platform/haiku/haiku_gl_view.h new file mode 100644 index 0000000000..f44b6d4325 --- /dev/null +++ b/platform/haiku/haiku_gl_view.h @@ -0,0 +1,15 @@ +#ifndef HAIKU_GL_VIEW_H +#define HAIKU_GL_VIEW_H + +#include <kernel/image.h> // needed for image_id +#include <GLView.h> + +class HaikuGLView : public BGLView +{ +public: + HaikuGLView(BRect frame, uint32 type); + virtual void AttachedToWindow(void); + virtual void Draw(BRect updateRect); +}; + +#endif diff --git a/platform/haiku/key_mapping_haiku.cpp b/platform/haiku/key_mapping_haiku.cpp new file mode 100644 index 0000000000..d7bde9a727 --- /dev/null +++ b/platform/haiku/key_mapping_haiku.cpp @@ -0,0 +1,193 @@ +#include <InterfaceDefs.h> + +#include "key_mapping_haiku.h" +#include "os/keyboard.h" + +struct _HaikuTranslatePair { + unsigned int keysym; + int32 keycode; +}; + +static _HaikuTranslatePair _mod_to_keycode[] = { + { KEY_SHIFT, B_SHIFT_KEY }, + { KEY_ALT, B_COMMAND_KEY }, + { KEY_CONTROL, B_CONTROL_KEY }, + { KEY_CAPSLOCK, B_CAPS_LOCK }, + { KEY_SCROLLLOCK, B_SCROLL_LOCK }, + { KEY_NUMLOCK, B_NUM_LOCK }, + { KEY_SUPER_L, B_OPTION_KEY }, + { KEY_MENU, B_MENU_KEY }, + { KEY_SHIFT, B_LEFT_SHIFT_KEY }, + { KEY_SHIFT, B_RIGHT_SHIFT_KEY }, + { KEY_ALT, B_LEFT_COMMAND_KEY }, + { KEY_ALT, B_RIGHT_COMMAND_KEY }, + { KEY_CONTROL, B_LEFT_CONTROL_KEY }, + { KEY_CONTROL, B_RIGHT_CONTROL_KEY }, + { KEY_SUPER_L, B_LEFT_OPTION_KEY }, + { KEY_SUPER_R, B_RIGHT_OPTION_KEY }, + { KEY_UNKNOWN, 0 } +}; + +static _HaikuTranslatePair _fn_to_keycode[] = { + { KEY_F1, B_F1_KEY }, + { KEY_F2, B_F2_KEY }, + { KEY_F3, B_F3_KEY }, + { KEY_F4, B_F4_KEY }, + { KEY_F5, B_F5_KEY }, + { KEY_F6, B_F6_KEY }, + { KEY_F7, B_F7_KEY }, + { KEY_F8, B_F8_KEY }, + { KEY_F9, B_F9_KEY }, + { KEY_F10, B_F10_KEY }, + { KEY_F11, B_F11_KEY }, + { KEY_F12, B_F12_KEY }, + //{ KEY_F13, ? }, + //{ KEY_F14, ? }, + //{ KEY_F15, ? }, + //{ KEY_F16, ? }, + { KEY_PRINT, B_PRINT_KEY }, + { KEY_SCROLLLOCK, B_SCROLL_KEY }, + { KEY_PAUSE, B_PAUSE_KEY }, + { KEY_UNKNOWN, 0 } +}; + +static _HaikuTranslatePair _hb_to_keycode[] = { + { KEY_BACKSPACE, B_BACKSPACE }, + { KEY_TAB, B_TAB }, + { KEY_RETURN, B_RETURN }, + { KEY_CAPSLOCK, B_CAPS_LOCK }, + { KEY_ESCAPE, B_ESCAPE }, + { KEY_SPACE, B_SPACE }, + { KEY_PAGEUP, B_PAGE_UP }, + { KEY_PAGEDOWN, B_PAGE_DOWN }, + { KEY_END, B_END }, + { KEY_HOME, B_HOME }, + { KEY_LEFT, B_LEFT_ARROW }, + { KEY_UP, B_UP_ARROW }, + { KEY_RIGHT, B_RIGHT_ARROW }, + { KEY_DOWN, B_DOWN_ARROW }, + { KEY_PRINT, B_PRINT_KEY }, + { KEY_INSERT, B_INSERT }, + { KEY_DELETE, B_DELETE }, + // { KEY_HELP, ??? }, + + { KEY_0, (0x30) }, + { KEY_1, (0x31) }, + { KEY_2, (0x32) }, + { KEY_3, (0x33) }, + { KEY_4, (0x34) }, + { KEY_5, (0x35) }, + { KEY_6, (0x36) }, + { KEY_7, (0x37) }, + { KEY_8, (0x38) }, + { KEY_9, (0x39) }, + { KEY_A, (0x61) }, + { KEY_B, (0x62) }, + { KEY_C, (0x63) }, + { KEY_D, (0x64) }, + { KEY_E, (0x65) }, + { KEY_F, (0x66) }, + { KEY_G, (0x67) }, + { KEY_H, (0x68) }, + { KEY_I, (0x69) }, + { KEY_J, (0x6A) }, + { KEY_K, (0x6B) }, + { KEY_L, (0x6C) }, + { KEY_M, (0x6D) }, + { KEY_N, (0x6E) }, + { KEY_O, (0x6F) }, + { KEY_P, (0x70) }, + { KEY_Q, (0x71) }, + { KEY_R, (0x72) }, + { KEY_S, (0x73) }, + { KEY_T, (0x74) }, + { KEY_U, (0x75) }, + { KEY_V, (0x76) }, + { KEY_W, (0x77) }, + { KEY_X, (0x78) }, + { KEY_Y, (0x79) }, + { KEY_Z, (0x7A) }, + +/* +{ KEY_PLAY, VK_PLAY},// (0xFA) +{ KEY_STANDBY,VK_SLEEP },//(0x5F) +{ 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) +{ 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, 0x3B }, + { KEY_EQUAL, 0x3D }, + { KEY_COLON, 0x2C }, + { KEY_MINUS, 0x2D }, + { KEY_PERIOD, 0x2E }, + { KEY_SLASH, 0x2F }, + { KEY_KP_MULTIPLY, 0x2A }, + { KEY_KP_ADD, 0x2B }, + + { KEY_QUOTELEFT, 0x60 }, + { KEY_BRACKETLEFT, 0x5B }, + { KEY_BACKSLASH, 0x5C }, + { KEY_BRACKETRIGHT, 0x5D }, + { KEY_APOSTROPHE, 0x27 }, + + { KEY_UNKNOWN, 0 } +}; + +unsigned int KeyMappingHaiku::get_keysym(int32 raw_char, int32 key) { + if (raw_char == B_INSERT && key == 0x64) { return KEY_KP_0; } + if (raw_char == B_END && key == 0x58) { return KEY_KP_1; } + if (raw_char == B_DOWN_ARROW && key == 0x59) { return KEY_KP_2; } + if (raw_char == B_PAGE_DOWN && key == 0x5A) { return KEY_KP_3; } + if (raw_char == B_LEFT_ARROW && key == 0x48) { return KEY_KP_4; } + if (raw_char == 0x35 && key == 0x49) { return KEY_KP_5; } + if (raw_char == B_RIGHT_ARROW && key == 0x4A) { return KEY_KP_6; } + if (raw_char == B_HOME && key == 0x37) { return KEY_KP_7; } + if (raw_char == B_UP_ARROW && key == 0x38) { return KEY_KP_8; } + if (raw_char == B_PAGE_UP && key == 0x39) { return KEY_KP_9; } + if (raw_char == 0x2F && key == 0x23) { return KEY_KP_DIVIDE; } + if (raw_char == 0x2D && key == 0x25) { return KEY_KP_SUBSTRACT; } + if (raw_char == B_DELETE && key == 0x65) { return KEY_KP_PERIOD; } + + if (raw_char == 0x10) { + for(int i = 0; _fn_to_keycode[i].keysym != KEY_UNKNOWN; i++) { + if (_fn_to_keycode[i].keycode == key) { + return _fn_to_keycode[i].keysym; + } + } + + return KEY_UNKNOWN; + } + + for(int i = 0; _hb_to_keycode[i].keysym != KEY_UNKNOWN; i++) { + if (_hb_to_keycode[i].keycode == raw_char) { + return _hb_to_keycode[i].keysym; + } + } + + return KEY_UNKNOWN; +} + +unsigned int KeyMappingHaiku::get_modifier_keysym(int32 key) { + for(int i = 0; _mod_to_keycode[i].keysym != KEY_UNKNOWN; i++) { + if ((_mod_to_keycode[i].keycode & key) != 0) { + return _mod_to_keycode[i].keysym; + } + } + + return KEY_UNKNOWN; +} diff --git a/platform/haiku/key_mapping_haiku.h b/platform/haiku/key_mapping_haiku.h new file mode 100644 index 0000000000..e2864678a8 --- /dev/null +++ b/platform/haiku/key_mapping_haiku.h @@ -0,0 +1,13 @@ +#ifndef KEY_MAPPING_HAIKU_H +#define KEY_MAPPING_HAIKU_H + +class KeyMappingHaiku +{ + KeyMappingHaiku() {}; + +public: + static unsigned int get_keysym(int32 raw_char, int32 key); + static unsigned int get_modifier_keysym(int32 key); +}; + +#endif diff --git a/platform/haiku/logo.png b/platform/haiku/logo.png Binary files differnew file mode 100644 index 0000000000..42d7728da8 --- /dev/null +++ b/platform/haiku/logo.png diff --git a/platform/haiku/os_haiku.cpp b/platform/haiku/os_haiku.cpp new file mode 100644 index 0000000000..1edb23d504 --- /dev/null +++ b/platform/haiku/os_haiku.cpp @@ -0,0 +1,320 @@ +#include <Screen.h> + +#include "servers/visual/visual_server_raster.h" +#include "servers/visual/visual_server_wrap_mt.h" +#include "drivers/gles2/rasterizer_gles2.h" +#include "servers/physics/physics_server_sw.h" +//#include "servers/physics_2d/physics_2d_server_wrap_mt.h" +#include "main/main.h" + +#include "os_haiku.h" + + +OS_Haiku::OS_Haiku() { +#ifdef MEDIA_KIT_ENABLED + AudioDriverManagerSW::add_driver(&driver_media_kit); +#endif +}; + +void OS_Haiku::run() { + if (!main_loop) { + return; + } + + main_loop->init(); + context_gl->release_current(); + + // TODO: clean up + BMessenger* bms = new BMessenger(window); + BMessage* msg = new BMessage(); + bms->SendMessage(LOCKGL_MSG, msg); + + window->StartMessageRunner(); + app->Run(); + window->StopMessageRunner(); + + delete app; + + delete bms; + delete msg; + main_loop->finish(); +} + +String OS_Haiku::get_name() { + return "Haiku"; +} + +int OS_Haiku::get_video_driver_count() const { + return 1; +} + +const char* OS_Haiku::get_video_driver_name(int p_driver) const { + return "GLES2"; +} + +OS::VideoMode OS_Haiku::get_default_video_mode() const { + return OS::VideoMode(800, 600, false); +} + +void OS_Haiku::initialize(const VideoMode& p_desired, int p_video_driver, int p_audio_driver) { + main_loop = NULL; + current_video_mode = p_desired; + + app = new HaikuApplication(); + + BRect frame; + frame.Set(50, 50, 50 + current_video_mode.width - 1, 50 + current_video_mode.height - 1); + + window = new HaikuDirectWindow(frame); + window->SetVideoMode(¤t_video_mode); + + if (current_video_mode.fullscreen) { + window->SetFullScreen(true); + } + + if (!current_video_mode.resizable) { + uint32 flags = window->Flags(); + flags |= B_NOT_RESIZABLE; + window->SetFlags(flags); + } + +#if defined(OPENGL_ENABLED) || defined(LEGACYGL_ENABLED) + context_gl = memnew(ContextGL_Haiku(window)); + context_gl->initialize(); + context_gl->make_current(); + + rasterizer = memnew(RasterizerGLES2); +#endif + + visual_server = memnew(VisualServerRaster(rasterizer)); + + ERR_FAIL_COND(!visual_server); + + // TODO: enable multithreaded VS + //if (get_render_thread_mode() != RENDER_THREAD_UNSAFE) { + // visual_server = memnew(VisualServerWrapMT(visual_server, get_render_thread_mode() == RENDER_SEPARATE_THREAD)); + //} + + input = memnew(InputDefault); + window->SetInput(input); + + window->Show(); + visual_server->init(); + + physics_server = memnew(PhysicsServerSW); + physics_server->init(); + physics_2d_server = memnew(Physics2DServerSW); + // TODO: enable multithreaded PS + //physics_2d_server = Physics2DServerWrapMT::init_server<Physics2DServerSW>(); + physics_2d_server->init(); + + AudioDriverManagerSW::get_driver(p_audio_driver)->set_singleton(); + + if (AudioDriverManagerSW::get_driver(p_audio_driver)->init() != OK) { + ERR_PRINT("Initializing audio failed."); + } + + sample_manager = memnew(SampleManagerMallocSW); + audio_server = memnew(AudioServerSW(sample_manager)); + audio_server->init(); + + spatial_sound_server = memnew(SpatialSoundServerSW); + spatial_sound_server->init(); + spatial_sound_2d_server = memnew(SpatialSound2DServerSW); + spatial_sound_2d_server->init(); +} + +void OS_Haiku::finalize() { + if (main_loop) { + memdelete(main_loop); + } + + main_loop = NULL; + + spatial_sound_server->finish(); + memdelete(spatial_sound_server); + + spatial_sound_2d_server->finish(); + memdelete(spatial_sound_2d_server); + + audio_server->finish(); + memdelete(audio_server); + memdelete(sample_manager); + + visual_server->finish(); + memdelete(visual_server); + memdelete(rasterizer); + + physics_server->finish(); + memdelete(physics_server); + + physics_2d_server->finish(); + memdelete(physics_2d_server); + + memdelete(input); + +#if defined(OPENGL_ENABLED) || defined(LEGACYGL_ENABLED) + memdelete(context_gl); +#endif +} + +void OS_Haiku::set_main_loop(MainLoop* p_main_loop) { + main_loop = p_main_loop; + input->set_main_loop(p_main_loop); + window->SetMainLoop(p_main_loop); +} + +MainLoop* OS_Haiku::get_main_loop() const { + return main_loop; +} + +void OS_Haiku::delete_main_loop() { + if (main_loop) { + memdelete(main_loop); + } + + main_loop = NULL; + window->SetMainLoop(NULL); +} + +void OS_Haiku::release_rendering_thread() { + context_gl->release_current(); +} + +void OS_Haiku::make_rendering_thread() { + context_gl->make_current(); +} + +bool OS_Haiku::can_draw() const { + // TODO: implement + return true; +} + +void OS_Haiku::swap_buffers() { + context_gl->swap_buffers(); +} + +Point2 OS_Haiku::get_mouse_pos() const { + return window->GetLastMousePosition(); +} + +int OS_Haiku::get_mouse_button_state() const { + return window->GetLastButtonMask(); +} + +void OS_Haiku::set_cursor_shape(CursorShape p_shape) { + //ERR_PRINT("set_cursor_shape() NOT IMPLEMENTED"); +} + +int OS_Haiku::get_screen_count() const { + // TODO: implement get_screen_count() + return 1; +} + +int OS_Haiku::get_current_screen() const { + // TODO: implement get_current_screen() + return 0; +} + +void OS_Haiku::set_current_screen(int p_screen) { + // TODO: implement set_current_screen() +} + +Point2 OS_Haiku::get_screen_position(int p_screen) const { + // TODO: make this work with the p_screen parameter + BScreen* screen = new BScreen(window); + BRect frame = screen->Frame(); + delete screen; + return Point2i(frame.left, frame.top); +} + +Size2 OS_Haiku::get_screen_size(int p_screen) const { + // TODO: make this work with the p_screen parameter + BScreen* screen = new BScreen(window); + BRect frame = screen->Frame(); + delete screen; + return Size2i(frame.IntegerWidth() + 1, frame.IntegerHeight() + 1); +} + +void OS_Haiku::set_window_title(const String& p_title) { + window->SetTitle(p_title.utf8().get_data()); +} + +Size2 OS_Haiku::get_window_size() const { + BSize size = window->Size(); + return Size2i(size.IntegerWidth() + 1, size.IntegerHeight() + 1); +} + +void OS_Haiku::set_window_size(const Size2 p_size) { + // TODO: why does it stop redrawing after this is called? + window->ResizeTo(p_size.x, p_size.y); +} + +Point2 OS_Haiku::get_window_position() const { + BPoint point(0, 0); + window->ConvertToScreen(&point); + return Point2i(point.x, point.y); +} + +void OS_Haiku::set_window_position(const Point2& p_position) { + window->MoveTo(p_position.x, p_position.y); +} + +void OS_Haiku::set_window_fullscreen(bool p_enabled) { + window->SetFullScreen(p_enabled); + current_video_mode.fullscreen = p_enabled; + visual_server->init(); +} + +bool OS_Haiku::is_window_fullscreen() const { + return current_video_mode.fullscreen; +} + +void OS_Haiku::set_window_resizable(bool p_enabled) { + uint32 flags = window->Flags(); + + if (p_enabled) { + flags &= ~(B_NOT_RESIZABLE); + } else { + flags |= B_NOT_RESIZABLE; + } + + window->SetFlags(flags); + current_video_mode.resizable = p_enabled; +} + +bool OS_Haiku::is_window_resizable() const { + return current_video_mode.resizable; +} + +void OS_Haiku::set_window_minimized(bool p_enabled) { + window->Minimize(p_enabled); +} + +bool OS_Haiku::is_window_minimized() const { + return window->IsMinimized(); +} + +void OS_Haiku::set_window_maximized(bool p_enabled) { + window->Minimize(!p_enabled); +} + +bool OS_Haiku::is_window_maximized() const { + return !window->IsMinimized(); +} + +void OS_Haiku::set_video_mode(const VideoMode& p_video_mode, int p_screen) { + ERR_PRINT("set_video_mode() NOT IMPLEMENTED"); +} + +OS::VideoMode OS_Haiku::get_video_mode(int p_screen) const { + return current_video_mode; +} + +void OS_Haiku::get_fullscreen_mode_list(List<VideoMode> *p_list, int p_screen) const { + ERR_PRINT("get_fullscreen_mode_list() NOT IMPLEMENTED"); +} + +String OS_Haiku::get_executable_path() const { + return OS::get_executable_path(); +} diff --git a/platform/haiku/os_haiku.h b/platform/haiku/os_haiku.h new file mode 100644 index 0000000000..e1b0b86cf4 --- /dev/null +++ b/platform/haiku/os_haiku.h @@ -0,0 +1,99 @@ +#ifndef OS_HAIKU_H +#define OS_HAIKU_H + +#include "drivers/unix/os_unix.h" +#include "servers/visual_server.h" +#include "servers/visual/rasterizer.h" +#include "servers/physics_server.h" +#include "servers/physics_2d/physics_2d_server_sw.h" +#include "servers/audio/audio_server_sw.h" +#include "servers/audio/sample_manager_sw.h" +#include "servers/spatial_sound/spatial_sound_server_sw.h" +#include "servers/spatial_sound_2d/spatial_sound_2d_server_sw.h" +#include "main/input_default.h" + +#include "audio_driver_media_kit.h" +#include "context_gl_haiku.h" +#include "haiku_application.h" +#include "haiku_direct_window.h" + + +class OS_Haiku : public OS_Unix { +private: + HaikuApplication* app; + HaikuDirectWindow* window; + MainLoop* main_loop; + InputDefault* input; + Rasterizer* rasterizer; + VisualServer* visual_server; + VideoMode current_video_mode; + PhysicsServer* physics_server; + Physics2DServer* physics_2d_server; + AudioServerSW* audio_server; + SampleManagerMallocSW* sample_manager; + SpatialSoundServerSW* spatial_sound_server; + SpatialSound2DServerSW* spatial_sound_2d_server; + +#ifdef MEDIA_KIT_ENABLED + AudioDriverMediaKit driver_media_kit; +#endif + +#if defined(OPENGL_ENABLED) || defined(LEGACYGL_ENABLED) + ContextGL_Haiku* context_gl; +#endif + + virtual void delete_main_loop(); + +protected: + virtual int get_video_driver_count() const; + virtual const char* get_video_driver_name(int p_driver) const; + virtual VideoMode get_default_video_mode() const; + + virtual void initialize(const VideoMode& p_desired, int p_video_driver, int p_audio_driver); + virtual void finalize(); + + virtual void set_main_loop(MainLoop* p_main_loop); + +public: + OS_Haiku(); + void run(); + + virtual String get_name(); + + virtual MainLoop* get_main_loop() const; + + virtual bool can_draw() const; + virtual void release_rendering_thread(); + virtual void make_rendering_thread(); + virtual void swap_buffers(); + + virtual Point2 get_mouse_pos() const; + virtual int get_mouse_button_state() const; + virtual void set_cursor_shape(CursorShape p_shape); + + virtual int get_screen_count() const; + virtual int get_current_screen() const; + virtual void set_current_screen(int p_screen); + virtual Point2 get_screen_position(int p_screen=0) const; + virtual Size2 get_screen_size(int p_screen=0) const; + virtual void set_window_title(const String& p_title); + virtual Size2 get_window_size() const; + virtual void set_window_size(const Size2 p_size); + virtual Point2 get_window_position() const; + virtual void set_window_position(const Point2& p_position); + virtual void set_window_fullscreen(bool p_enabled); + virtual bool is_window_fullscreen() const; + virtual void set_window_resizable(bool p_enabled); + virtual bool is_window_resizable() const; + virtual void set_window_minimized(bool p_enabled); + virtual bool is_window_minimized() const; + virtual void set_window_maximized(bool p_enabled); + virtual bool is_window_maximized() const; + + virtual void set_video_mode(const VideoMode& p_video_mode, int p_screen=0); + virtual VideoMode get_video_mode(int p_screen=0) const; + virtual void get_fullscreen_mode_list(List<VideoMode> *p_list, int p_screen=0) const; + virtual String get_executable_path() const; +}; + +#endif diff --git a/platform/haiku/platform_config.h b/platform/haiku/platform_config.h new file mode 100644 index 0000000000..691bdbdb9c --- /dev/null +++ b/platform/haiku/platform_config.h @@ -0,0 +1,6 @@ +#include <alloca.h> + +// for ifaddrs.h needed in drivers/unix/ip_unix.cpp +#define _BSD_SOURCE 1 + +#define GLES2_INCLUDE_H <GL/glew.h> diff --git a/scene/2d/parallax_background.cpp b/scene/2d/parallax_background.cpp index 109546bde3..8bb4eb55ba 100644 --- a/scene/2d/parallax_background.cpp +++ b/scene/2d/parallax_background.cpp @@ -110,7 +110,10 @@ void ParallaxBackground::_update_scroll() { if (!l) continue; - l->set_base_offset_and_scale(ofs,scale); + if (ignore_camera_zoom) + l->set_base_offset_and_scale(ofs, 1.0); + else + l->set_base_offset_and_scale(ofs, scale); } } @@ -165,6 +168,18 @@ Point2 ParallaxBackground::get_limit_end() const { return limit_end; } +void ParallaxBackground::set_ignore_camera_zoom(bool ignore){ + + ignore_camera_zoom = ignore; + +} + +bool ParallaxBackground::is_ignore_camera_zoom(){ + + return ignore_camera_zoom; + +} + void ParallaxBackground::_bind_methods() { ObjectTypeDB::bind_method(_MD("_camera_moved"),&ParallaxBackground::_camera_moved); @@ -178,6 +193,8 @@ void ParallaxBackground::_bind_methods() { ObjectTypeDB::bind_method(_MD("get_limit_begin"),&ParallaxBackground::get_limit_begin); ObjectTypeDB::bind_method(_MD("set_limit_end","ofs"),&ParallaxBackground::set_limit_end); ObjectTypeDB::bind_method(_MD("get_limit_end"),&ParallaxBackground::get_limit_end); + ObjectTypeDB::bind_method(_MD("set_ignore_camera_zoom"), &ParallaxBackground::set_ignore_camera_zoom); + ObjectTypeDB::bind_method(_MD("is_ignore_camera_zoom"), &ParallaxBackground::is_ignore_camera_zoom); ADD_PROPERTY( PropertyInfo(Variant::VECTOR2,"scroll/offset"),_SCS("set_scroll_offset"),_SCS("get_scroll_offset")); @@ -185,6 +202,7 @@ void ParallaxBackground::_bind_methods() { ADD_PROPERTY( PropertyInfo(Variant::VECTOR2,"scroll/base_scale"),_SCS("set_scroll_base_scale"),_SCS("get_scroll_base_scale")); ADD_PROPERTY( PropertyInfo(Variant::VECTOR2,"scroll/limit_begin"),_SCS("set_limit_begin"),_SCS("get_limit_begin")); ADD_PROPERTY( PropertyInfo(Variant::VECTOR2,"scroll/limit_end"),_SCS("set_limit_end"),_SCS("get_limit_end")); + ADD_PROPERTY( PropertyInfo(Variant::BOOL, "scroll/ignore_camera_zoom"), _SCS("set_ignore_camera_zoom"), _SCS("is_ignore_camera_zoom")); } diff --git a/scene/2d/parallax_background.h b/scene/2d/parallax_background.h index 363236b2ad..8dede07a16 100644 --- a/scene/2d/parallax_background.h +++ b/scene/2d/parallax_background.h @@ -44,6 +44,7 @@ class ParallaxBackground : public CanvasLayer { String group_name; Point2 limit_begin; Point2 limit_end; + bool ignore_camera_zoom; void _update_scroll(); protected: @@ -72,6 +73,9 @@ public: void set_limit_end(const Point2& p_ofs); Point2 get_limit_end() const; + void set_ignore_camera_zoom(bool ignore); + bool is_ignore_camera_zoom(); + ParallaxBackground(); }; diff --git a/scene/gui/popup_menu.cpp b/scene/gui/popup_menu.cpp index 5afe2ed704..6c21ea639f 100644 --- a/scene/gui/popup_menu.cpp +++ b/scene/gui/popup_menu.cpp @@ -740,10 +740,18 @@ int PopupMenu::find_item_by_accelerator(uint32_t p_accel) const { void PopupMenu::activate_item(int p_item) { - ERR_FAIL_INDEX(p_item,items.size()); ERR_FAIL_COND(items[p_item].separator); emit_signal("item_pressed",items[p_item].ID); + + //hide all parent PopupMenue's + Node *next = get_parent(); + PopupMenu *pop = next->cast_to<PopupMenu>(); + while (pop) { + pop->hide(); + next = next->get_parent(); + pop = next->cast_to<PopupMenu>(); + } hide(); } diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp index 7a607786ee..ef6a2ba6aa 100644 --- a/scene/gui/rich_text_label.cpp +++ b/scene/gui/rich_text_label.cpp @@ -1503,10 +1503,10 @@ Error RichTextLabel::append_bbcode(const String& p_bbcode) { void RichTextLabel::scroll_to_line(int p_line) { + p_line -= 1; ERR_FAIL_INDEX(p_line,lines.size()); _validate_line_caches(); - vscroll->set_val(lines[p_line].height_accum_cache); - + vscroll->set_val(lines[p_line].height_accum_cache-lines[p_line].height_cache); } @@ -1569,27 +1569,23 @@ bool RichTextLabel::search(const String& p_string,bool p_from_selection) { it=_get_next_item(it); } - if (!it) - line=lines.size()-1; } - scroll_to_line(line-2); + if (line > 1) { + line-=1; + } + + scroll_to_line(line); return true; } - } else if (it->type==ITEM_NEWLINE) { - - line=static_cast<ItemNewline*>(it)->line; } - it=_get_next_item(it); charidx=0; } - - return false; } diff --git a/scene/gui/tabs.cpp b/scene/gui/tabs.cpp index a849d3ae72..6d84f028b3 100644 --- a/scene/gui/tabs.cpp +++ b/scene/gui/tabs.cpp @@ -64,6 +64,15 @@ Size2 Tabs::get_minimum_size() const { ms.width+=bms.width; ms.height=MAX(bms.height+tab_bg->get_minimum_size().height,ms.height); } + + if (tabs[i].close_button.is_valid()) { + Ref<Texture> cb=tabs[i].close_button; + Size2 bms = cb->get_size()+get_stylebox("button")->get_minimum_size(); + bms.width+=get_constant("hseparation"); + + ms.width+=bms.width; + ms.height=MAX(bms.height+tab_bg->get_minimum_size().height,ms.height); + } } return ms; @@ -77,22 +86,48 @@ void Tabs::_input_event(const InputEvent& p_event) { Point2 pos( p_event.mouse_motion.x, p_event.mouse_motion.y ); - int hover=-1; + int hover_buttons=-1; + hover=-1; for(int i=0;i<tabs.size();i++) { + // test hovering tab to display close button if policy says so + if (cb_displaypolicy == SHOW_HOVER) { + int ofs=tabs[i].ofs_cache; + int size = tabs[i].ofs_cache; + if (pos.x >=tabs[i].ofs_cache && pos.x<tabs[i].ofs_cache+tabs[i].size_cache) { + hover=i; + } + } + + + // test hovering right button and close button if (tabs[i].rb_rect.has_point(pos)) { - hover=i; + rb_hover=i; + hover_buttons = i; break; } + else if (tabs[i].cb_rect.has_point(pos)) { + cb_hover=i; + hover_buttons = i; + break; + } + + + } - if (hover!=rb_hover) { - rb_hover=hover; - update(); + if (hover_buttons == -1) { // no hover + rb_hover= hover_buttons; + cb_hover= hover_buttons; } + update(); + return; } + + + if (rb_pressing && p_event.type==InputEvent::MOUSE_BUTTON && !p_event.mouse_button.pressed && p_event.mouse_button.button_index==BUTTON_LEFT) { @@ -106,6 +141,20 @@ void Tabs::_input_event(const InputEvent& p_event) { update(); } + if (cb_pressing && p_event.type==InputEvent::MOUSE_BUTTON && + !p_event.mouse_button.pressed && + p_event.mouse_button.button_index==BUTTON_LEFT) { + + if (cb_hover!=-1) { + //pressed + emit_signal("tab_close",cb_hover); + } + + cb_pressing=false; + update(); + } + + if (p_event.type==InputEvent::MOUSE_BUTTON && p_event.mouse_button.pressed && p_event.mouse_button.button_index==BUTTON_LEFT) { @@ -122,6 +171,12 @@ void Tabs::_input_event(const InputEvent& p_event) { return; } + if (tabs[i].cb_rect.has_point(pos)) { + cb_pressing=true; + update(); + return; + } + int ofs=tabs[i].ofs_cache; int size = tabs[i].ofs_cache; if (pos.x >=tabs[i].ofs_cache && pos.x<tabs[i].ofs_cache+tabs[i].size_cache) { @@ -148,6 +203,8 @@ void Tabs::_notification(int p_what) { case NOTIFICATION_MOUSE_EXIT: { rb_hover=-1; + cb_hover=-1; + hover=-1; update(); } break; case NOTIFICATION_DRAW: { @@ -186,7 +243,7 @@ void Tabs::_notification(int p_what) { String s = tabs[i].text; int lsize=0; - int slen=font->get_string_size(s).width;; + int slen=font->get_string_size(s).width; lsize+=slen; Ref<Texture> icon; @@ -211,6 +268,56 @@ void Tabs::_notification(int p_what) { } + // Close button + switch (cb_displaypolicy) { + case SHOW_ALWAYS: { + if (tabs[i].close_button.is_valid()) { + Ref<StyleBox> style = get_stylebox("button"); + Ref<Texture> rb=tabs[i].close_button; + + lsize+=get_constant("hseparation"); + lsize+=style->get_margin(MARGIN_LEFT); + lsize+=rb->get_width(); + lsize+=style->get_margin(MARGIN_RIGHT); + + } + } break; + case SHOW_ACTIVE_ONLY: { + if (i==current) { + if (tabs[i].close_button.is_valid()) { + Ref<StyleBox> style = get_stylebox("button"); + Ref<Texture> rb=tabs[i].close_button; + + lsize+=get_constant("hseparation"); + lsize+=style->get_margin(MARGIN_LEFT); + lsize+=rb->get_width(); + lsize+=style->get_margin(MARGIN_RIGHT); + + } + } + } break; + case SHOW_HOVER: { + if (i==current || i==hover) { + if (tabs[i].close_button.is_valid()) { + Ref<StyleBox> style = get_stylebox("button"); + Ref<Texture> rb=tabs[i].close_button; + + lsize+=get_constant("hseparation"); + lsize+=style->get_margin(MARGIN_LEFT); + lsize+=rb->get_width(); + lsize+=style->get_margin(MARGIN_RIGHT); + + } + } + } break; + case SHOW_NEVER: // by default, never show close button + default: { + // do nothing + } break; + + } + + Ref<StyleBox> sb; int va; Color col; @@ -273,6 +380,103 @@ void Tabs::_notification(int p_what) { } + + + + // Close button + switch (cb_displaypolicy) { + case SHOW_ALWAYS: { + if (tabs[i].close_button.is_valid()) { + Ref<StyleBox> style = get_stylebox("button"); + Ref<Texture> cb=tabs[i].close_button; + + w+=get_constant("hseparation"); + + Rect2 cb_rect; + cb_rect.size=style->get_minimum_size()+cb->get_size(); + cb_rect.pos.x=w; + cb_rect.pos.y=sb->get_margin(MARGIN_TOP)+((sb_rect.size.y-sb_ms.y)-(cb_rect.size.y))/2; + + if (cb_hover==i) { + if (cb_pressing) + get_stylebox("button_pressed")->draw(ci,cb_rect); + else + style->draw(ci,cb_rect); + } + + w+=style->get_margin(MARGIN_LEFT); + + cb->draw(ci,Point2i( w,cb_rect.pos.y+style->get_margin(MARGIN_TOP) )); + w+=cb->get_width(); + w+=style->get_margin(MARGIN_RIGHT); + tabs[i].cb_rect=cb_rect; + } + } break; + case SHOW_ACTIVE_ONLY: { + if (current==i) { + if (tabs[i].close_button.is_valid()) { + Ref<StyleBox> style = get_stylebox("button"); + Ref<Texture> cb=tabs[i].close_button; + + w+=get_constant("hseparation"); + + Rect2 cb_rect; + cb_rect.size=style->get_minimum_size()+cb->get_size(); + cb_rect.pos.x=w; + cb_rect.pos.y=sb->get_margin(MARGIN_TOP)+((sb_rect.size.y-sb_ms.y)-(cb_rect.size.y))/2; + + if (cb_hover==i) { + if (cb_pressing) + get_stylebox("button_pressed")->draw(ci,cb_rect); + else + style->draw(ci,cb_rect); + } + + w+=style->get_margin(MARGIN_LEFT); + + cb->draw(ci,Point2i( w,cb_rect.pos.y+style->get_margin(MARGIN_TOP) )); + w+=cb->get_width(); + w+=style->get_margin(MARGIN_RIGHT); + tabs[i].cb_rect=cb_rect; + } + } + } break; + case SHOW_HOVER: { + if (current==i || hover==i) { + if (tabs[i].close_button.is_valid()) { + Ref<StyleBox> style = get_stylebox("button"); + Ref<Texture> cb=tabs[i].close_button; + + w+=get_constant("hseparation"); + + Rect2 cb_rect; + cb_rect.size=style->get_minimum_size()+cb->get_size(); + cb_rect.pos.x=w; + cb_rect.pos.y=sb->get_margin(MARGIN_TOP)+((sb_rect.size.y-sb_ms.y)-(cb_rect.size.y))/2; + + if (cb_hover==i) { + if (cb_pressing) + get_stylebox("button_pressed")->draw(ci,cb_rect); + else + style->draw(ci,cb_rect); + } + + w+=style->get_margin(MARGIN_LEFT); + + cb->draw(ci,Point2i( w,cb_rect.pos.y+style->get_margin(MARGIN_TOP) )); + w+=cb->get_width(); + w+=style->get_margin(MARGIN_RIGHT); + tabs[i].cb_rect=cb_rect; + } + } + } break; + case SHOW_NEVER: + default: { + // show nothing + } break; + + } + w+=sb->get_margin(MARGIN_RIGHT); tabs[i].size_cache=w-tabs[i].ofs_cache; @@ -358,11 +562,29 @@ Ref<Texture> Tabs::get_tab_right_button(int p_tab) const{ } +void Tabs::set_tab_close_button(int p_tab, const Ref<Texture>& p_close_button) { + ERR_FAIL_INDEX(p_tab, tabs.size()); + tabs[p_tab].close_button=p_close_button; + update(); + minimum_size_changed(); +} + + +Ref<Texture> Tabs::get_tab_close_button(int p_tab) const{ + + ERR_FAIL_INDEX_V(p_tab,tabs.size(),Ref<Texture>()); + return tabs[p_tab].close_button; + +} + void Tabs::add_tab(const String& p_str,const Ref<Texture>& p_icon) { Tab t; t.text=p_str; t.icon=p_icon; + + t.close_button = get_icon("Close","EditorIcons"); + tabs.push_back(t); update(); @@ -394,6 +616,11 @@ void Tabs::remove_tab(int p_idx) { } +void Tabs::set_tab_close_display_policy(CloseButtonDisplayPolicy p_cb_displaypolicy) { + cb_displaypolicy = p_cb_displaypolicy; +} + + void Tabs::set_tab_align(TabAlign p_align) { tab_align=p_align; @@ -423,14 +650,22 @@ void Tabs::_bind_methods() { ADD_SIGNAL(MethodInfo("tab_changed",PropertyInfo(Variant::INT,"tab"))); ADD_SIGNAL(MethodInfo("right_button_pressed",PropertyInfo(Variant::INT,"tab"))); + ADD_SIGNAL(MethodInfo("tab_close",PropertyInfo(Variant::INT,"tab"))); + ADD_PROPERTY( PropertyInfo(Variant::INT, "current_tab", PROPERTY_HINT_RANGE,"-1,4096,1",PROPERTY_USAGE_EDITOR), _SCS("set_current_tab"), _SCS("get_current_tab") ); BIND_CONSTANT( ALIGN_LEFT ); BIND_CONSTANT( ALIGN_CENTER ); BIND_CONSTANT( ALIGN_RIGHT ); + + BIND_CONSTANT( SHOW_ACTIVE_ONLY ); + BIND_CONSTANT( SHOW_ALWAYS ); + BIND_CONSTANT( SHOW_HOVER ); + BIND_CONSTANT( SHOW_NEVER ); } + Tabs::Tabs() { current=0; @@ -438,4 +673,7 @@ Tabs::Tabs() { rb_hover=-1; rb_pressing=false; + cb_hover=-1; + cb_pressing=false; + cb_displaypolicy = SHOW_NEVER; // Default : no close button } diff --git a/scene/gui/tabs.h b/scene/gui/tabs.h index 5cb0d9e916..1a8352bc93 100644 --- a/scene/gui/tabs.h +++ b/scene/gui/tabs.h @@ -42,6 +42,14 @@ public: ALIGN_CENTER, ALIGN_RIGHT }; + + enum CloseButtonDisplayPolicy { + + SHOW_ALWAYS, + SHOW_ACTIVE_ONLY, + SHOW_HOVER, + SHOW_NEVER + }; private: @@ -53,6 +61,8 @@ private: int size_cache; Ref<Texture> right_button; Rect2 rb_rect; + Ref<Texture> close_button; + Rect2 cb_rect; }; Vector<Tab> tabs; @@ -63,6 +73,12 @@ private: int rb_hover; bool rb_pressing; + int cb_hover; + bool cb_pressing; + CloseButtonDisplayPolicy cb_displaypolicy; + + int hover; // hovered tab + protected: void _input_event(const InputEvent& p_event); @@ -82,6 +98,10 @@ public: void set_tab_right_button(int p_tab,const Ref<Texture>& p_right_button); Ref<Texture> get_tab_right_button(int p_tab) const; + void set_tab_close_button(int p_tab, const Ref<Texture>& p_close_button); + Ref<Texture> get_tab_close_button(int p_tab) const; + void set_tab_close_display_policy(CloseButtonDisplayPolicy p_cb_displaypolicy); + void set_tab_align(TabAlign p_align); TabAlign get_tab_align() const; diff --git a/tools/editor/editor_node.cpp b/tools/editor/editor_node.cpp index 9137503e1b..f007e95494 100644 --- a/tools/editor/editor_node.cpp +++ b/tools/editor/editor_node.cpp @@ -976,6 +976,7 @@ void EditorNode::_save_scene(String p_file) { //EditorFileSystem::get_singleton()->update_file(p_file,sdata->get_type()); set_current_version(editor_data.get_undo_redo().get_version()); _update_title(); + _update_scene_tabs(); } else { _dialog_display_file_error(p_file,err); @@ -1399,7 +1400,6 @@ void EditorNode::_dialog_action(String p_file) { } break; default: { //save scene? - if (file->get_mode()==FileDialog::MODE_SAVE_FILE) { //_save_scene(p_file); @@ -3931,6 +3931,7 @@ void EditorNode::_bind_methods() { ObjectTypeDB::bind_method("set_current_scene",&EditorNode::set_current_scene); ObjectTypeDB::bind_method("set_current_version",&EditorNode::set_current_version); ObjectTypeDB::bind_method("_scene_tab_changed",&EditorNode::_scene_tab_changed); + ObjectTypeDB::bind_method("_scene_tab_closed",&EditorNode::_scene_tab_closed); ObjectTypeDB::bind_method("_scene_tab_script_edited",&EditorNode::_scene_tab_script_edited); ObjectTypeDB::bind_method("_set_main_scene_state",&EditorNode::_set_main_scene_state); ObjectTypeDB::bind_method("_update_scene_tabs",&EditorNode::_update_scene_tabs); @@ -4385,6 +4386,17 @@ void EditorNode::_scene_tab_script_edited(int p_tab) { edit_resource(script); } +void EditorNode::_scene_tab_closed(int p_tab) { + set_current_scene(p_tab); + bool p_confirmed = true; + if (unsaved_cache) + p_confirmed = false; + + _menu_option_confirm(FILE_CLOSE, p_confirmed); + _update_scene_tabs(); +} + + void EditorNode::_scene_tab_changed(int p_tab) { @@ -4552,8 +4564,10 @@ EditorNode::EditorNode() { scene_tabs=memnew( Tabs ); scene_tabs->add_tab("unsaved"); scene_tabs->set_tab_align(Tabs::ALIGN_CENTER); + scene_tabs->set_tab_close_display_policy(Tabs::SHOW_HOVER); scene_tabs->connect("tab_changed",this,"_scene_tab_changed"); scene_tabs->connect("right_button_pressed",this,"_scene_tab_script_edited"); + scene_tabs->connect("tab_close", this, "_scene_tab_closed"); top_dark_vb->add_child(scene_tabs); //left left_l_hsplit = memnew( HSplitContainer ); @@ -4690,6 +4704,7 @@ EditorNode::EditorNode() { main_editor_tabs = memnew( Tabs ); main_editor_tabs->connect("tab_changed",this,"_editor_select"); + main_editor_tabs->set_tab_close_display_policy(Tabs::SHOW_NEVER); HBoxContainer *srth = memnew( HBoxContainer ); srt->add_child( srth ); Control *tec = memnew( Control ); diff --git a/tools/editor/editor_node.h b/tools/editor/editor_node.h index d52e08191d..978e8390dc 100644 --- a/tools/editor/editor_node.h +++ b/tools/editor/editor_node.h @@ -501,6 +501,7 @@ class EditorNode : public Node { void _dock_split_dragged(int ofs); void _dock_popup_exit(); void _scene_tab_changed(int p_tab); + void _scene_tab_closed(int p_tab); void _scene_tab_script_edited(int p_tab); Dictionary _get_main_scene_state(); diff --git a/tools/editor/editor_settings.cpp b/tools/editor/editor_settings.cpp index a771893bdd..651b30c724 100644 --- a/tools/editor/editor_settings.cpp +++ b/tools/editor/editor_settings.cpp @@ -474,6 +474,7 @@ void EditorSettings::_load_defaults() { set("scenetree_editor/duplicate_node_name_num_separator",0); hints["scenetree_editor/duplicate_node_name_num_separator"]=PropertyInfo(Variant::INT,"scenetree_editor/duplicate_node_name_num_separator",PROPERTY_HINT_ENUM, "None,Space,Underscore,Dash"); + set("gridmap_editor/pick_distance", 5000.0); set("3d_editor/default_fov",45.0); set("3d_editor/default_z_near",0.1); diff --git a/tools/editor/plugins/canvas_item_editor_plugin.cpp b/tools/editor/plugins/canvas_item_editor_plugin.cpp index c2cacd13bc..d318f6f6fa 100644 --- a/tools/editor/plugins/canvas_item_editor_plugin.cpp +++ b/tools/editor/plugins/canvas_item_editor_plugin.cpp @@ -144,6 +144,9 @@ void CanvasItemEditor::_unhandled_key_input(const InputEvent& p_ev) { if (!is_visible()) return; + if (p_ev.key.mod.control) + // prevent to change tool mode when control key is pressed + return; if (p_ev.key.pressed && !p_ev.key.echo && p_ev.key.scancode==KEY_Q) _tool_select(TOOL_SELECT); if (p_ev.key.pressed && !p_ev.key.echo && p_ev.key.scancode==KEY_W) diff --git a/tools/editor/project_manager.cpp b/tools/editor/project_manager.cpp index f1eecd53b0..9f47291433 100644 --- a/tools/editor/project_manager.cpp +++ b/tools/editor/project_manager.cpp @@ -245,7 +245,8 @@ public: project_name->clear(); if (import_mode) { - set_title("Import Existing Project:"); + set_title("Import Existing Project"); + get_ok()->set_text("Import"); pp->set_text("Project Path: (Must exist)"); pn->set_text("Project Name:"); pn->hide(); @@ -254,7 +255,8 @@ public: popup_centered(Size2(500,125)); } else { - set_title("Create New Project:"); + set_title("Create New Project"); + get_ok()->set_text("Create"); pp->set_text("Project Path:"); pn->set_text("Project Name:"); pn->show(); @@ -313,7 +315,6 @@ public: l->add_color_override("font_color",Color(1,0.4,0.3,0.8)); l->set_align(Label::ALIGN_CENTER); - get_ok()->set_text("Create"); DirAccess *d = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); project_path->set_text(d->get_current_dir()); memdelete(d); |