diff --git a/.gitmodules b/.gitmodules
index 7c6cfdb94..cb71c3459 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -1,20 +1,20 @@
[submodule "tests/harness/modules/ruisapp"]
path = tests/harness/modules/ruisapp
url = ../ruisapp
- branch = main
+ branch = multiwindow # main
[submodule "tests/harness/modules/ruis-render-opengl"]
path = tests/harness/modules/ruis-render-opengl
url = ../ruis-render-opengl
- branch = main
+ branch = multiwindow # main
[submodule "tests/harness/modules/ruis-render-opengles"]
path = tests/harness/modules/ruis-render-opengles
url = ../ruis-render-opengles
- branch = main
-[submodule "tool-configs"]
- path = tool-configs
- url = ../tool-configs
- branch = main
+ branch = multiwindow # main
[submodule "tests/harness/modules/ruis-render-null"]
path = tests/harness/modules/ruis-render-null
url = ../ruis-render-null
+ branch = multiwindow # main
+[submodule "tool-configs"]
+ path = tool-configs
+ url = ../tool-configs
branch = main
diff --git a/.vscode/launch.json b/.vscode/launch.json
index 2e085ddd4..2d60009b8 100644
--- a/.vscode/launch.json
+++ b/.vscode/launch.json
@@ -5,7 +5,7 @@
"version": "0.2.0",
"configurations": [
{
- "name": "(gdb) app",
+ "name": "(gdb) app-xorg",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/tests/app/out/dev/tests",
@@ -15,7 +15,11 @@
"environment": [
{
"name": "LD_LIBRARY_PATH",
- "value": "../../src/out/dev:../harness/modules/ruisapp/src/out/rel_no_install/opengl-xorg:../harness/modules/ruis-render-opengl/src/out/rel_no_install"
+ "value": "../../src/out/dev:../harness/modules/ruisapp/src/out/dev/opengl-xorg:../harness/modules/ruis-render-opengl/src/out/dev"
+ },
+ {
+ "name": "DYLD_LIBRARY_PATH",
+ "value": "../../src/out/dev:../harness/modules/ruisapp/src/out/dev/opengl:../harness/modules/ruis-render-opengl/src/out/dev"
}
],
"externalConsole": false,
@@ -27,7 +31,57 @@
"ignoreFailures": true
}
],
- "preLaunchTask": "build-dev"
+ // "preLaunchTask": "build-dev"
+ },
+ {
+ "name": "(gdb) app-wayland",
+ "type": "cppdbg",
+ "request": "launch",
+ "program": "${workspaceFolder}/tests/app/out/dev/tests",
+ "args": [],
+ "stopAtEntry": false,
+ "cwd": "${workspaceFolder}/tests/app",
+ "environment": [
+ {
+ "name": "LD_LIBRARY_PATH",
+ "value": "../../src/out/dev:../harness/modules/ruisapp/src/out/dev/opengles-wayland:../harness/modules/ruis-render-opengles/src/out/dev"
+ }
+ ],
+ "externalConsole": false,
+ "MIMode": "gdb",
+ "setupCommands": [
+ {
+ "description": "Enable pretty-printing for gdb",
+ "text": "-enable-pretty-printing",
+ "ignoreFailures": true
+ }
+ ],
+ // "preLaunchTask": "build-dev"
+ },
+ {
+ "name": "(gdb) app-sdl",
+ "type": "cppdbg",
+ "request": "launch",
+ "program": "${workspaceFolder}/tests/app/out/dev/tests",
+ "args": [],
+ "stopAtEntry": false,
+ "cwd": "${workspaceFolder}/tests/app",
+ "environment": [
+ {
+ "name": "LD_LIBRARY_PATH",
+ "value": "../../src/out/dev:../harness/modules/ruisapp/src/out/dev/opengl-sdl:../harness/modules/ruis-render-opengl/src/out/dev"
+ }
+ ],
+ "externalConsole": false,
+ "MIMode": "gdb",
+ "setupCommands": [
+ {
+ "description": "Enable pretty-printing for gdb",
+ "text": "-enable-pretty-printing",
+ "ignoreFailures": true
+ }
+ ],
+ // "preLaunchTask": "build-dev"
},
{
"name": "(gdb) app2",
diff --git a/.vscode/tasks.json b/.vscode/tasks.json
index de70b7a1b..dd9966851 100644
--- a/.vscode/tasks.json
+++ b/.vscode/tasks.json
@@ -207,6 +207,13 @@
"problemMatcher": [],
"group": "build"
},
+ {
+ "label": "run-app-gl-sdl-dev",
+ "type": "shell",
+ "command": "make run-app win=sdl config=dev",
+ "problemMatcher": [],
+ "group": "build"
+ },
{
"label": "run-app-dev",
"type": "shell",
diff --git a/build/android/app/CMakeLists.txt b/build/android/app/CMakeLists.txt
index 3aaaf060d..391d177c0 100644
--- a/build/android/app/CMakeLists.txt
+++ b/build/android/app/CMakeLists.txt
@@ -12,15 +12,13 @@ file(GLOB_RECURSE srcs
include (${ANDROID_GRADLE_NATIVE_BUNDLE_PLUGIN_MK})
-set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17")
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17 -DDEBUG")
include_directories(
../../../src
../../../tests/harness/modules/ruisapp/src
../../../tests/harness/modules/ruis-render-opengles/src
)
-#link_directories(../ruis/build/intermediates/cmake/release/obj/${ANDROID_ABI})
-#link_directories(../ruis/.cxx/Debug/4x66344r/arm64-v8a)
add_library(
# Specifies the name of the library.
diff --git a/build/android/app/build.gradle b/build/android/app/build.gradle
index e4abe2313..1b6360f31 100755
--- a/build/android/app/build.gradle
+++ b/build/android/app/build.gradle
@@ -55,7 +55,7 @@ dependencies {
// implementation 'io.github.cppfw:png:+'
// implementation 'io.github.cppfw:jpeg:+'
implementation 'io.github.cppfw:freetype:+'
-// implementation project(path: ':ruis')
+ // implementation project(path: ':ruis')
}
task copyResToAssets {
diff --git a/build/android/app/src/main/java/io/github/cppfw/ruisapp/RuisappActivity.java b/build/android/app/src/main/java/io/github/cppfw/ruisapp/RuisappActivity.java
deleted file mode 100755
index fb92e9fa6..000000000
--- a/build/android/app/src/main/java/io/github/cppfw/ruisapp/RuisappActivity.java
+++ /dev/null
@@ -1,117 +0,0 @@
-package io.github.cppfw.ruisapp;
-
-import android.app.NativeActivity;
-import android.app.Service;
-import android.content.Context;
-import android.graphics.Rect;
-import android.os.Bundle;
-import android.util.DisplayMetrics;
-import android.util.Log;
-import android.view.Display;
-import android.view.KeyCharacterMap;
-import android.view.KeyEvent;
-import android.view.Window;
-import android.view.WindowManager;
-import android.view.inputmethod.InputMethodManager;
-
-import java.io.IOException;
-
-
-public class RuisappActivity extends NativeActivity {
- {
- System.loadLibrary("c++_shared");
- System.loadLibrary("ruisapp_application");
- }
-
- public static final String LOGTAG = "ruisapp java side";
-
- private int curKeyDevice;
- private KeyCharacterMap curCharMap;
-
- public int resolveKeyUnicode(int deviceID, int metaState, int keyCode){
- Log.d(LOGTAG, "resolveKeyUnicode(): invoked, keyCode = " + keyCode);
- if(this.curCharMap == null || curKeyDevice != deviceID){
- try{
- this.curCharMap = KeyCharacterMap.load(deviceID);
- this.curKeyDevice = deviceID;
- }catch(Exception e){
- Log.e(LOGTAG, "resolveKeyUnicode(): Could not load KeyCharacterMap");
- return 0;//could not load char map, thus could not resolve character
- }
- }
-
- return this.curCharMap.get(keyCode, metaState);
- }
-
- public float getDotsPerInch(){
- Display d = ((WindowManager)getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
- DisplayMetrics m = new DisplayMetrics();
- d.getMetrics(m);
- Log.d(LOGTAG, "getDotsPerInch(): xdpi = " + m.xdpi + " ydpi = " + m.ydpi + " density = " + m.density);
- return (m.xdpi + m.ydpi) / 2.0f;
- }
-
- private static native void handleCharacterStringInput(String str);
-
- @Override
- public boolean dispatchKeyEvent(KeyEvent event) {
- Log.d(LOGTAG, "dispatchKeyEvent(): invoked");
- if(event.getAction() == KeyEvent.ACTION_MULTIPLE && event.getKeyCode() == KeyEvent.KEYCODE_UNKNOWN){
- Log.d(LOGTAG, "dispatchKeyEvent(): multiple characters are being delivered, chars = " + event.getCharacters());
- //Multiple characters are being delivered. NativeActivity currently does not
- //support passing multiple characters from KeyEvent to native code, so we need to do it here.
- this.handleCharacterStringInput(event.getCharacters());
- return true;
- }
- return super.dispatchKeyEvent(event);
- }
-
- //Override the Back button handler to prevent activity from automatically closing by Back key.
- @Override
- public void onBackPressed() {
- }
-
- private InputMethodManager imm;
-
- @Override
- protected void onCreate(Bundle savedInstanceState){
- super.onCreate(savedInstanceState);
-
- this.imm = (InputMethodManager)this.getSystemService(Service.INPUT_METHOD_SERVICE);
- }
-
-
- public void showVirtualKeyboard(){
- this.imm.showSoftInput(this.getWindow().getDecorView(), InputMethodManager.SHOW_FORCED);
- Rect r = new Rect();
- this.getWindow().getDecorView().getWindowVisibleDisplayFrame(r);
- Log.d(LOGTAG, "showVirtualKeyboard(): visible rect = " + r.left + ", " + r.right + ", " + r.top + ", " + r.bottom);
- }
-
- public void hideVirtualKeyboard(){
- this.imm.hideSoftInputFromWindow(this.getWindow().getDecorView().getWindowToken(), InputMethodManager.HIDE_IMPLICIT_ONLY);
- }
-
- public String[] listDirContents(String path){
- try {
- String[] list = getAssets().list(path);
-
- for(int i = 0; i != list.length; ++i){
- if(getAssets().list(path + "/" + list[i]).length > 0){
- //this is a directory
- list[i] += "/";
- }
- }
-
-// Log.d(LOGTAG, "file list = " + list);
- return list;
- }catch (IOException e){
- Log.d(LOGTAG, e.getMessage());
- }
- return null;
- }
-
- public String getStorageDir(){
- return this.getFilesDir().getPath();
- }
-}
diff --git a/build/android/app/src/main/java/io/github/cppfw/ruisapp/RuisappActivity.java b/build/android/app/src/main/java/io/github/cppfw/ruisapp/RuisappActivity.java
new file mode 120000
index 000000000..5fce9376a
--- /dev/null
+++ b/build/android/app/src/main/java/io/github/cppfw/ruisapp/RuisappActivity.java
@@ -0,0 +1 @@
+../../../../../../../../../../tests/harness/modules/ruisapp/build/android/ruisapp/src/main/java/io/github/cppfw/ruisapp/RuisappActivity.java
\ No newline at end of file
diff --git a/build/conan/conanfile.py b/build/conan/conanfile.py
index d82c04c79..b1b829d81 100644
--- a/build/conan/conanfile.py
+++ b/build/conan/conanfile.py
@@ -57,7 +57,7 @@ def source(self):
# shallow fetch commit
git.fetch_commit(url=sources["url"], commit=sources['commit'])
# shallow clone submodules
- git.run("submodule update --init --remote --depth 1")
+ git.run("submodule update --init --remote")
def build(self):
if self.settings.os == "Emscripten":
diff --git a/build/vcpkg/test/vcpkg-configuration.json b/build/vcpkg/test/vcpkg-configuration.json
index 42f6d2c85..242e5e3e3 100644
--- a/build/vcpkg/test/vcpkg-configuration.json
+++ b/build/vcpkg/test/vcpkg-configuration.json
@@ -8,7 +8,7 @@
{
"kind": "git",
"repository": "https://github.com/cppfw/vcpkg-repo/",
- "baseline": "d48205c0ac1f9dec582330ec79d145cdd5905949",
+ "baseline": "623f683b18c6f49a18104e1c52e7d3c17f38ef92",
"reference": "main",
"packages": [
"myci",
diff --git a/config/rel.mk b/config/rel.mk
index 5668adc2a..bdc5995ac 100644
--- a/config/rel.mk
+++ b/config/rel.mk
@@ -1,9 +1,19 @@
include $(config_dir)base/base.mk
+this_cxxflags += -O3
+
# TODO: compilation with -O3 currently fails with unjustified "maybe used uninitialized" error
# when building with "g++ (Debian 12.2.0-14) 12.2.0",
-# have't tried it with clang++. Need to restore -O3 when GCC is fixed.
-this_cxxflags += -O1
+# have't tried it with clang++. Need to remove this warning suppression when GCC is fixed.
+ifeq ($(this_cxx),g++)
+ ifeq ($(os),macosx)
+ # On macos, the this_cxx can be set to g++, but it is still clang compiler, becuase
+ # often, on macos the g++ is symlinked to clang++.
+ # Thus, on macos do not suppress the warning, because it is not supported by clang.
+ else
+ this_cxxflags += -Wno-maybe-uninitialized
+ endif
+endif
# WORKAROUND: on ubuntu jammy dpkg-buildpackage passes -ffat-lto-objects compilation flag
# which is not supported by clang and clang-tidy complains about it:
diff --git a/src/ruis/context.cpp b/src/ruis/context.cpp
index 046a21699..790ce4a52 100644
--- a/src/ruis/context.cpp
+++ b/src/ruis/context.cpp
@@ -25,17 +25,11 @@ along with this program. If not, see .
using namespace ruis;
-context::context(
- utki::shared_ref style_provider,
- utki::shared_ref updater,
- parameters params
-) :
+context::context(parameters params) :
post_to_ui_thread_function(std::move(params.post_to_ui_thread_function)),
- style_provider(std::move(style_provider)),
- res_loader(this->style_provider.get().res_loader),
- renderer(this->res_loader.get().renderer),
- updater(std::move(updater)),
- cursor_stack(std::move(params.set_mouse_cursor_function)),
+ style_provider(std::move(params.style_provider)),
+ renderer(std::move(params.renderer)),
+ updater(std::move(params.updater)),
localization(std::move(params.localization)),
units(std::move(params.units))
{
diff --git a/src/ruis/context.hpp b/src/ruis/context.hpp
index 24d8e1c11..64659f975 100644
--- a/src/ruis/context.hpp
+++ b/src/ruis/context.hpp
@@ -26,7 +26,6 @@ along with this program. If not, see .
#include "util/events.hpp"
#include "util/localization.hpp"
#include "util/mouse_cursor.hpp"
-#include "util/mouse_cursor_stack.hpp"
#include "util/units.hpp"
#include "resource_loader.hpp"
@@ -70,19 +69,13 @@ class context : public std::enable_shared_from_this
return this->style_provider.get();
}
- /**
- * @brief Resource loader.
- * Allows loading and managing life time of resources.
- */
- const utki::shared_ref res_loader;
-
/**
* @brief Shorthand alias for resource loader.
* @return this->res_loader.get().
*/
resource_loader& loader() noexcept
{
- return this->res_loader.get();
+ return this->style().res_loader.get();
}
/**
@@ -104,11 +97,20 @@ class context : public std::enable_shared_from_this
* @brief Shorthand alias for renderer.
* @return this->renderer.get().
*/
- const ruis::render::renderer& ren() const noexcept
+ ruis::render::renderer& ren() const noexcept
{
return this->renderer.get();
}
+ /**
+ * @brief Shorthand alias for native_window.
+ * @return The native window of this GUI context.
+ */
+ ruis::render::native_window& window() noexcept
+ {
+ return this->ren().ctx().native_window;
+ }
+
/**
* @brief Updater which updates updatables from within UI thread.
* The updater calls active updatables periodically from the UI thread.
@@ -116,12 +118,6 @@ class context : public std::enable_shared_from_this
// potentially, updater can be shared between contexts, this is why it is shared_ref
const utki::shared_ref updater;
- /**
- * @brief Mouse cursor stack.
- * It allows changing shape of the mouse cursor.
- */
- mouse_cursor_stack cursor_stack;
-
/**
* @brief current localization.
* Vocabulary of localized strings.
@@ -144,22 +140,18 @@ class context : public std::enable_shared_from_this
struct parameters {
std::function)> post_to_ui_thread_function;
- std::function set_mouse_cursor_function;
- ruis::units units;
+ utki::shared_ref updater;
+ utki::shared_ref renderer;
+ utki::shared_ref style_provider;
utki::shared_ref localization = utki::make_shared();
+ ruis::units units;
};
/**
* @brief Constructor.
- * @param style_provider - style provider to use for this context.
- * @param updater - updater to use along with this context.
* @param params - context parameters.
*/
- context(
- utki::shared_ref style_provider,
- utki::shared_ref updater,
- parameters params
- );
+ context(parameters params);
context(const context&) = delete;
context& operator=(const context&) = delete;
diff --git a/src/ruis/font/font.hpp b/src/ruis/font/font.hpp
index 326febc24..59cfe5df8 100644
--- a/src/ruis/font/font.hpp
+++ b/src/ruis/font/font.hpp
@@ -88,7 +88,8 @@ class font
* rendering.
*/
virtual render_result render_internal(
- const ruis::matrix4& matrix, //
+ render::renderer& renderer, //
+ const ruis::matrix4& matrix,
const ruis::color& color,
const std::u32string_view str,
unsigned tab_size,
@@ -132,7 +133,8 @@ class font
* @return Render result.
*/
render_result render(
- const ruis::matrix4& matrix, //
+ render::renderer& renderer, //
+ const ruis::matrix4& matrix,
const ruis::color& color,
const std::u32string_view str,
unsigned tab_size = 4,
@@ -140,7 +142,8 @@ class font
) const
{
return this->render_internal(
- matrix, //
+ renderer, //
+ matrix,
color,
str,
tab_size,
@@ -160,7 +163,8 @@ class font
* @return Render result.
*/
render_result render(
- const ruis::matrix4& matrix, //
+ render::renderer& renderer, //
+ const ruis::matrix4& matrix,
const ruis::color& color,
utki::utf8_iterator str,
unsigned tab_size = 4,
@@ -168,7 +172,8 @@ class font
) const
{
return this->render(
- matrix, //
+ renderer, //
+ matrix,
color,
utki::to_utf32(str),
tab_size,
@@ -188,6 +193,7 @@ class font
* @return Render result.
*/
render_result render(
+ render::renderer& renderer, //
const ruis::matrix4& matrix, //
const ruis::color& color,
const char* str,
@@ -196,9 +202,12 @@ class font
) const
{
return this->render(
- matrix, //
+ renderer, //
+ matrix,
color,
- utki::utf8_iterator(str)
+ utki::utf8_iterator(str),
+ tab_size,
+ offset
);
}
@@ -214,17 +223,19 @@ class font
* @return Redner result.
*/
render_result render(
+ render::renderer& renderer, //
const ruis::matrix4& matrix, //
const ruis::color& color,
- const std::string& str,
+ std::string_view str,
unsigned tab_size = 4,
size_t offset = std::numeric_limits::max()
) const
{
return this->render(
- matrix, //
+ renderer, //
+ matrix,
color,
- str.c_str(),
+ utki::utf8_iterator(str),
tab_size,
offset
);
diff --git a/src/ruis/font/texture_font.cpp b/src/ruis/font/texture_font.cpp
index 76adc7c09..1e59ac30b 100644
--- a/src/ruis/font/texture_font.cpp
+++ b/src/ruis/font/texture_font.cpp
@@ -173,19 +173,19 @@ texture_font::glyph texture_font::load_glyph(char32_t c) const
g.top_left = ftg.vertices[0];
g.bottom_right = ftg.vertices[2];
- auto& r = this->renderer.get();
+ auto& rc = this->rendering_context.get();
// clang-format off
- g.vao = r.render_context.get().make_vertex_array(
+ g.vao = rc.make_vertex_array(
{
- r.render_context.get().make_vertex_buffer(utki::make_span(ftg.vertices)),
- this->renderer.get().obj().quad_01_vbo
+ rc.make_vertex_buffer(utki::make_span(ftg.vertices)),
+ this->common_rendering_objects.get().quad_01_vbo
},
- this->renderer.get().obj().quad_fan_indices,
+ this->common_rendering_objects.get().quad_fan_indices,
render::vertex_array::mode::triangle_fan
).to_shared_ptr();
- g.tex = this->renderer.get().render_context.get().make_texture_2d(
+ g.tex = rc.make_texture_2d(
std::move(ftg.image),
{
.min_filter = render::texture_2d::filter::nearest,
@@ -199,15 +199,16 @@ texture_font::glyph texture_font::load_glyph(char32_t c) const
}
texture_font::texture_font(
- utki::shared_ref renderer,
- // NOLINTNEXTLINE(modernize-pass-by-value)
- const utki::shared_ref& face,
+ utki::shared_ref rendering_context, //
+ utki::shared_ref common_rendering_objects,
+ utki::shared_ref face,
unsigned font_size,
unsigned max_cached
) :
- renderer(std::move(renderer)),
+ rendering_context(std::move(rendering_context)),
+ common_rendering_objects(std::move(common_rendering_objects)),
font_size(font_size),
- face(face),
+ face(std::move(face)),
max_cached(max_cached)
{
// TRACE(<< "texture_font::Load(): enter" << std::endl)
@@ -253,7 +254,8 @@ const texture_font::glyph& texture_font::get_glyph(char32_t c) const
}
real texture_font::render_glyph_internal(
- const ruis::matrix4& matrix, //
+ render::renderer& renderer, //
+ const ruis::matrix4& matrix,
const ruis::color& color,
char32_t ch
) const
@@ -263,7 +265,7 @@ real texture_font::render_glyph_internal(
// texture can be null for glyph of empty characters, like space, tab etc...
if (g.tex) {
ASSERT(g.vao)
- this->renderer.get().shaders().color_pos_tex_alpha->render(
+ renderer.shaders().color_pos_tex_alpha->render(
matrix, //
*g.vao,
color,
@@ -337,6 +339,7 @@ ruis::rect texture_font::get_bounding_box_internal(std::u32string_view str, unsi
}
font::render_result texture_font::render_internal(
+ render::renderer& renderer, //
const ruis::matrix4& matrix,
const ruis::color& color,
const std::u32string_view str,
@@ -350,7 +353,7 @@ font::render_result texture_font::render_internal(
return ret;
}
- this->renderer.get().render_context.get().set_simple_alpha_blending();
+ renderer.rendering_context.get().set_simple_alpha_blending();
ruis::matrix4 matr(matrix);
@@ -374,7 +377,12 @@ font::render_result texture_font::render_internal(
cur_offset += actual_tab_size;
return advance;
} else { // all other characters
- auto advance = this->render_glyph_internal(matr, color, c);
+ auto advance = this->render_glyph_internal(
+ renderer, //
+ matr,
+ color,
+ c
+ );
++ret.length;
++cur_offset;
return advance;
diff --git a/src/ruis/font/texture_font.hxx b/src/ruis/font/texture_font.hxx
index 84a8a0a52..d3074dc15 100644
--- a/src/ruis/font/texture_font.hxx
+++ b/src/ruis/font/texture_font.hxx
@@ -104,7 +104,8 @@ public:
*/
class texture_font : public font
{
- const utki::shared_ref renderer;
+ const utki::shared_ref rendering_context;
+ const utki::shared_ref common_rendering_objects;
const unsigned font_size;
@@ -142,17 +143,22 @@ public:
* @param max_cached - maximum number of glyphs to cache.
*/
texture_font(
- utki::shared_ref renderer,
- const utki::shared_ref& face,
+ utki::shared_ref rendering_context, //
+ utki::shared_ref common_rendering_objects,
+ utki::shared_ref face,
unsigned font_size,
unsigned max_cached
);
- real get_advance(char32_t c, unsigned tab_size) const override;
+ real get_advance(
+ char32_t c, //
+ unsigned tab_size
+ ) const override;
protected:
render_result render_internal(
- const ruis::matrix4& matrix, //
+ render::renderer& renderer, //
+ const ruis::matrix4& matrix,
const ruis::color& color,
const std::u32string_view str,
unsigned tab_size,
@@ -171,7 +177,8 @@ protected:
private:
real render_glyph_internal(
- const ruis::matrix4& matrix, //
+ render::renderer& renderer, //
+ const ruis::matrix4& matrix,
const ruis::color& color,
char32_t ch
) const;
diff --git a/src/ruis/font/texture_font_provider.cpp b/src/ruis/font/texture_font_provider.cpp
index c82b70671..6134fd233 100644
--- a/src/ruis/font/texture_font_provider.cpp
+++ b/src/ruis/font/texture_font_provider.cpp
@@ -24,20 +24,22 @@ along with this program. If not, see .
using namespace ruis;
texture_font_provider::texture_font_provider(
- utki::shared_ref renderer,
- // NOLINTNEXTLINE(modernize-pass-by-value)
- const utki::shared_ref& face,
+ utki::shared_ref rendering_context, //
+ utki::shared_ref common_rendering_objects,
+ utki::shared_ref face,
unsigned max_cached
) :
- renderer(std::move(renderer)),
- face(face),
+ rendering_context(std::move(rendering_context)),
+ common_rendering_objects(std::move(common_rendering_objects)),
+ face(std::move(face)),
max_cached(max_cached)
{}
utki::shared_ref texture_font_provider::create(real size) const
{
return utki::make_shared(
- this->renderer, //
+ this->rendering_context, //
+ this->common_rendering_objects,
this->face,
unsigned(size),
max_cached
diff --git a/src/ruis/font/texture_font_provider.hxx b/src/ruis/font/texture_font_provider.hxx
index 97e8b92ed..828913edf 100644
--- a/src/ruis/font/texture_font_provider.hxx
+++ b/src/ruis/font/texture_font_provider.hxx
@@ -28,15 +28,17 @@ namespace ruis {
class texture_font_provider : public font_provider
{
- const utki::shared_ref renderer;
+ const utki::shared_ref rendering_context;
+ const utki::shared_ref common_rendering_objects;
const utki::shared_ref face;
const unsigned max_cached;
public:
texture_font_provider(
- utki::shared_ref renderer,
- const utki::shared_ref& face,
+ utki::shared_ref rendering_context, //
+ utki::shared_ref common_rendering_objects,
+ utki::shared_ref face,
unsigned max_cached
);
diff --git a/src/ruis/gui.cpp b/src/ruis/gui.cpp
index ba5f90077..67079f57c 100644
--- a/src/ruis/gui.cpp
+++ b/src/ruis/gui.cpp
@@ -28,8 +28,8 @@ along with this program. If not, see .
using namespace ruis;
// NOLINTNEXTLINE(modernize-pass-by-value)
-gui::gui(const utki::shared_ref& context) :
- context(context),
+gui::gui(utki::shared_ref context) :
+ context(std::move(context)),
root_widget(ruis::make::gap(this->context, {}))
{}
@@ -88,11 +88,23 @@ void gui::init_standard_widgets(papki::file& fi)
}
}
-void gui::set_viewport(const ruis::vector2& size)
+void gui::set_viewport(const ruis::rect& rect)
{
- this->viewport_size = size;
+ if (this->viewport_rect == rect) {
+ return;
+ }
+
+ this->context.get().ren().ctx().apply([&]() {
+ this->viewport_rect = rect;
+
+ utki::log_debug([&](auto& o) {
+ o << "gui::set_viewport(): new viewport retangle = " << this->viewport_rect << std::endl;
+ });
+
+ this->context.get().ren().ctx().set_viewport(this->viewport_rect.to());
- this->root_widget.get().resize(this->viewport_size);
+ this->root_widget.get().resize(this->viewport_rect.d);
+ });
}
void gui::set_root(utki::shared_ref w)
@@ -101,10 +113,14 @@ void gui::set_root(utki::shared_ref w)
throw std::invalid_argument("given widget is already added to some container");
}
+ if (w.get().context.to_shared_ptr() != this->context.to_shared_ptr()) {
+ throw std::invalid_argument("cannot set root widget from another GUI context");
+ }
+
this->root_widget = std::move(w);
this->root_widget.get().move_to(ruis::vector2(0));
- this->root_widget.get().resize(this->viewport_size);
+ this->root_widget.get().resize(this->viewport_rect.d);
}
void gui::render(const matrix4& matrix) const
@@ -117,12 +133,18 @@ void gui::render(const matrix4& matrix) const
this->root_widget.get().lay_out();
}
- ruis::matrix4 m = make_viewport_matrix(matrix, this->viewport_size);
+ ruis::matrix4 m = make_viewport_matrix(
+ matrix, //
+ this->viewport_rect.d
+ );
this->get_root().render_internal(m);
}
-void gui::send_mouse_move(const vector2& pos, unsigned id)
+void gui::send_mouse_move(
+ const vector2& pos, //
+ unsigned id
+)
{
auto& rw = this->get_root();
if (rw.is_interactive()) {
@@ -131,7 +153,12 @@ void gui::send_mouse_move(const vector2& pos, unsigned id)
}
}
-void gui::send_mouse_button(bool is_down, const vector2& pos, mouse_button button, unsigned id)
+void gui::send_mouse_button(
+ bool is_down, //
+ const vector2& pos,
+ mouse_button button,
+ unsigned id
+)
{
auto& rw = this->get_root();
if (rw.is_interactive()) {
@@ -140,12 +167,18 @@ void gui::send_mouse_button(bool is_down, const vector2& pos, mouse_button butto
}
}
-void gui::send_mouse_hover(bool is_hovered, unsigned pointer_id)
+void gui::send_mouse_hover(
+ bool is_hovered, //
+ unsigned pointer_id
+)
{
this->get_root().set_hovered(is_hovered, pointer_id);
}
-void gui::send_key(bool is_down, key key_code)
+void gui::send_key(
+ bool is_down, //
+ key key_code
+)
{
// TRACE(<< "HandleKeyEvent(): is_down = " << is_down << " is_char_input_only = " << is_char_input_only << "
// keyCode = " << unsigned(keyCode) << std::endl)
@@ -169,16 +202,19 @@ void gui::send_key(bool is_down, key key_code)
}
}
-void gui::send_character_input(const input_string_provider& string_provider, key key_code)
+void gui::send_character_input(
+ const input_string_provider& string_provider, //
+ key key_code
+)
{
if (auto w = this->context.get().focused_widget.lock()) {
- character_input_event e;
- auto str = string_provider.get();
- e.string = str;
- e.combo.key = key_code;
- e.combo.modifiers = this->key_modifiers;
-
if (auto c = dynamic_cast(w.get())) {
+ character_input_event e;
+ auto str = string_provider.get();
+ e.string = str;
+ e.combo.key = key_code;
+ e.combo.modifiers = this->key_modifiers;
+
c->on_character_input(e);
}
}
diff --git a/src/ruis/gui.hpp b/src/ruis/gui.hpp
index c01418550..58b813bed 100644
--- a/src/ruis/gui.hpp
+++ b/src/ruis/gui.hpp
@@ -38,7 +38,7 @@ class gui final
* @brief Constructor.
* @param context - ruis context to use for this gui instance.
*/
- gui(const utki::shared_ref& context);
+ gui(utki::shared_ref context);
gui(const gui&) = delete;
gui& operator=(const gui&) = delete;
@@ -81,15 +81,15 @@ class gui final
}
private:
- vector2 viewport_size{0, 0};
+ ruis::rect viewport_rect = {0, 0, 0, 0};
public:
/**
- * @brief Set viewport size for GUI.
- * Set the dimensions of the rectangular area where GUI will be rendered.
- * @param size - dimensions of the viewport, in pixels.
+ * @brief Set viewport rectangle.
+ * Set the rectangular area within the native window where GUI will be rendered.
+ * @param rect - viewport rectangle within the native window, in pixels.
*/
- void set_viewport(const ruis::vector2& size);
+ void set_viewport(const ruis::rect& rect);
/**
* @brief Render GUI.
@@ -108,18 +108,9 @@ class gui final
* widgets to be used by application.
* @param fi - file interface to use for resource loading.
*/
+ // TODO: make free function taking context as argument
void init_standard_widgets(papki::file& fi);
- /**
- * @brief Update GUI.
- * Call this function from main loop of the program.
- * @return number of milliseconds to sleep before next call.
- */
- uint32_t update()
- {
- return this->context.get().updater.get().update();
- }
-
/**
* @brief Feed in the mouse move event to GUI.
* @param pos - new position of the mouse pointer.
@@ -188,7 +179,10 @@ class gui final
* @param string_provider - input string provider.
* @param key_code - key code associated with character input, can be unknown.
*/
- void send_character_input(const input_string_provider& string_provider, ruis::key key_code);
+ void send_character_input(
+ const input_string_provider& string_provider, //
+ ruis::key key_code
+ );
};
} // namespace ruis
diff --git a/src/ruis/paint/frame_vao.cpp b/src/ruis/paint/frame_vao.cpp
index 641abf920..f5f74050a 100644
--- a/src/ruis/paint/frame_vao.cpp
+++ b/src/ruis/paint/frame_vao.cpp
@@ -48,11 +48,11 @@ void frame_vao::set(vector2 dims, vector2 thickness)
// NOLINTNEXTLINE(cppcoreguidelines-avoid-magic-numbers)
std::array indices = {0, 4, 1, 5, 2, 6, 3, 7, 0, 4};
- this->vao = this->renderer.get().render_context.get().make_vertex_array(
+ this->vao = this->renderer.get().rendering_context.get().make_vertex_array(
{
- this->renderer.get().render_context.get().make_vertex_buffer(vertices),
+ this->renderer.get().rendering_context.get().make_vertex_buffer(vertices),
},
- this->renderer.get().render_context.get().make_index_buffer(indices),
+ this->renderer.get().rendering_context.get().make_index_buffer(indices),
ruis::render::vertex_array::mode::triangle_strip
);
}
diff --git a/src/ruis/paint/path_vao.cpp b/src/ruis/paint/path_vao.cpp
index bacd85025..22054b7e9 100644
--- a/src/ruis/paint/path_vao.cpp
+++ b/src/ruis/paint/path_vao.cpp
@@ -32,21 +32,21 @@ path_vao::path_vao(const utki::shared_ref& r) :
void path_vao::set(const path::vertices& path)
{
- auto core_buf = this->renderer.get().render_context.get().make_vertex_buffer(path.pos);
+ auto core_buf = this->renderer.get().rendering_context.get().make_vertex_buffer(path.pos);
- this->core = this->renderer.get().render_context.get().make_vertex_array(
+ this->core = this->renderer.get().rendering_context.get().make_vertex_array(
{
core_buf,
},
- this->renderer.get().render_context.get().make_index_buffer(path.in_indices),
+ this->renderer.get().rendering_context.get().make_index_buffer(path.in_indices),
ruis::render::vertex_array::mode::triangle_strip
);
- this->border = this->renderer.get().render_context.get().make_vertex_array(
+ this->border = this->renderer.get().rendering_context.get().make_vertex_array(
{
core_buf,
- this->renderer.get().render_context.get().make_vertex_buffer(path.alpha),
+ this->renderer.get().rendering_context.get().make_vertex_buffer(path.alpha),
},
- this->renderer.get().render_context.get().make_index_buffer(path.out_indices),
+ this->renderer.get().rendering_context.get().make_index_buffer(path.out_indices),
ruis::render::vertex_array::mode::triangle_strip
);
}
diff --git a/src/ruis/render/context.cpp b/src/ruis/render/context.cpp
index 5e7af0393..c89f05b57 100644
--- a/src/ruis/render/context.cpp
+++ b/src/ruis/render/context.cpp
@@ -23,18 +23,72 @@ along with this program. If not, see .
using namespace ruis::render;
-context::context(parameters params) :
+std::vector ruis::render::context::cur_context_stack;
+
+context::context(
+ utki::shared_ref native_window, //
+ parameters params
+) :
+ native_window(std::move(native_window)),
initial_matrix(std::move(params.initial_matrix))
-{}
+{
+ // insert this context to the bottom of the current contexts stack
+ cur_context_stack.insert(cur_context_stack.begin(), this);
+
+ if (this->is_current()) {
+ // this context is the first one created, so it should become current
+ this->native_window.get().bind_rendering_context();
+ }
+}
+
+context::~context()
+{
+ if (this->is_current()) {
+ cur_context_stack.pop_back();
+ }
+
+ // remove all occurrencies of this context from current contexts stack,
+ // because there can be several of them
+ cur_context_stack.erase(
+ std::remove(
+ cur_context_stack.begin(), //
+ cur_context_stack.end(),
+ this
+ ),
+ cur_context_stack.end()
+ );
+
+ if (!cur_context_stack.empty()) {
+ cur_context_stack.back()->native_window.get().bind_rendering_context();
+ }
+}
void context::apply(std::function func)
{
+ utki::assert(func, SL);
+
if (this->is_current()) {
+ // this context is already current
func();
return;
}
- throw std::logic_error("context::apply(): the context is non-current, switching context is not yet implemented");
+ cur_context_stack.push_back(this);
+
+ utki::scope_exit restore_old_current_context_scope_exit([&]() {
+ utki::assert(this->is_current(), SL);
+ cur_context_stack.pop_back();
+ if (!cur_context_stack.empty()) {
+ // bind the previous context
+ cur_context_stack.back()->native_window.get().bind_rendering_context();
+ }
+ });
+
+ this->native_window.get().bind_rendering_context();
+
+ utki::assert(this->is_current(), SL);
+
+ func();
}
void context::set_framebuffer(frame_buffer* fb)
diff --git a/src/ruis/render/context.hpp b/src/ruis/render/context.hpp
index f06422013..ae6e4b3e1 100644
--- a/src/ruis/render/context.hpp
+++ b/src/ruis/render/context.hpp
@@ -21,6 +21,8 @@ along with this program. If not, see .
#pragma once
+#include
+
#include
#include
@@ -30,6 +32,7 @@ along with this program. If not, see .
#include "shaders/texturing_shader.hpp"
#include "frame_buffer.hpp"
+#include "native_window.hpp"
#include "texture_cube.hpp"
#include "texture_depth.hpp"
@@ -38,16 +41,26 @@ class context : public std::enable_shared_from_this
{
friend class frame_buffer;
+ // Context destruction is rare, so removing from the middle of stack is rare, ok to use std::vector.
+ static std::vector cur_context_stack;
+
protected:
utki::shared_ref get_shared_ref()
{
- return utki::make_shared_from(*this);
+ return utki::shared_ref(this->shared_from_this());
+ }
+
+ utki::shared_ref get_shared_ref() const
+ {
+ return utki::shared_ref(this->shared_from_this());
}
private:
std::weak_ptr cur_fb;
public:
+ const utki::shared_ref native_window;
+
struct parameters {
r4::matrix4 initial_matrix;
};
@@ -59,7 +72,10 @@ class context : public std::enable_shared_from_this
*/
const r4::matrix4 initial_matrix;
- context(parameters params);
+ context(
+ utki::shared_ref, //
+ parameters params
+ );
context(const context&) = delete;
context& operator=(const context&) = delete;
@@ -67,24 +83,28 @@ class context : public std::enable_shared_from_this
context(context&&) = delete;
context& operator=(context&&) = delete;
- virtual ~context() = default;
+ virtual ~context();
bool is_current() const noexcept
{
- // TODO: actually check that the context is current
- return true;
+ // if at least one context exists then the cur_context_stack is not empty
+ utki::assert(!cur_context_stack.empty(), SL);
+ return cur_context_stack.back() == this;
}
/**
* @brief Execute procedure with this context made current.
+ * Previous context will be restored to be current after procedure execution.
* @param proc - procedure to execute.
*/
+ // TODO: make argument generic callable instead of std::function? i.e. template method for compiler optimizations?
void apply(std::function proc);
// ===============================
// ====== factory functions ======
struct shaders {
+ // TODO: make unique_ref
std::unique_ptr pos_tex;
std::unique_ptr color_pos;
std::unique_ptr color_pos_lum;
@@ -93,7 +113,7 @@ class context : public std::enable_shared_from_this
std::unique_ptr color_pos_tex_alpha;
};
- virtual utki::shared_ref make_shaders() = 0;
+ virtual utki::shared_ref make_shaders() const = 0;
struct texture_2d_parameters {
texture_2d::filter min_filter = texture_2d::filter::nearest;
@@ -105,19 +125,20 @@ class context : public std::enable_shared_from_this
rasterimage::format format,
rasterimage::dimensioned::dimensions_type dims,
texture_2d_parameters params
- ) = 0;
+ ) const = 0;
virtual utki::shared_ref make_texture_2d(
const rasterimage::image_variant& imvar,
texture_2d_parameters params
- ) = 0;
+ ) const = 0;
virtual utki::shared_ref make_texture_2d(
rasterimage::image_variant&& imvar,
texture_2d_parameters params
- ) = 0;
+ ) const = 0;
- virtual utki::shared_ref make_texture_depth(rasterimage::dimensioned::dimensions_type dims) = 0;
+ virtual utki::shared_ref make_texture_depth(rasterimage::dimensioned::dimensions_type dims
+ ) const = 0;
virtual utki::shared_ref make_texture_cube(
rasterimage::image_variant&& positive_x,
@@ -126,25 +147,21 @@ class context : public std::enable_shared_from_this
rasterimage::image_variant&& negative_y,
rasterimage::image_variant&& positive_z,
rasterimage::image_variant&& negative_z
- ) = 0;
-
- virtual utki::shared_ref make_vertex_buffer(utki::span> vertices) = 0;
-
- virtual utki::shared_ref make_vertex_buffer(utki::span> vertices) = 0;
+ ) const = 0;
- virtual utki::shared_ref make_vertex_buffer(utki::span> vertices) = 0;
+ virtual utki::shared_ref make_vertex_buffer(utki::span> vertices) const = 0;
+ virtual utki::shared_ref make_vertex_buffer(utki::span> vertices) const = 0;
+ virtual utki::shared_ref make_vertex_buffer(utki::span> vertices) const = 0;
+ virtual utki::shared_ref make_vertex_buffer(utki::span vertices) const = 0;
- virtual utki::shared_ref make_vertex_buffer(utki::span vertices) = 0;
-
- virtual utki::shared_ref make_index_buffer(utki::span indices) = 0;
-
- virtual utki::shared_ref make_index_buffer(utki::span indices) = 0;
+ virtual utki::shared_ref make_index_buffer(utki::span indices) const = 0;
+ virtual utki::shared_ref make_index_buffer(utki::span indices) const = 0;
virtual utki::shared_ref make_vertex_array(
std::vector> buffers,
utki::shared_ref indices,
vertex_array::mode rendering_mode
- ) = 0;
+ ) const = 0;
virtual utki::shared_ref make_framebuffer( //
std::shared_ptr color,
@@ -167,7 +184,7 @@ class context : public std::enable_shared_from_this
* @brief Get current frame buffer.
* @return Current frame buffer. If nullptr, then it is a screen buffer.
*/
- std::shared_ptr get_framebuffer()
+ std::shared_ptr get_framebuffer() const
{
return this->cur_fb.lock();
}
@@ -201,7 +218,7 @@ class context : public std::enable_shared_from_this
* should be interpreted in context of the specific renderer.
* @return Window coordinates of the point.
*/
- virtual r4::vector2 to_window_coords(ruis::vec2 point) const = 0;
+ virtual r4::vector2 to_window_coords(const ruis::vec2& point) const = 0;
/**
* @brief Check if scissor test is enabled.
@@ -231,7 +248,7 @@ class context : public std::enable_shared_from_this
* TODO:
* @param r - new scissor rectangle.
*/
- virtual void set_scissor(r4::rectangle r) = 0;
+ virtual void set_scissor(const r4::rectangle& r) = 0;
/**
* @brief Get current rendering viewport within application window.
@@ -255,7 +272,7 @@ class context : public std::enable_shared_from_this
* covering the whole framebuffer.
* @param r - new viewport rectangle.
*/
- virtual void set_viewport(r4::rectangle r) = 0;
+ virtual void set_viewport(const r4::rectangle& r) = 0;
virtual void enable_blend(bool enable) = 0;
diff --git a/src/ruis/render/frame_buffer.cpp b/src/ruis/render/frame_buffer.cpp
index 12784c38a..83a8160a4 100644
--- a/src/ruis/render/frame_buffer.cpp
+++ b/src/ruis/render/frame_buffer.cpp
@@ -28,7 +28,7 @@ along with this program. If not, see .
using namespace ruis::render;
frame_buffer::frame_buffer( //
- utki::shared_ref render_context,
+ utki::shared_ref rendering_context,
std::shared_ptr color,
std::shared_ptr depth,
std::shared_ptr stencil
@@ -60,7 +60,7 @@ frame_buffer::frame_buffer( //
return cur_tex->dims();
}()),
- render_context(std::move(render_context)),
+ rendering_context(std::move(rendering_context)),
color(std::move(color)),
depth(std::move(depth)),
stencil(std::move(stencil))
@@ -68,9 +68,9 @@ frame_buffer::frame_buffer( //
void frame_buffer::apply(std::function func)
{
- auto& rc = this->render_context.get();
+ auto& rc = this->rendering_context.get();
if (!rc.is_current()) {
- throw std::logic_error("framebuffer::apply(): the framebuffer's render_context is not current");
+ throw std::logic_error("framebuffer::apply(): the framebuffer's rendering_context is not current");
}
utki::scope_exit framebuffer_scope_exit([old_framebuffer = rc.get_framebuffer(), &rc]() {
diff --git a/src/ruis/render/frame_buffer.hpp b/src/ruis/render/frame_buffer.hpp
index 26942ab36..1ac9c0bf9 100644
--- a/src/ruis/render/frame_buffer.hpp
+++ b/src/ruis/render/frame_buffer.hpp
@@ -37,16 +37,18 @@ class frame_buffer :
public std::enable_shared_from_this
{
protected:
+ // in OpneGL framebuffer objects are not shared between contexts,
+ // so the reference stored here is for non-const context object which owns the framebuffer
+ const utki::shared_ref rendering_context;
+
frame_buffer( //
- utki::shared_ref render_context,
+ utki::shared_ref rendering_context,
std::shared_ptr color,
std::shared_ptr depth,
std::shared_ptr stencil
);
public:
- const utki::shared_ref render_context;
-
const std::shared_ptr color;
const std::shared_ptr depth;
const std::shared_ptr stencil;
diff --git a/src/ruis/render/index_buffer.hpp b/src/ruis/render/index_buffer.hpp
index 131f9a4c6..139897792 100644
--- a/src/ruis/render/index_buffer.hpp
+++ b/src/ruis/render/index_buffer.hpp
@@ -29,14 +29,14 @@ class context;
class index_buffer
{
+ const utki::shared_ref rendering_context;
+
protected:
- index_buffer(utki::shared_ref render_context) :
- render_context(std::move(render_context))
+ index_buffer(utki::shared_ref rendering_context) :
+ rendering_context(std::move(rendering_context))
{}
public:
- const utki::shared_ref render_context;
-
index_buffer(const index_buffer&) = delete;
index_buffer& operator=(const index_buffer&) = delete;
diff --git a/src/ruis/util/mouse_cursor_stack.cpp b/src/ruis/render/native_window.cpp
similarity index 66%
rename from src/ruis/util/mouse_cursor_stack.cpp
rename to src/ruis/render/native_window.cpp
index eff75eeb4..8d62bf41d 100644
--- a/src/ruis/util/mouse_cursor_stack.cpp
+++ b/src/ruis/render/native_window.cpp
@@ -19,23 +19,24 @@ along with this program. If not, see .
/* ================ LICENSE END ================ */
-#include "mouse_cursor_stack.hpp"
+#include "native_window.hpp"
#include
-using namespace ruis;
+using namespace ruis::render;
-mouse_cursor_stack::mouse_cursor_stack(std::function set_mouse_cursor) :
- set_mouse_cursor(std::move(set_mouse_cursor))
+void native_window::set_fullscreen(bool enable)
{
- if (!this->set_mouse_cursor) {
- throw std::invalid_argument( //
- "mouse_cursor_stack::mouse_cursor_stack(): set_mouse_cursor function cannot be null"
- );
+ if (enable == this->is_fullscreen()) {
+ return;
}
+
+ this->set_fullscreen_internal(enable);
+
+ this->is_fullscreen_v = enable;
}
-decltype(mouse_cursor_stack::cursor_stack)::iterator mouse_cursor_stack::push(mouse_cursor cursor)
+native_window::cursor_id native_window::push_mouse_cursor(mouse_cursor cursor)
{
this->cursor_stack.push_front(cursor);
@@ -44,9 +45,9 @@ decltype(mouse_cursor_stack::cursor_stack)::iterator mouse_cursor_stack::push(mo
return this->cursor_stack.begin();
}
-void mouse_cursor_stack::pop(decltype(cursor_stack)::iterator i)
+void native_window::pop_mouse_cursor(cursor_id i)
{
- ASSERT(this->cursor_stack.size() > 1)
+ utki::assert(this->cursor_stack.size() > 1, SL);
bool top_cursor = i == this->cursor_stack.begin();
this->cursor_stack.erase(i);
diff --git a/src/ruis/render/native_window.hpp b/src/ruis/render/native_window.hpp
new file mode 100644
index 000000000..394ff0304
--- /dev/null
+++ b/src/ruis/render/native_window.hpp
@@ -0,0 +1,88 @@
+/*
+ruis - GUI framework
+
+Copyright (C) 2012-2025 Ivan Gagis
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see .
+*/
+
+/* ================ LICENSE END ================ */
+
+#pragma once
+
+#include
+#include
+
+#include "../util/mouse_cursor.hpp"
+
+namespace ruis::render {
+class context;
+
+// TODO: doxygen
+class native_window
+{
+ friend class ruis::render::context;
+
+ bool is_fullscreen_v = false;
+
+ virtual void bind_rendering_context() {}
+
+ virtual void set_fullscreen_internal(bool enable) {}
+
+ std::list cursor_stack = {mouse_cursor::arrow};
+
+ virtual void set_mouse_cursor(ruis::mouse_cursor c) {}
+
+public:
+ native_window() = default;
+
+ native_window(const native_window&) = delete;
+ native_window& operator=(const native_window&) = delete;
+
+ native_window(native_window&&) = delete;
+ native_window& operator=(native_window&&) = delete;
+
+ virtual ~native_window() = default;
+
+ // TODO: make private somehow?
+ virtual void swap_frame_buffers() {}
+
+ void set_fullscreen(bool enable);
+
+ bool is_fullscreen() const noexcept
+ {
+ return this->is_fullscreen_v;
+ }
+
+ // TODO: add set_maximized(bool) & is_maximized()
+ // TODO: add set_minimized(bool) & is_minimized()
+ // TODO: add set_hidden(bool) & is_hidden()
+
+ /**
+ * @brief Handler of window close event.
+ * Invoked when user tries to close the window, e.g. by clicking the window's close button.
+ */
+ std::function close_handler;
+
+ // ================
+ // = mouse cursor =
+
+ using cursor_id = decltype(cursor_stack)::iterator;
+
+ cursor_id push_mouse_cursor(mouse_cursor cursor);
+ void pop_mouse_cursor(cursor_id i);
+
+ virtual void set_mouse_cursor_visible(bool visible) {}
+};
+} // namespace ruis::render
diff --git a/src/ruis/render/renderer.cpp b/src/ruis/render/renderer.cpp
index 06c9d780c..4e442eaed 100644
--- a/src/ruis/render/renderer.cpp
+++ b/src/ruis/render/renderer.cpp
@@ -25,62 +25,55 @@ along with this program. If not, see .
using namespace ruis::render;
-renderer::renderer(utki::shared_ref render_context) :
- render_context(std::move(render_context)),
- common_objects(utki::make_shared([this]() -> objects {
- // clang-format off
- objects self{
- .shaders = this->render_context.get().make_shaders(),
- .empty_vertex_array = this->render_context.get().make_vertex_array(
- {
- this->render_context.get().make_vertex_buffer(utki::span>())
- },
- this->render_context.get().make_index_buffer(utki::span()),
- ruis::render::vertex_array::mode::triangle_strip
- ),
- .quad_01_vbo = this->render_context.get().make_vertex_buffer(
- utki::make_span(std::array{
- vec2(0, 0),
- vec2(0, 1),
- vec2(1, 1),
- vec2(1, 0)
- })
- ),
- .quad_fan_indices = this->render_context.get().make_index_buffer(
- utki::make_span(std::array{0, 1, 2, 3})
- ),
- .pos_quad_01_vao = this->render_context.get().make_vertex_array(
- {self.quad_01_vbo},
- self.quad_fan_indices,
- vertex_array::mode::triangle_fan
- ),
- .pos_tex_quad_01_vao = this->render_context.get().make_vertex_array(
- {
- self.quad_01_vbo,
- self.quad_01_vbo
- },
- self.quad_fan_indices,
- vertex_array::mode::triangle_fan
- ),
- .white_texture = this->render_context.get().make_texture_2d(
- []() {
- // raster image 1 by 1 pixel
- rasterimage::image_variant imvar(
- {1, 1}, //
- rasterimage::format::rgba,
- rasterimage::depth::uint_8_bit
- );
+renderer::renderer(
+ utki::shared_ref rendering_context, //
+ utki::shared_ref common_shaders,
+ utki::shared_ref common_objects
+) :
+ rendering_context(std::move(rendering_context)),
+ common_shaders(std::move(common_shaders)),
+ common_objects(std::move(common_objects))
+{}
+
+renderer::objects::objects(const ruis::render::context& rendering_context) :
+ empty_vertex_array(rendering_context.make_vertex_array(
+ {//
+ rendering_context.make_vertex_buffer(utki::span>())
+ },
+ rendering_context.make_index_buffer(utki::span()),
+ ruis::render::vertex_array::mode::triangle_strip
+ )),
+ quad_01_vbo(rendering_context.make_vertex_buffer(utki::make_span(std::array{
+ vec2(0, 0), //
+ vec2(0, 1),
+ vec2(1, 1),
+ vec2(1, 0)
+ }))),
+ quad_fan_indices(rendering_context.make_index_buffer(utki::make_span(std::array{0, 1, 2, 3}))),
+ pos_quad_01_vao(rendering_context.make_vertex_array(
+ {this->quad_01_vbo},
+ this->quad_fan_indices,
+ vertex_array::mode::triangle_fan
+ )),
+ pos_tex_quad_01_vao(rendering_context.make_vertex_array(
+ {this->quad_01_vbo, this->quad_01_vbo},
+ this->quad_fan_indices,
+ vertex_array::mode::triangle_fan
+ )),
+ white_texture(rendering_context.make_texture_2d(
+ []() {
+ // raster image 1 by 1 pixel
+ rasterimage::image_variant imvar(
+ {1, 1}, //
+ rasterimage::format::rgba,
+ rasterimage::depth::uint_8_bit
+ );
- auto& im = imvar.get();
- constexpr auto opaque_white =
- std::remove_reference_t::pixel_type{0xff, 0xff, 0xff, 0xff};
- im[0][0] = opaque_white;
- return imvar;
- }(),
- {}
- )
- };
- // clang-format on
- return self;
- }()))
+ auto& im = imvar.get();
+ constexpr auto opaque_white = std::remove_reference_t::pixel_type{0xff, 0xff, 0xff, 0xff};
+ im[0][0] = opaque_white;
+ return imvar;
+ }(),
+ {}
+ ))
{}
diff --git a/src/ruis/render/renderer.hpp b/src/ruis/render/renderer.hpp
index 6458befef..1bb736e88 100644
--- a/src/ruis/render/renderer.hpp
+++ b/src/ruis/render/renderer.hpp
@@ -28,29 +28,31 @@ namespace ruis::render {
class renderer : public std::enable_shared_from_this
{
public:
- const utki::shared_ref render_context;
+ const utki::shared_ref rendering_context;
/**
* @brief Shorthand alias for render context.
- * @return this->render_context.get().
+ * @return this->rendering_context.get().
*/
ruis::render::context& ctx() noexcept
{
- return this->render_context.get();
+ return this->rendering_context.get();
}
/**
* @brief Shorthand alias for render context.
- * @return this->render_context.get().
+ * @return this->rendering_context.get().
*/
- // TODO: return const ref?
ruis::render::context& ctx() const noexcept
{
- return this->render_context.get();
+ return this->rendering_context.get();
}
+ const utki::shared_ref common_shaders;
+
struct objects {
- utki::shared_ref shaders;
+ objects(const ruis::render::context& rendering_context);
+
utki::shared_ref empty_vertex_array;
/**
@@ -75,14 +77,13 @@ class renderer : public std::enable_shared_from_this
const ruis::render::context::shaders& shaders() const noexcept
{
- return this->common_objects.get().shaders.get();
+ return this->common_shaders.get();
}
- renderer(utki::shared_ref render_context);
-
renderer(
- utki::shared_ref render_context, //
- utki::shared_ref common_objects
+ utki::shared_ref rendering_context, //
+ utki::shared_ref common_shaders,
+ utki::shared_ref common_objects
);
renderer(const renderer&) = delete;
diff --git a/src/ruis/render/shaders/coloring_shader.hpp b/src/ruis/render/shaders/coloring_shader.hpp
index 27e13bfd2..228c03d07 100644
--- a/src/ruis/render/shaders/coloring_shader.hpp
+++ b/src/ruis/render/shaders/coloring_shader.hpp
@@ -33,14 +33,14 @@ class context;
class coloring_shader
{
+ const utki::shared_ref rendering_context;
+
protected:
- coloring_shader(utki::shared_ref render_context) :
- render_context(std::move(render_context))
+ coloring_shader(utki::shared_ref rendering_context) :
+ rendering_context(std::move(rendering_context))
{}
public:
- const utki::shared_ref render_context;
-
coloring_shader(const coloring_shader&) = delete;
coloring_shader& operator=(const coloring_shader&) = delete;
diff --git a/src/ruis/render/shaders/coloring_texturing_shader.hpp b/src/ruis/render/shaders/coloring_texturing_shader.hpp
index 6b6f83e6c..c8140ca84 100644
--- a/src/ruis/render/shaders/coloring_texturing_shader.hpp
+++ b/src/ruis/render/shaders/coloring_texturing_shader.hpp
@@ -34,14 +34,14 @@ class context;
class coloring_texturing_shader
{
+ const utki::shared_ref rendering_context;
+
protected:
- coloring_texturing_shader(utki::shared_ref render_context) :
- render_context(std::move(render_context))
+ coloring_texturing_shader(utki::shared_ref rendering_context) :
+ rendering_context(std::move(rendering_context))
{}
public:
- const utki::shared_ref render_context;
-
coloring_texturing_shader(const coloring_texturing_shader&) = delete;
coloring_texturing_shader& operator=(const coloring_texturing_shader&) = delete;
diff --git a/src/ruis/render/shaders/shader.hpp b/src/ruis/render/shaders/shader.hpp
index 27cf292be..1ac026c73 100644
--- a/src/ruis/render/shaders/shader.hpp
+++ b/src/ruis/render/shaders/shader.hpp
@@ -31,14 +31,14 @@ class context;
class shader
{
+ const utki::shared_ref rendering_context;
+
protected:
- shader(utki::shared_ref render_context) :
- render_context(std::move(render_context))
+ shader(utki::shared_ref rendering_context) :
+ rendering_context(std::move(rendering_context))
{}
public:
- const utki::shared_ref render_context;
-
shader(const shader&) = delete;
shader& operator=(const shader&) = delete;
diff --git a/src/ruis/render/shaders/texturing_shader.hpp b/src/ruis/render/shaders/texturing_shader.hpp
index a6daa72e0..3473e6f25 100644
--- a/src/ruis/render/shaders/texturing_shader.hpp
+++ b/src/ruis/render/shaders/texturing_shader.hpp
@@ -30,14 +30,14 @@ class context;
class texturing_shader
{
+ const utki::shared_ref rendering_context;
+
protected:
- texturing_shader(utki::shared_ref render_context) :
- render_context(std::move(render_context))
+ texturing_shader(utki::shared_ref rendering_context) :
+ rendering_context(std::move(rendering_context))
{}
public:
- const utki::shared_ref render_context;
-
texturing_shader(const texturing_shader&) = delete;
texturing_shader& operator=(const texturing_shader&) = delete;
diff --git a/src/ruis/render/texture_2d.hpp b/src/ruis/render/texture_2d.hpp
index e37d753a9..17f9ffb62 100644
--- a/src/ruis/render/texture_2d.hpp
+++ b/src/ruis/render/texture_2d.hpp
@@ -32,6 +32,8 @@ class context;
class texture_2d : public rasterimage::dimensioned
{
+ const utki::shared_ref rendering_context;
+
public:
enum class filter {
nearest,
@@ -44,15 +46,13 @@ class texture_2d : public rasterimage::dimensioned
linear
};
- const utki::shared_ref render_context;
-
protected:
texture_2d(
- utki::shared_ref render_context, //
+ utki::shared_ref rendering_context, //
r4::vector2 dims
) :
rasterimage::dimensioned(dims),
- render_context(std::move(render_context))
+ rendering_context(std::move(rendering_context))
{}
public:
diff --git a/src/ruis/render/texture_cube.hpp b/src/ruis/render/texture_cube.hpp
index fa21259d7..996acac82 100644
--- a/src/ruis/render/texture_cube.hpp
+++ b/src/ruis/render/texture_cube.hpp
@@ -29,14 +29,14 @@ class context;
class texture_cube
{
+ const utki::shared_ref rendering_context;
+
protected:
- texture_cube(utki::shared_ref render_context) :
- render_context(std::move(render_context))
+ texture_cube(utki::shared_ref rendering_context) :
+ rendering_context(std::move(rendering_context))
{}
public:
- const utki::shared_ref render_context;
-
texture_cube(const texture_cube&) = delete;
texture_cube& operator=(const texture_cube&) = delete;
diff --git a/src/ruis/render/texture_depth.hpp b/src/ruis/render/texture_depth.hpp
index da7d9d13e..f1320259b 100644
--- a/src/ruis/render/texture_depth.hpp
+++ b/src/ruis/render/texture_depth.hpp
@@ -30,18 +30,18 @@ class context;
class texture_depth : public rasterimage::dimensioned
{
+ const utki::shared_ref rendering_context;
+
protected:
texture_depth(
- utki::shared_ref render_context, //
+ utki::shared_ref rendering_context, //
r4::vector2 dims
) :
rasterimage::dimensioned(dims),
- render_context(std::move(render_context))
+ rendering_context(std::move(rendering_context))
{}
public:
- const utki::shared_ref render_context;
-
texture_depth(const texture_depth&) = delete;
texture_depth& operator=(const texture_depth&) = delete;
diff --git a/src/ruis/render/texture_stencil.hpp b/src/ruis/render/texture_stencil.hpp
index 5eabba698..1fcb0c2d5 100644
--- a/src/ruis/render/texture_stencil.hpp
+++ b/src/ruis/render/texture_stencil.hpp
@@ -30,18 +30,18 @@ class context;
class texture_stencil : public rasterimage::dimensioned
{
+ const utki::shared_ref rendering_context;
+
protected:
texture_stencil(
- utki::shared_ref render_context, //
+ utki::shared_ref rendering_context, //
r4::vector2 dims
) :
rasterimage::dimensioned(dims),
- render_context(std::move(render_context))
+ rendering_context(std::move(rendering_context))
{}
public:
- const utki::shared_ref render_context;
-
texture_stencil(const texture_stencil&) = delete;
texture_stencil& operator=(const texture_stencil&) = delete;
diff --git a/src/ruis/render/vertex_array.cpp b/src/ruis/render/vertex_array.cpp
index b36de1a2f..b24f48988 100644
--- a/src/ruis/render/vertex_array.cpp
+++ b/src/ruis/render/vertex_array.cpp
@@ -26,12 +26,12 @@ along with this program. If not, see .
using namespace ruis::render;
vertex_array::vertex_array(
- utki::shared_ref render_context, //
+ utki::shared_ref rendering_context, //
buffers_type buffers,
utki::shared_ref indices,
mode rendering_mode
) :
- render_context(std::move(render_context)),
+ rendering_context(std::move(rendering_context)),
buffers(std::move(buffers)),
indices(std::move(indices)),
rendering_mode(rendering_mode)
diff --git a/src/ruis/render/vertex_array.hpp b/src/ruis/render/vertex_array.hpp
index 8daf6e25f..ea84833bc 100644
--- a/src/ruis/render/vertex_array.hpp
+++ b/src/ruis/render/vertex_array.hpp
@@ -35,9 +35,9 @@ class context;
class vertex_array
{
-public:
- const utki::shared_ref render_context;
+ const utki::shared_ref rendering_context;
+public:
using buffers_type = std::vector>;
const buffers_type buffers;
@@ -63,7 +63,7 @@ class vertex_array
protected:
vertex_array(
- utki::shared_ref render_context, //
+ utki::shared_ref rendering_context, //
buffers_type buffers,
utki::shared_ref indices,
mode rendering_mode
diff --git a/src/ruis/render/vertex_buffer.hpp b/src/ruis/render/vertex_buffer.hpp
index cb87c2455..3bf6aa710 100644
--- a/src/ruis/render/vertex_buffer.hpp
+++ b/src/ruis/render/vertex_buffer.hpp
@@ -31,17 +31,17 @@ class context;
class vertex_buffer
{
-public:
- const utki::shared_ref render_context;
+ const utki::shared_ref rendering_context;
+public:
const size_t size;
protected:
vertex_buffer(
- utki::shared_ref render_context, //
+ utki::shared_ref rendering_context, //
size_t size
) :
- render_context(std::move(render_context)),
+ rendering_context(std::move(rendering_context)),
size(size)
{}
diff --git a/src/ruis/res/font.cpp b/src/ruis/res/font.cpp
index 8c8d1a4d3..385d63281 100644
--- a/src/ruis/res/font.cpp
+++ b/src/ruis/res/font.cpp
@@ -33,7 +33,8 @@ using namespace ruis;
using namespace ruis::res;
res::font::font(
- utki::shared_ref renderer, //
+ utki::shared_ref rendering_context, //
+ utki::shared_ref common_rendering_objects,
const papki::file& file_normal,
std::unique_ptr file_bold,
std::unique_ptr file_italic,
@@ -42,18 +43,27 @@ res::font::font(
)
{
// NOLINTNEXTLINE(bugprone-unused-return-value, "false positive")
- this->fonts[unsigned(style::normal)] =
- std::make_unique(renderer, utki::make_shared(file_normal), max_cached);
+ this->fonts[unsigned(style::normal)] = std::make_unique(
+ rendering_context, //
+ common_rendering_objects,
+ utki::make_shared(file_normal),
+ max_cached
+ );
if (file_bold) {
// NOLINTNEXTLINE(bugprone-unused-return-value, "false positive")
- this->fonts[unsigned(style::bold)] =
- std::make_unique(renderer, utki::make_shared(*file_bold), max_cached);
+ this->fonts[unsigned(style::bold)] = std::make_unique(
+ rendering_context, //
+ common_rendering_objects,
+ utki::make_shared(*file_bold),
+ max_cached
+ );
}
if (file_italic) {
// NOLINTNEXTLINE(bugprone-unused-return-value, "false positive")
this->fonts[unsigned(style::italic)] = std::make_unique(
- renderer,
+ rendering_context, //
+ common_rendering_objects,
utki::make_shared(*file_italic),
max_cached
);
@@ -61,7 +71,8 @@ res::font::font(
if (file_bold_italic) {
// NOLINTNEXTLINE(bugprone-unused-return-value, "false positive")
this->fonts[unsigned(style::bold_italic)] = std::make_unique(
- std::move(renderer),
+ std::move(rendering_context), //
+ std::move(common_rendering_objects),
utki::make_shared(*file_bold_italic),
max_cached
);
@@ -98,7 +109,8 @@ utki::shared_ref