Compare commits
17 Commits
master
...
embedder_t
Author | SHA1 | Date |
---|---|---|
Vitaliy Zarubin | ec4b86573c | 1 year ago |
Vitaliy Zarubin | 32a481b213 | 1 year ago |
Vitaliy Zarubin | 4db615def4 | 1 year ago |
Vitaliy Zarubin | 0ccba5006e | 1 year ago |
Vitaliy Zarubin | c4556091dc | 1 year ago |
Vitaliy Zarubin | 4d898d36a5 | 1 year ago |
Vitaliy Zarubin | e6e3352e7f | 1 year ago |
Vitaliy Zarubin | f79d080cf3 | 1 year ago |
Vitaliy Zarubin | 96795f33f0 | 1 year ago |
Vitaliy Zarubin | 1761211ba1 | 1 year ago |
Vitaliy Zarubin | 4e6ff5e419 | 1 year ago |
Vitaliy Zarubin | edfa81bca0 | 1 year ago |
Vitaliy Zarubin | 013245d9bb | 1 year ago |
Vitaliy Zarubin | fed1031ab4 | 1 year ago |
Vitaliy Zarubin | 80e1758cc8 | 1 year ago |
Vitaliy Zarubin | 3413ecd9a3 | 1 year ago |
Vitaliy Zarubin | 4b7268cee0 | 1 year ago |
39 changed files with 1754 additions and 17 deletions
@ -0,0 +1,22 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2023 Open Mobile Platform LLC <community@omp.ru> |
||||
// SPDX-License-Identifier: BSD-3-Clause |
||||
import 'package:flutter/widgets.dart'; |
||||
import 'package:scoped_model/scoped_model.dart'; |
||||
import 'package:xdga_directories/xdga_directories.dart' as xdga; |
||||
|
||||
/// Model for [EmbedderTexturePage] |
||||
class EmbedderTextureModel extends Model { |
||||
/// Get [ScopedModel] |
||||
static EmbedderTextureModel of(BuildContext context) => |
||||
ScopedModel.of<EmbedderTextureModel>(context); |
||||
|
||||
/// Error |
||||
String? _error; |
||||
|
||||
/// Public error |
||||
String? get error => _error; |
||||
|
||||
/// Public is error |
||||
bool get isError => _error != null; |
||||
|
||||
} |
@ -0,0 +1,25 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2023 Open Mobile Platform LLC <community@omp.ru> |
||||
// SPDX-License-Identifier: BSD-3-Clause |
||||
import 'package:flutter_example_packages/base/package/package_page.dart'; |
||||
import 'package:flutter_example_packages/packages/embedder_texture/page.dart'; |
||||
import 'package:get_it/get_it.dart'; |
||||
|
||||
import 'model.dart'; |
||||
|
||||
/// Package values |
||||
final packageEmbedderTexture = PackagePage( |
||||
key: 'Embedder Texture', |
||||
descEN: ''' |
||||
Test Embedder texture plugin |
||||
''', |
||||
descRU: ''' |
||||
Тестирование текстур Embedder |
||||
''', |
||||
version: '0.0.1', |
||||
isPlatformDependent: true, |
||||
page: () => EmbedderTexturePage(), |
||||
init: () { |
||||
GetIt.instance |
||||
.registerFactory<EmbedderTextureModel>(() => EmbedderTextureModel()); |
||||
}, |
||||
); |
@ -0,0 +1,53 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2023 Open Mobile Platform LLC <community@omp.ru> |
||||
// SPDX-License-Identifier: BSD-3-Clause |
||||
import 'package:flutter/material.dart'; |
||||
import 'package:flutter_example_packages/base/di/app_di.dart'; |
||||
import 'package:flutter_example_packages/base/package/package.dart'; |
||||
import 'package:flutter_example_packages/packages/embedder_texture/model.dart'; |
||||
import 'package:flutter_example_packages/packages/embedder_texture/package.dart'; |
||||
import 'package:flutter_example_packages/widgets/base/export.dart'; |
||||
import 'package:flutter_example_packages/widgets/blocks/block_alert.dart'; |
||||
import 'package:flutter_example_packages/widgets/blocks/block_info_package.dart'; |
||||
import 'package:flutter_example_packages/widgets/blocks/block_item.dart'; |
||||
import 'package:flutter_example_packages/widgets/layouts/block_layout.dart'; |
||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart'; |
||||
import 'package:embedder_texture/embedder_texture.dart'; |
||||
|
||||
class EmbedderTexturePage extends AppStatefulWidget { |
||||
EmbedderTexturePage({ |
||||
super.key, |
||||
}); |
||||
|
||||
final Package package = packageEmbedderTexture; |
||||
|
||||
@override |
||||
State<EmbedderTexturePage> createState() => _EmbedderTexturePageState(); |
||||
} |
||||
|
||||
class _EmbedderTexturePageState extends AppState<EmbedderTexturePage> { |
||||
@override |
||||
Widget buildWide( |
||||
BuildContext context, |
||||
MediaQueryData media, |
||||
AppLocalizations l10n, |
||||
) { |
||||
final width = MediaQuery.of(context).size.width; |
||||
final height = MediaQuery.of(context).size.height; |
||||
|
||||
return BlockLayout<EmbedderTextureModel>( |
||||
model: getIt<EmbedderTextureModel>(), |
||||
title: widget.package.key, |
||||
builder: (context, child, model) { |
||||
return Padding( |
||||
padding: const EdgeInsets.all(20), |
||||
child: Center( |
||||
child: EmbedderTexture( |
||||
width: width, |
||||
height: height, |
||||
), |
||||
), |
||||
); |
||||
}, |
||||
); |
||||
} |
||||
} |
@ -0,0 +1,139 @@
|
||||
# Project-level configuration. |
||||
cmake_minimum_required(VERSION 3.10) |
||||
project(runner LANGUAGES CXX) |
||||
|
||||
# The name of the executable created for the application. Change this to change |
||||
# the on-disk name of your application. |
||||
set(BINARY_NAME "flutter_example_packages") |
||||
# The unique GTK application identifier for this application. See: |
||||
# https://wiki.gnome.org/HowDoI/ChooseApplicationID |
||||
set(APPLICATION_ID "ru.auroraos.flutter_example_packages") |
||||
|
||||
# Explicitly opt in to modern CMake behaviors to avoid warnings with recent |
||||
# versions of CMake. |
||||
cmake_policy(SET CMP0063 NEW) |
||||
|
||||
# Load bundled libraries from the lib/ directory relative to the binary. |
||||
set(CMAKE_INSTALL_RPATH "$ORIGIN/lib") |
||||
|
||||
# Root filesystem for cross-building. |
||||
if(FLUTTER_TARGET_PLATFORM_SYSROOT) |
||||
set(CMAKE_SYSROOT ${FLUTTER_TARGET_PLATFORM_SYSROOT}) |
||||
set(CMAKE_FIND_ROOT_PATH ${CMAKE_SYSROOT}) |
||||
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) |
||||
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) |
||||
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) |
||||
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) |
||||
endif() |
||||
|
||||
# Define build configuration options. |
||||
if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) |
||||
set(CMAKE_BUILD_TYPE "Debug" CACHE |
||||
STRING "Flutter build mode" FORCE) |
||||
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS |
||||
"Debug" "Profile" "Release") |
||||
endif() |
||||
|
||||
# Compilation settings that should be applied to most targets. |
||||
# |
||||
# Be cautious about adding new options here, as plugins use this function by |
||||
# default. In most cases, you should add new options to specific targets instead |
||||
# of modifying this function. |
||||
function(APPLY_STANDARD_SETTINGS TARGET) |
||||
target_compile_features(${TARGET} PUBLIC cxx_std_14) |
||||
# target_compile_options(${TARGET} PRIVATE -Wall -Werror) |
||||
target_compile_options(${TARGET} PRIVATE "$<$<NOT:$<CONFIG:Debug>>:-O3>") |
||||
target_compile_definitions(${TARGET} PRIVATE "$<$<NOT:$<CONFIG:Debug>>:NDEBUG>") |
||||
endfunction() |
||||
|
||||
# Flutter library and tool build rules. |
||||
set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter") |
||||
add_subdirectory(${FLUTTER_MANAGED_DIR}) |
||||
|
||||
# System-level dependencies. |
||||
find_package(PkgConfig REQUIRED) |
||||
pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) |
||||
|
||||
add_definitions(-DAPPLICATION_ID="${APPLICATION_ID}") |
||||
|
||||
# Define the application target. To change its name, change BINARY_NAME above, |
||||
# not the value here, or `flutter run` will no longer work. |
||||
# |
||||
# Any new source files that you add to the application should be added here. |
||||
add_executable(${BINARY_NAME} |
||||
"main.cc" |
||||
"my_application.cc" |
||||
"${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" |
||||
) |
||||
|
||||
# Apply the standard set of build settings. This can be removed for applications |
||||
# that need different build settings. |
||||
apply_standard_settings(${BINARY_NAME}) |
||||
|
||||
# Add dependency libraries. Add any application-specific dependencies here. |
||||
target_link_libraries(${BINARY_NAME} PRIVATE flutter) |
||||
target_link_libraries(${BINARY_NAME} PRIVATE PkgConfig::GTK) |
||||
|
||||
# Run the Flutter tool portions of the build. This must not be removed. |
||||
add_dependencies(${BINARY_NAME} flutter_assemble) |
||||
|
||||
# Only the install-generated bundle's copy of the executable will launch |
||||
# correctly, since the resources must in the right relative locations. To avoid |
||||
# people trying to run the unbundled copy, put it in a subdirectory instead of |
||||
# the default top-level location. |
||||
set_target_properties(${BINARY_NAME} |
||||
PROPERTIES |
||||
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/intermediates_do_not_run" |
||||
) |
||||
|
||||
|
||||
# Generated plugin build rules, which manage building the plugins and adding |
||||
# them to the application. |
||||
include(flutter/generated_plugins.cmake) |
||||
|
||||
|
||||
# === Installation === |
||||
# By default, "installing" just makes a relocatable bundle in the build |
||||
# directory. |
||||
set(BUILD_BUNDLE_DIR "${PROJECT_BINARY_DIR}/bundle") |
||||
if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) |
||||
set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE) |
||||
endif() |
||||
|
||||
# Start with a clean build bundle directory every time. |
||||
install(CODE " |
||||
file(REMOVE_RECURSE \"${BUILD_BUNDLE_DIR}/\") |
||||
" COMPONENT Runtime) |
||||
|
||||
set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data") |
||||
set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}/lib") |
||||
|
||||
install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}" |
||||
COMPONENT Runtime) |
||||
|
||||
install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" |
||||
COMPONENT Runtime) |
||||
|
||||
install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" |
||||
COMPONENT Runtime) |
||||
|
||||
foreach(bundled_library ${PLUGIN_BUNDLED_LIBRARIES}) |
||||
install(FILES "${bundled_library}" |
||||
DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" |
||||
COMPONENT Runtime) |
||||
endforeach(bundled_library) |
||||
|
||||
# Fully re-copy the assets directory on each build to avoid having stale files |
||||
# from a previous install. |
||||
set(FLUTTER_ASSET_DIR_NAME "flutter_assets") |
||||
install(CODE " |
||||
file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\") |
||||
" COMPONENT Runtime) |
||||
install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}" |
||||
DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) |
||||
|
||||
# Install the AOT library on non-Debug builds only. |
||||
if(NOT CMAKE_BUILD_TYPE MATCHES "Debug") |
||||
install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" |
||||
COMPONENT Runtime) |
||||
endif() |
@ -0,0 +1,88 @@
|
||||
# This file controls Flutter-level build steps. It should not be edited. |
||||
cmake_minimum_required(VERSION 3.10) |
||||
|
||||
set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral") |
||||
|
||||
# Configuration provided via flutter tool. |
||||
include(${EPHEMERAL_DIR}/generated_config.cmake) |
||||
|
||||
# TODO: Move the rest of this into files in ephemeral. See |
||||
# https://github.com/flutter/flutter/issues/57146. |
||||
|
||||
# Serves the same purpose as list(TRANSFORM ... PREPEND ...), |
||||
# which isn't available in 3.10. |
||||
function(list_prepend LIST_NAME PREFIX) |
||||
set(NEW_LIST "") |
||||
foreach(element ${${LIST_NAME}}) |
||||
list(APPEND NEW_LIST "${PREFIX}${element}") |
||||
endforeach(element) |
||||
set(${LIST_NAME} "${NEW_LIST}" PARENT_SCOPE) |
||||
endfunction() |
||||
|
||||
# === Flutter Library === |
||||
# System-level dependencies. |
||||
find_package(PkgConfig REQUIRED) |
||||
pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) |
||||
pkg_check_modules(GLIB REQUIRED IMPORTED_TARGET glib-2.0) |
||||
pkg_check_modules(GIO REQUIRED IMPORTED_TARGET gio-2.0) |
||||
|
||||
set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/libflutter_linux_gtk.so") |
||||
|
||||
# Published to parent scope for install step. |
||||
set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE) |
||||
set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE) |
||||
set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE) |
||||
set(AOT_LIBRARY "${PROJECT_DIR}/build/lib/libapp.so" PARENT_SCOPE) |
||||
|
||||
list(APPEND FLUTTER_LIBRARY_HEADERS |
||||
"fl_basic_message_channel.h" |
||||
"fl_binary_codec.h" |
||||
"fl_binary_messenger.h" |
||||
"fl_dart_project.h" |
||||
"fl_engine.h" |
||||
"fl_json_message_codec.h" |
||||
"fl_json_method_codec.h" |
||||
"fl_message_codec.h" |
||||
"fl_method_call.h" |
||||
"fl_method_channel.h" |
||||
"fl_method_codec.h" |
||||
"fl_method_response.h" |
||||
"fl_plugin_registrar.h" |
||||
"fl_plugin_registry.h" |
||||
"fl_standard_message_codec.h" |
||||
"fl_standard_method_codec.h" |
||||
"fl_string_codec.h" |
||||
"fl_value.h" |
||||
"fl_view.h" |
||||
"flutter_linux.h" |
||||
) |
||||
list_prepend(FLUTTER_LIBRARY_HEADERS "${EPHEMERAL_DIR}/flutter_linux/") |
||||
add_library(flutter INTERFACE) |
||||
target_include_directories(flutter INTERFACE |
||||
"${EPHEMERAL_DIR}" |
||||
) |
||||
target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}") |
||||
target_link_libraries(flutter INTERFACE |
||||
PkgConfig::GTK |
||||
PkgConfig::GLIB |
||||
PkgConfig::GIO |
||||
) |
||||
add_dependencies(flutter flutter_assemble) |
||||
|
||||
# === Flutter tool backend === |
||||
# _phony_ is a non-existent file to force this command to run every time, |
||||
# since currently there's no way to get a full input/output list from the |
||||
# flutter tool. |
||||
add_custom_command( |
||||
OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS} |
||||
${CMAKE_CURRENT_BINARY_DIR}/_phony_ |
||||
COMMAND ${CMAKE_COMMAND} -E env |
||||
${FLUTTER_TOOL_ENVIRONMENT} |
||||
"${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.sh" |
||||
${FLUTTER_TARGET_PLATFORM} ${CMAKE_BUILD_TYPE} |
||||
VERBATIM |
||||
) |
||||
add_custom_target(flutter_assemble DEPENDS |
||||
"${FLUTTER_LIBRARY}" |
||||
${FLUTTER_LIBRARY_HEADERS} |
||||
) |
@ -0,0 +1,19 @@
|
||||
//
|
||||
// Generated file. Do not edit.
|
||||
//
|
||||
|
||||
// clang-format off
|
||||
|
||||
#include "generated_plugin_registrant.h" |
||||
|
||||
#include <embedder_texture/embedder_texture_plugin.h> |
||||
#include <flutter_secure_storage_linux/flutter_secure_storage_linux_plugin.h> |
||||
|
||||
void fl_register_plugins(FlPluginRegistry* registry) { |
||||
g_autoptr(FlPluginRegistrar) embedder_texture_registrar = |
||||
fl_plugin_registry_get_registrar_for_plugin(registry, "EmbedderTexturePlugin"); |
||||
embedder_texture_plugin_register_with_registrar(embedder_texture_registrar); |
||||
g_autoptr(FlPluginRegistrar) flutter_secure_storage_linux_registrar = |
||||
fl_plugin_registry_get_registrar_for_plugin(registry, "FlutterSecureStorageLinuxPlugin"); |
||||
flutter_secure_storage_linux_plugin_register_with_registrar(flutter_secure_storage_linux_registrar); |
||||
} |
@ -0,0 +1,15 @@
|
||||
//
|
||||
// Generated file. Do not edit.
|
||||
//
|
||||
|
||||
// clang-format off
|
||||
|
||||
#ifndef GENERATED_PLUGIN_REGISTRANT_ |
||||
#define GENERATED_PLUGIN_REGISTRANT_ |
||||
|
||||
#include <flutter_linux/flutter_linux.h> |
||||
|
||||
// Registers Flutter plugins.
|
||||
void fl_register_plugins(FlPluginRegistry* registry); |
||||
|
||||
#endif // GENERATED_PLUGIN_REGISTRANT_
|
@ -0,0 +1,25 @@
|
||||
# |
||||
# Generated file, do not edit. |
||||
# |
||||
|
||||
list(APPEND FLUTTER_PLUGIN_LIST |
||||
embedder_texture |
||||
flutter_secure_storage_linux |
||||
) |
||||
|
||||
list(APPEND FLUTTER_FFI_PLUGIN_LIST |
||||
) |
||||
|
||||
set(PLUGIN_BUNDLED_LIBRARIES) |
||||
|
||||
foreach(plugin ${FLUTTER_PLUGIN_LIST}) |
||||
add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/linux plugins/${plugin}) |
||||
target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) |
||||
list(APPEND PLUGIN_BUNDLED_LIBRARIES $<TARGET_FILE:${plugin}_plugin>) |
||||
list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) |
||||
endforeach(plugin) |
||||
|
||||
foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST}) |
||||
add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/linux plugins/${ffi_plugin}) |
||||
list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) |
||||
endforeach(ffi_plugin) |
@ -0,0 +1,6 @@
|
||||
#include "my_application.h" |
||||
|
||||
int main(int argc, char** argv) { |
||||
g_autoptr(MyApplication) app = my_application_new(); |
||||
return g_application_run(G_APPLICATION(app), argc, argv); |
||||
} |
@ -0,0 +1,104 @@
|
||||
#include "my_application.h" |
||||
|
||||
#include <flutter_linux/flutter_linux.h> |
||||
#ifdef GDK_WINDOWING_X11 |
||||
#include <gdk/gdkx.h> |
||||
#endif |
||||
|
||||
#include "flutter/generated_plugin_registrant.h" |
||||
|
||||
struct _MyApplication { |
||||
GtkApplication parent_instance; |
||||
char** dart_entrypoint_arguments; |
||||
}; |
||||
|
||||
G_DEFINE_TYPE(MyApplication, my_application, GTK_TYPE_APPLICATION) |
||||
|
||||
// Implements GApplication::activate.
|
||||
static void my_application_activate(GApplication* application) { |
||||
MyApplication* self = MY_APPLICATION(application); |
||||
GtkWindow* window = |
||||
GTK_WINDOW(gtk_application_window_new(GTK_APPLICATION(application))); |
||||
|
||||
// Use a header bar when running in GNOME as this is the common style used
|
||||
// by applications and is the setup most users will be using (e.g. Ubuntu
|
||||
// desktop).
|
||||
// If running on X and not using GNOME then just use a traditional title bar
|
||||
// in case the window manager does more exotic layout, e.g. tiling.
|
||||
// If running on Wayland assume the header bar will work (may need changing
|
||||
// if future cases occur).
|
||||
gboolean use_header_bar = TRUE; |
||||
#ifdef GDK_WINDOWING_X11 |
||||
GdkScreen* screen = gtk_window_get_screen(window); |
||||
if (GDK_IS_X11_SCREEN(screen)) { |
||||
const gchar* wm_name = gdk_x11_screen_get_window_manager_name(screen); |
||||
if (g_strcmp0(wm_name, "GNOME Shell") != 0) { |
||||
use_header_bar = FALSE; |
||||
} |
||||
} |
||||
#endif |
||||
if (use_header_bar) { |
||||
GtkHeaderBar* header_bar = GTK_HEADER_BAR(gtk_header_bar_new()); |
||||
gtk_widget_show(GTK_WIDGET(header_bar)); |
||||
gtk_header_bar_set_title(header_bar, "flutter_example_packages"); |
||||
gtk_header_bar_set_show_close_button(header_bar, TRUE); |
||||
gtk_window_set_titlebar(window, GTK_WIDGET(header_bar)); |
||||
} else { |
||||
gtk_window_set_title(window, "flutter_example_packages"); |
||||
} |
||||
|
||||
gtk_window_set_default_size(window, 1280, 720); |
||||
gtk_widget_show(GTK_WIDGET(window)); |
||||
|
||||
g_autoptr(FlDartProject) project = fl_dart_project_new(); |
||||
fl_dart_project_set_dart_entrypoint_arguments(project, self->dart_entrypoint_arguments); |
||||
|
||||
FlView* view = fl_view_new(project); |
||||
gtk_widget_show(GTK_WIDGET(view)); |
||||
gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(view)); |
||||
|
||||
fl_register_plugins(FL_PLUGIN_REGISTRY(view)); |
||||
|
||||
gtk_widget_grab_focus(GTK_WIDGET(view)); |
||||
} |
||||
|
||||
// Implements GApplication::local_command_line.
|
||||
static gboolean my_application_local_command_line(GApplication* application, gchar*** arguments, int* exit_status) { |
||||
MyApplication* self = MY_APPLICATION(application); |
||||
// Strip out the first argument as it is the binary name.
|
||||
self->dart_entrypoint_arguments = g_strdupv(*arguments + 1); |
||||
|
||||
g_autoptr(GError) error = nullptr; |
||||
if (!g_application_register(application, nullptr, &error)) { |
||||
g_warning("Failed to register: %s", error->message); |
||||
*exit_status = 1; |
||||
return TRUE; |
||||
} |
||||
|
||||
g_application_activate(application); |
||||
*exit_status = 0; |
||||
|
||||
return TRUE; |
||||
} |
||||
|
||||
// Implements GObject::dispose.
|
||||
static void my_application_dispose(GObject* object) { |
||||
MyApplication* self = MY_APPLICATION(object); |
||||
g_clear_pointer(&self->dart_entrypoint_arguments, g_strfreev); |
||||
G_OBJECT_CLASS(my_application_parent_class)->dispose(object); |
||||
} |
||||
|
||||
static void my_application_class_init(MyApplicationClass* klass) { |
||||
G_APPLICATION_CLASS(klass)->activate = my_application_activate; |
||||
G_APPLICATION_CLASS(klass)->local_command_line = my_application_local_command_line; |
||||
G_OBJECT_CLASS(klass)->dispose = my_application_dispose; |
||||
} |
||||
|
||||
static void my_application_init(MyApplication* self) {} |
||||
|
||||
MyApplication* my_application_new() { |
||||
return MY_APPLICATION(g_object_new(my_application_get_type(), |
||||
"application-id", APPLICATION_ID, |
||||
"flags", G_APPLICATION_NON_UNIQUE, |
||||
nullptr)); |
||||
} |
@ -0,0 +1,18 @@
|
||||
#ifndef FLUTTER_MY_APPLICATION_H_ |
||||
#define FLUTTER_MY_APPLICATION_H_ |
||||
|
||||
#include <gtk/gtk.h> |
||||
|
||||
G_DECLARE_FINAL_TYPE(MyApplication, my_application, MY, APPLICATION, |
||||
GtkApplication) |
||||
|
||||
/**
|
||||
* my_application_new: |
||||
* |
||||
* Creates a new Flutter-based application. |
||||
* |
||||
* Returns: a new #MyApplication. |
||||
*/ |
||||
MyApplication* my_application_new(); |
||||
|
||||
#endif // FLUTTER_MY_APPLICATION_H_
|
@ -0,0 +1,30 @@
|
||||
# Miscellaneous |
||||
*.class |
||||
*.log |
||||
*.pyc |
||||
*.swp |
||||
.DS_Store |
||||
.atom/ |
||||
.buildlog/ |
||||
.history |
||||
.svn/ |
||||
migrate_working_dir/ |
||||
|
||||
# IntelliJ related |
||||
*.iml |
||||
*.ipr |
||||
*.iws |
||||
.idea/ |
||||
|
||||
# The .vscode folder contains launch configuration and tasks you configure in |
||||
# VS Code which you may wish to be included in version control, so this line |
||||
# is commented out by default. |
||||
.vscode/ |
||||
|
||||
# Flutter/Dart/Pub related |
||||
# Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock. |
||||
/pubspec.lock |
||||
**/doc/api/ |
||||
.dart_tool/ |
||||
.packages |
||||
build/ |
@ -0,0 +1 @@
|
||||
include: package:flutter_lints/flutter.yaml |
@ -0,0 +1,36 @@
|
||||
# SPDX-FileCopyrightText: Copyright 2023 Open Mobile Platform LLC <community@omp.ru> |
||||
# SPDX-License-Identifier: BSD-3-Clause |
||||
|
||||
cmake_minimum_required(VERSION 3.10) |
||||
|
||||
set(PROJECT_NAME embedder_texture) |
||||
set(PLUGIN_NAME embedder_texture_platform_plugin) |
||||
|
||||
project(${PROJECT_NAME} LANGUAGES CXX) |
||||
|
||||
set(CMAKE_CXX_STANDARD 17) |
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON) |
||||
|
||||
set(CMAKE_CXX_FLAGS "-Wall -Wextra -Wno-psabi") |
||||
set(CMAKE_CXX_FLAGS_RELEASE "-O3") |
||||
|
||||
find_package(PkgConfig REQUIRED) |
||||
find_package(Qt5 COMPONENTS Core Multimedia REQUIRED) |
||||
|
||||
pkg_check_modules(FlutterEmbedder REQUIRED IMPORTED_TARGET flutter-embedder) |
||||
pkg_check_modules(GLES REQUIRED IMPORTED_TARGET glesv2) |
||||
pkg_check_modules(SC REQUIRED IMPORTED_TARGET streamcamera) |
||||
|
||||
add_library(${PLUGIN_NAME} SHARED |
||||
embedder_texture_plugin.cpp |
||||
camera_pixels_helper.cpp |
||||
camera_egl_helper.cpp |
||||
camera.cpp |
||||
) |
||||
|
||||
set_target_properties(${PLUGIN_NAME} PROPERTIES CXX_VISIBILITY_PRESET hidden) |
||||
target_link_libraries(${PLUGIN_NAME} PRIVATE PkgConfig::FlutterEmbedder PkgConfig::GLES PkgConfig::SC) |
||||
target_link_libraries(${PLUGIN_NAME} PUBLIC Qt5::Core Qt5::Multimedia) |
||||
|
||||
target_include_directories(${PLUGIN_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include) |
||||
target_compile_definitions(${PLUGIN_NAME} PRIVATE PLUGIN_IMPL) |
@ -0,0 +1,114 @@
|
||||
/**
|
||||
* SPDX-FileCopyrightText: Copyright 2023 Open Mobile Platform LLC <community@omp.ru> |
||||
* SPDX-License-Identifier: BSD-3-Clause |
||||
*/ |
||||
#include <embedder_texture/camera.h> |
||||
#include <embedder_texture/camera_egl_helper.h> |
||||
#include <embedder_texture/camera_pixels_helper.h> |
||||
|
||||
Camera::Camera(TextureRegistrar *plugin) |
||||
: m_plugin(plugin) |
||||
, m_manager(StreamCameraManager()) |
||||
{ |
||||
CameraEGLHelper::EGLInit(); |
||||
} |
||||
|
||||
void Camera::InitializeCamera(int cameraID) |
||||
{ |
||||
if (m_cameraId != cameraID && m_manager->getNumberOfCameras()) { |
||||
Aurora::StreamCamera::CameraInfo info; |
||||
|
||||
if (m_manager->getCameraInfo(cameraID, info)) { |
||||
m_cameraId = cameraID; |
||||
m_camera = m_manager->openCamera(info.id); |
||||
m_camera->setListener(this); |
||||
} |
||||
} |
||||
} |
||||
|
||||
Aurora::StreamCamera::CameraCapability Camera::StartCapture() |
||||
{ |
||||
if (m_camera) { |
||||
Aurora::StreamCamera::CameraInfo info; |
||||
|
||||
if (m_camera->getInfo(info)) { |
||||
std::vector<Aurora::StreamCamera::CameraCapability> caps; |
||||
if (m_manager->queryCapabilities(info.id, caps)) { |
||||
for(Aurora::StreamCamera::CameraCapability cap : caps) { |
||||
if (m_widthTexture + m_heightTexture < cap.width + cap.height) { |
||||
m_camera->startCapture(cap); |
||||
return cap; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
||||
return Aurora::StreamCamera::CameraCapability{}; |
||||
} |
||||
|
||||
void Camera::StopCapture() |
||||
{ |
||||
if (m_camera) { |
||||
m_cameraId = -1; |
||||
m_buffer = nullptr; |
||||
m_camera->stopCapture(); |
||||
} |
||||
} |
||||
|
||||
std::map<Encodable, Encodable> Camera::Register(int cameraID, int width, int height) |
||||
{ |
||||
m_widthTexture = width; |
||||
m_heightTexture = height; |
||||
|
||||
m_textureId = m_plugin->RegisterTexture( |
||||
[this](size_t width, size_t height) { return this->m_buffer; }); |
||||
|
||||
InitializeCamera(cameraID); |
||||
auto cab = StartCapture(); |
||||
|
||||
return std::map<Encodable, Encodable>{ |
||||
{"textureId", m_textureId}, |
||||
{"width", cab.width}, |
||||
{"height", cab.height}, |
||||
}; |
||||
} |
||||
|
||||
void Camera::Unregister() |
||||
{ |
||||
StopCapture(); |
||||
m_plugin->UnregisterTexture(m_textureId); |
||||
} |
||||
|
||||
void Camera::onCameraFrame(std::shared_ptr<Aurora::StreamCamera::GraphicBuffer> buffer) |
||||
{ |
||||
if (buffer->handleType == Aurora::StreamCamera::HandleType::EGL) { |
||||
// @todo Not tested. The device needs to be completed.
|
||||
auto eglImage = CameraEGLHelper::EGLCreateImage(buffer); |
||||
this->m_buffer = new TextureVariant(FlutterEGLImage{ |
||||
eglImage, |
||||
buffer->width, |
||||
buffer->height, |
||||
}); |
||||
} else { |
||||
auto pixels = CameraPixelsHelper::YUVtoARGB(buffer->mapYCbCr()); |
||||
this->m_buffer = new TextureVariant(FlutterPixelBuffer{ |
||||
pixels, |
||||
buffer->width, |
||||
buffer->height, |
||||
}); |
||||
} |
||||
|
||||
m_plugin->MarkTextureAvailable(m_textureId); |
||||
} |
||||
|
||||
void Camera::onCameraError(const std::string &errorDescription) |
||||
{ |
||||
this->Unregister(); |
||||
std::cout << errorDescription << std::endl; |
||||
} |
||||
|
||||
void Camera::onCameraParameterChanged(Aurora::StreamCamera::CameraParameter parameter, |
||||
const std::string &value) |
||||
{ |
||||
std::cout << "onCameraParameterChanged" << std::endl; |
||||
} |
@ -0,0 +1,42 @@
|
||||
/**
|
||||
* SPDX-FileCopyrightText: Copyright 2023 Open Mobile Platform LLC <community@omp.ru> |
||||
* SPDX-License-Identifier: BSD-3-Clause |
||||
*/ |
||||
#include <embedder_texture/camera_egl_helper.h> |
||||
#include <flutter/platform-methods.h> |
||||
|
||||
#include <GLES2/gl2.h> |
||||
#include <GLES2/gl2ext.h> |
||||
|
||||
static PFNEGLCREATEIMAGEKHRPROC eglCreateImageKHR; |
||||
static PFNEGLDESTROYIMAGEKHRPROC eglDestroyImageKHR; |
||||
|
||||
void CameraEGLHelper::EGLInit() |
||||
{ |
||||
eglCreateImageKHR = reinterpret_cast<PFNEGLCREATEIMAGEKHRPROC>( |
||||
eglGetProcAddress("eglCreateImageKHR")); |
||||
eglDestroyImageKHR = reinterpret_cast<PFNEGLDESTROYIMAGEKHRPROC>( |
||||
eglGetProcAddress("eglDestroyImageKHR")); |
||||
} |
||||
|
||||
EGLImageKHR CameraEGLHelper::EGLCreateImage( |
||||
std::shared_ptr<Aurora::StreamCamera::GraphicBuffer> buffer) |
||||
{ |
||||
auto display = PlatformMethods::GetEGLDisplay(); |
||||
auto context = PlatformMethods::GetEGLContext(); |
||||
|
||||
const void *handle = buffer->handle; |
||||
GLint eglImgAttrs[] = {EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE, EGL_NONE}; |
||||
return eglCreateImageKHR(display, |
||||
context, |
||||
EGL_NATIVE_BUFFER_ANDROID, |
||||
(EGLClientBuffer) handle, |
||||
eglImgAttrs); |
||||
} |
||||
|
||||
void CameraEGLHelper::EGLDestroyImage(EGLImageKHR image) |
||||
{ |
||||
auto display = PlatformMethods::GetEGLDisplay(); |
||||
|
||||
eglDestroyImageKHR(display, image); |
||||
} |
@ -0,0 +1,106 @@
|
||||
/**
|
||||
* SPDX-FileCopyrightText: Copyright 2023 Open Mobile Platform LLC <community@omp.ru> |
||||
* SPDX-License-Identifier: BSD-3-Clause |
||||
*/ |
||||
#include <embedder_texture/camera_helper.h> |
||||
|
||||
static PFNEGLCREATEIMAGEKHRPROC eglCreateImageKHR; |
||||
static PFNEGLDESTROYIMAGEKHRPROC eglDestroyImageKHR; |
||||
|
||||
void CameraHelper::EGLInit() |
||||
{ |
||||
eglCreateImageKHR = reinterpret_cast<PFNEGLCREATEIMAGEKHRPROC>( |
||||
eglGetProcAddress("eglCreateImageKHR")); |
||||
eglDestroyImageKHR = reinterpret_cast<PFNEGLDESTROYIMAGEKHRPROC>( |
||||
eglGetProcAddress("eglDestroyImageKHR")); |
||||
} |
||||
|
||||
EGLImageKHR CameraHelper::EGLCreateImage( |
||||
std::shared_ptr<const Aurora::StreamCamera::YCbCrFrame> frame) |
||||
{ |
||||
auto eglDisplay = PlatformMethods::GetEGLDisplay(); |
||||
auto eglContext = PlatformMethods::GetEGLContext(); |
||||
|
||||
const void *handle = buffer->handle; |
||||
GLint eglImgAttrs[] = {EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE, EGL_NONE}; |
||||
return s_eglCreateImageKHR(eglDisplay, |
||||
eglContext, |
||||
EGL_NATIVE_BUFFER_ANDROID, |
||||
(EGLClientBuffer) handle, |
||||
eglImgAttrs); |
||||
} |
||||
|
||||
void CameraHelper::EGLDestroyImage(EGLImageKHR eglImage, EGLDisplay eglDisplay) |
||||
{ |
||||
return eglDestroyImageKHR(eglDisplay, eglImage); |
||||
} |
||||
|
||||
uint8_t *CameraHelper::YUVtoARGB(std::shared_ptr<const Aurora::StreamCamera::YCbCrFrame> frame) |
||||
{ |
||||
QSize size(frame->width, frame->height); |
||||
QImage *image = new QImage(size, QImage::Format_ARGB32); |
||||
|
||||
planarYuv420ToArgb(frame->y, |
||||
frame->cb, |
||||
frame->cr, |
||||
frame->yStride, |
||||
frame->cStride, |
||||
frame->cStride, |
||||
frame->chromaStep, |
||||
reinterpret_cast<quint32 *>(image->bits()), |
||||
frame->width, |
||||
frame->height); |
||||
|
||||
return static_cast<uint8_t *>(image->bits()); |
||||
} |
||||
|
||||
quint32 CameraHelper::yuvToArgb(qint32 y, qint32 rv, qint32 guv, qint32 bu, qint32 a = 255) |
||||
{ |
||||
qint32 yy = (y - 16) * 298; |
||||
|
||||
return (a << 24) | qBound(0, (yy + rv) >> 8, 255) << 16 | qBound(0, (yy - guv) >> 8, 255) << 8 |
||||
| qBound(0, (yy + bu) >> 8, 255); |
||||
} |
||||
|
||||
void CameraHelper::planarYuv420ToArgb(const uchar *y, |
||||
const uchar *u, |
||||
const uchar *v, |
||||
qint32 yStride, |
||||
qint32 uStride, |
||||
qint32 vStride, |
||||
qint32 uvPixelStride, |
||||
quint32 *rgb, |
||||
qint32 width, |
||||
qint32 height) |
||||
{ |
||||
quint32 *rgb0 = rgb; |
||||
quint32 *rgb1 = rgb + width; |
||||
|
||||
for (qint32 j = 0; j < height; j += 2) { |
||||
const uchar *lineY0 = y; |
||||
const uchar *lineY1 = y + yStride; |
||||
const uchar *lineU = u; |
||||
const uchar *lineV = v; |
||||
|
||||
for (qint32 i = 0; i < width; i += 2) { |
||||
const qint32 uu = *lineU - 128; |
||||
const qint32 vv = *lineV - 128; |
||||
const qint32 rv = 409 * vv + 128; |
||||
const qint32 guv = 100 * uu + 208 * vv + 128; |
||||
const qint32 bu = 516 * uu + 128; |
||||
|
||||
lineU += uvPixelStride; |
||||
lineV += uvPixelStride; |
||||
*rgb0++ = yuvToArgb(*lineY0++, rv, guv, bu); |
||||
*rgb0++ = yuvToArgb(*lineY0++, rv, guv, bu); |
||||
*rgb1++ = yuvToArgb(*lineY1++, rv, guv, bu); |
||||
*rgb1++ = yuvToArgb(*lineY1++, rv, guv, bu); |
||||
} |
||||
|
||||
y += yStride << 1; |
||||
u += uStride; |
||||
v += vStride; |
||||
rgb0 += width; |
||||
rgb1 += width; |
||||
} |
||||
} |
@ -0,0 +1,77 @@
|
||||
/**
|
||||
* SPDX-FileCopyrightText: Copyright 2023 Open Mobile Platform LLC <community@omp.ru> |
||||
* SPDX-License-Identifier: BSD-3-Clause |
||||
*/ |
||||
#include <embedder_texture/camera_pixels_helper.h> |
||||
|
||||
uint8_t *CameraPixelsHelper::YUVtoARGB(std::shared_ptr<const Aurora::StreamCamera::YCbCrFrame> frame) |
||||
{ |
||||
QSize size(frame->width, frame->height); |
||||
QImage *image = new QImage(size, QImage::Format_ARGB32); |
||||
|
||||
planarYuv420ToArgb(frame->y, |
||||
frame->cr, |
||||
frame->cb, |
||||
frame->yStride, |
||||
frame->cStride, |
||||
frame->cStride, |
||||
frame->chromaStep, |
||||
reinterpret_cast<quint32 *>(image->bits()), |
||||
frame->width, |
||||
frame->height); |
||||
|
||||
return static_cast<uint8_t *>(image->bits()); |
||||
} |
||||
|
||||
quint32 CameraPixelsHelper::yuvToArgb(qint32 y, qint32 rv, qint32 guv, qint32 bu, qint32 a = 255) |
||||
{ |
||||
qint32 yy = (y - 16) * 298; |
||||
|
||||
return (a << 24) |
||||
| qBound(0, (yy + rv) >> 8, 255) << 16 |
||||
| qBound(0, (yy - guv) >> 8, 255) << 8 |
||||
| qBound(0, (yy + bu) >> 8, 255); |
||||
} |
||||
|
||||
void CameraPixelsHelper::planarYuv420ToArgb(const uchar *y, |
||||
const uchar *u, |
||||
const uchar *v, |
||||
qint32 yStride, |
||||
qint32 uStride, |
||||
qint32 vStride, |
||||
qint32 uvPixelStride, |
||||
quint32 *rgb, |
||||
qint32 width, |
||||
qint32 height) |
||||
{ |
||||
quint32 *rgb0 = rgb; |
||||
quint32 *rgb1 = rgb + width; |
||||
|
||||
for (qint32 j = 0; j < height; j += 2) { |
||||
const uchar *lineY0 = y; |
||||
const uchar *lineY1 = y + yStride; |
||||
const uchar *lineU = u; |
||||
const uchar *lineV = v; |
||||
|
||||
for (qint32 i = 0; i < width; i += 2) { |
||||
const qint32 uu = *lineU - 128; |
||||
const qint32 vv = *lineV - 128; |
||||
const qint32 rv = 409 * vv + 128; |
||||
const qint32 guv = 100 * uu + 208 * vv + 128; |
||||
const qint32 bu = 516 * uu + 128; |
||||
|
||||
lineU += uvPixelStride; |
||||
lineV += uvPixelStride; |
||||
*rgb0++ = yuvToArgb(*lineY0++, rv, guv, bu); |
||||
*rgb0++ = yuvToArgb(*lineY0++, rv, guv, bu); |
||||
*rgb1++ = yuvToArgb(*lineY1++, rv, guv, bu); |
||||
*rgb1++ = yuvToArgb(*lineY1++, rv, guv, bu); |
||||
} |
||||
|
||||
y += yStride << 1; |
||||
u += uStride; |
||||
v += vStride; |
||||
rgb0 += width; |
||||
rgb1 += width; |
||||
} |
||||
} |
@ -0,0 +1,87 @@
|
||||
/**
|
||||
* SPDX-FileCopyrightText: Copyright 2023 Open Mobile Platform LLC <community@omp.ru> |
||||
* SPDX-License-Identifier: BSD-3-Clause |
||||
*/ |
||||
#include <embedder_texture/embedder_texture_plugin.h> |
||||
#include <flutter/method-channel.h> |
||||
#include <flutter/platform-data.h> |
||||
#include <flutter/platform-events.h> |
||||
#include <flutter/platform-methods.h> |
||||
|
||||
EmbedderTexturePlugin::EmbedderTexturePlugin() |
||||
{ |
||||
PlatformEvents::SubscribeOrientationChanged([this](DisplayRotation orientation) { |
||||
if (this->m_isEnableOrientationChanged) { |
||||
EventChannel("embedder_texture_orientation", MethodCodecType::Standard) |
||||
.SendEvent(static_cast<int>(orientation)); |
||||
} |
||||
}); |
||||
} |
||||
|
||||
void EmbedderTexturePlugin::RegisterWithRegistrar(PluginRegistrar ®istrar) |
||||
{ |
||||
TextureRegistrar *plugin = registrar.GetRegisterTexture(); |
||||
|
||||
m_camera = new Camera(plugin); |
||||
|
||||
registrar.RegisterMethodChannel("embedder_texture", |
||||
MethodCodecType::Standard, |
||||
[this](const MethodCall &call) { this->onMethodCall(call); }); |
||||
|
||||
registrar.RegisterEventChannel( |
||||
"embedder_texture_orientation", |
||||
MethodCodecType::Standard, |
||||
[this](const Encodable &) { |
||||
this->m_isEnableOrientationChanged = true; |
||||
return EventResponse(); |
||||
}, |
||||
[this](const Encodable &) { |
||||
this->m_isEnableOrientationChanged = false; |
||||
return EventResponse(); |
||||
}); |
||||
|
||||
} |
||||
|
||||
void EmbedderTexturePlugin::onMethodCall(const MethodCall &call) |
||||
{ |
||||
const auto &method = call.GetMethod(); |
||||
|
||||
if (method == "create") { |
||||
onCreate(call); |
||||
return; |
||||
} |
||||
|
||||
if (method == "remove") { |
||||
onRemove(call); |
||||
return; |
||||
} |
||||
|
||||
unimplemented(call); |
||||
} |
||||
|
||||
void EmbedderTexturePlugin::onCreate(const MethodCall &call) |
||||
{ |
||||
auto cameraId = 0; |
||||
auto width = call.GetArgument<Encodable::Int>("width"); |
||||
auto height = call.GetArgument<Encodable::Int>("height"); |
||||
|
||||
auto result = m_camera->Register(cameraId, width, height); |
||||
|
||||
result["orientation"] = static_cast<int>(PlatformMethods::GetOrientation()); |
||||
|
||||
call.SendSuccessResponse(result); |
||||
} |
||||
|
||||
void EmbedderTexturePlugin::onRemove(const MethodCall &call) |
||||
{ |
||||
auto textureId = call.GetArgument<Encodable::Int>("textureId"); |
||||
|
||||
m_camera->Unregister(); |
||||
|
||||
call.SendSuccessResponse(true); |
||||
} |
||||
|
||||
void EmbedderTexturePlugin::unimplemented(const MethodCall &call) |
||||
{ |
||||
call.SendSuccessResponse(nullptr); |
||||
} |
@ -0,0 +1,47 @@
|
||||
/**
|
||||
* SPDX-FileCopyrightText: Copyright 2023 Open Mobile Platform LLC <community@omp.ru> |
||||
* SPDX-License-Identifier: BSD-3-Clause |
||||
*/ |
||||
#ifndef CAMERA_BUFFER_H |
||||
#define CAMERA_BUFFER_H |
||||
|
||||
#include <flutter/plugin-interface.h> |
||||
#include <streamcamera/streamcamera.h> |
||||
|
||||
#include <QImage> |
||||
#include <QtCore> |
||||
|
||||
class Camera : public Aurora::StreamCamera::CameraListener |
||||
{ |
||||
public: |
||||
Camera(TextureRegistrar *plugin); |
||||
|
||||
void onCameraError(const std::string &errorDescription) override; |
||||
void onCameraFrame(std::shared_ptr<Aurora::StreamCamera::GraphicBuffer> buffer) override; |
||||
void onCameraParameterChanged(Aurora::StreamCamera::CameraParameter, |
||||
const std::string &value) override; |
||||
|
||||
std::map<Encodable, Encodable> Register(int cameraID, int width, int height); |
||||
void Unregister(); |
||||
|
||||
private: |
||||
void InitializeCamera(int cameraID); |
||||
Aurora::StreamCamera::CameraCapability StartCapture(); |
||||
void StopCapture(); |
||||
|
||||
private: |
||||
TextureRegistrar *m_plugin; |
||||
|
||||
Aurora::StreamCamera::CameraManager *m_manager; |
||||
std::shared_ptr<Aurora::StreamCamera::Camera> m_camera; |
||||
|
||||
int m_cameraId = -1; |
||||
int64_t m_textureId; |
||||
|
||||
int m_widthTexture; |
||||
int m_heightTexture; |
||||
|
||||
TextureVariant *m_buffer; |
||||
}; |
||||
|
||||
#endif /* CAMERA_BUFFER_H */ |
@ -0,0 +1,21 @@
|
||||
/**
|
||||
* SPDX-FileCopyrightText: Copyright 2023 Open Mobile Platform LLC <community@omp.ru> |
||||
* SPDX-License-Identifier: BSD-3-Clause |
||||
*/ |
||||
#ifndef CAMERA_EGL_HELPER_H |
||||
#define CAMERA_EGL_HELPER_H |
||||
|
||||
#include <streamcamera/streamcamera.h> |
||||
|
||||
#include <EGL/egl.h> |
||||
#include <EGL/eglext.h> |
||||
|
||||
class CameraEGLHelper |
||||
{ |
||||
public: |
||||
static void EGLInit(); |
||||
static EGLImageKHR EGLCreateImage(std::shared_ptr<Aurora::StreamCamera::GraphicBuffer> buffer); |
||||
static void EGLDestroyImage(EGLImageKHR image); |
||||
}; |
||||
|
||||
#endif /* CAMERA_EGL_HELPER_H */ |
@ -0,0 +1,33 @@
|
||||
/**
|
||||
* SPDX-FileCopyrightText: Copyright 2023 Open Mobile Platform LLC <community@omp.ru> |
||||
* SPDX-License-Identifier: BSD-3-Clause |
||||
*/ |
||||
#ifndef CAMERA_PIXELS_HELPER_H |
||||
#define CAMERA_PIXELS_HELPER_H |
||||
|
||||
#include <flutter/plugin-interface.h> |
||||
#include <streamcamera/streamcamera.h> |
||||
|
||||
#include <QImage> |
||||
#include <QtCore> |
||||
|
||||
class CameraPixelsHelper |
||||
{ |
||||
public: |
||||
static uint8_t *YUVtoARGB(std::shared_ptr<const Aurora::StreamCamera::YCbCrFrame> frame); |
||||
|
||||
private: |
||||
static quint32 yuvToArgb(qint32 y, qint32 rv, qint32 guv, qint32 bu, qint32 a); |
||||
static void planarYuv420ToArgb(const uchar *y, |
||||
const uchar *u, |
||||
const uchar *v, |
||||
qint32 yStride, |
||||
qint32 uStride, |
||||
qint32 vStride, |
||||
qint32 uvPixelStride, |
||||
quint32 *rgb, |
||||
qint32 width, |
||||
qint32 height); |
||||
}; |
||||
|
||||
#endif /* CAMERA_PIXELS_HELPER_H */ |
@ -0,0 +1,35 @@
|
||||
/**
|
||||
* SPDX-FileCopyrightText: Copyright 2023 Open Mobile Platform LLC <community@omp.ru> |
||||
* SPDX-License-Identifier: BSD-3-Clause |
||||
*/ |
||||
#ifndef EMBEDDER_TEXTURE_PLUGIN_H |
||||
#define EMBEDDER_TEXTURE_PLUGIN_H |
||||
|
||||
#include <flutter/plugin-interface.h> |
||||
|
||||
#include <embedder_texture/camera.h> |
||||
|
||||
#ifdef PLUGIN_IMPL |
||||
#define PLUGIN_EXPORT __attribute__((visibility("default"))) |
||||
#else |
||||
#define PLUGIN_EXPORT |
||||
#endif |
||||
|
||||
class PLUGIN_EXPORT EmbedderTexturePlugin final : public PluginInterface |
||||
{ |
||||
public: |
||||
EmbedderTexturePlugin(); |
||||
void RegisterWithRegistrar(PluginRegistrar ®istrar) override; |
||||
|
||||
private: |
||||
void onMethodCall(const MethodCall &call); |
||||
void onCreate(const MethodCall &call); |
||||
void onRemove(const MethodCall &call); |
||||
void unimplemented(const MethodCall &call); |
||||
|
||||
private: |
||||
Camera *m_camera; |
||||
bool m_isEnableOrientationChanged = false; |
||||
}; |
||||
|
||||
#endif /* EMBEDDER_TEXTURE_PLUGIN_H */ |
@ -0,0 +1,162 @@
|
||||
import 'package:flutter/material.dart'; |
||||
|
||||
import 'embedder_texture_platform_interface.dart'; |
||||
|
||||
enum OrientationEvent { |
||||
undefined, |
||||
portrait, |
||||
landscape, |
||||
portraitFlipped, |
||||
landscapeFlipped, |
||||
} |
||||
|
||||
class EmbedderTexture extends StatefulWidget { |
||||
const EmbedderTexture({ |
||||
super.key, |
||||
required this.width, |
||||
required this.height, |
||||
}); |
||||
|
||||
final double width; |
||||
final double height; |
||||
|
||||
@override |
||||
State<EmbedderTexture> createState() => _EmbedderTextureState(); |
||||
} |
||||
|
||||
class _EmbedderTextureState extends State<EmbedderTexture> { |
||||
int _textureID = 0; |
||||
int _cameraWidth = 0; |
||||
int _cameraHeight = 0; |
||||
OrientationEvent _orientation = OrientationEvent.undefined; |
||||
|
||||
@override |
||||
initState() { |
||||
super.initState(); |
||||
EmbedderTexturePlatform.instance |
||||
.create(widget.width, widget.height) |
||||
.then((data) => setState(() { |
||||
if (mounted) { |
||||
_textureID = data['textureId']!; |
||||
_cameraWidth = data['width']!; |
||||
_cameraHeight = data['height']!; |
||||
|
||||
switch (data['orientation']!) { |
||||
case 0: |
||||
_orientation = OrientationEvent.portrait; |
||||
break; |
||||
case 90: |
||||
_orientation = OrientationEvent.landscape; |
||||
break; |
||||
case 180: |
||||
_orientation = OrientationEvent.portraitFlipped; |
||||
break; |
||||
case 270: |
||||
_orientation = OrientationEvent.landscapeFlipped; |
||||
break; |
||||
default: |
||||
_orientation = OrientationEvent.undefined; |
||||
} |
||||
|
||||
debugPrint(data.toString()); |
||||
} |
||||
})); |
||||
|
||||
EmbedderTexturePlatform.instance.onChangeOrientation().listen((event) { |
||||
setState(() { |
||||
if (mounted) { |
||||
_orientation = event; |
||||
} |
||||
}); |
||||
}); |
||||
} |
||||
|
||||
@override |
||||
void dispose() { |
||||
super.dispose(); |
||||
EmbedderTexturePlatform.instance.remove(_textureID); |
||||
} |
||||
|
||||
// @override |
||||
// Widget build(BuildContext context) { |
||||
// if (_textureID != 0) { |
||||
// double w = 0; |
||||
// double h = 0; |
||||
|
||||
// if (MediaQuery.of(context).orientation == Orientation.portrait) { |
||||
// w = _cameraWidth * widget.height / (widget.width - 40); |
||||
// h = widget.width - 40; |
||||
// } else { |
||||
// w = _cameraHeight.toDouble(); |
||||
// h = widget.height - 40 - 56; |
||||
// } |
||||
|
||||
// return Container( |
||||
// color: Colors.black, |
||||
// width: widget.width, |
||||
// height: widget.height, |
||||
// child: RotationTransition( |
||||
// turns: AlwaysStoppedAnimation( |
||||
// _orientation == OrientationEvent.portrait ? 90 / 360 : 0, |
||||
// ), |
||||
// child: SizedBox( |
||||
// width: w, |
||||
// height: h, |
||||
// child: Texture(textureId: _textureID), |
||||
// ), |
||||
// ), |
||||
// ); |
||||
// } |
||||
// return const SizedBox.shrink(); |
||||
// } |
||||
|
||||
@override |
||||
Widget build(BuildContext context) { |
||||
if (_textureID != 0) { |
||||
double w = 0; |
||||
double h = 0; |
||||
|
||||
if (_orientation == OrientationEvent.portrait || |
||||
_orientation == OrientationEvent.portraitFlipped) { |
||||
w = _cameraWidth * widget.height / (widget.width - 40); |
||||
h = widget.width - 40; |
||||
} else { |
||||
w = _cameraHeight.toDouble(); |
||||
h = widget.height - 40 - 56; |
||||
} |
||||
|
||||
AlwaysStoppedAnimation<double>? turns; |
||||
|
||||
switch (_orientation) { |
||||
case OrientationEvent.portrait: |
||||
turns = const AlwaysStoppedAnimation(90 / 360); |
||||
break; |
||||
case OrientationEvent.portraitFlipped: |
||||
turns = const AlwaysStoppedAnimation(270 / 360); |
||||
break; |
||||
case OrientationEvent.landscapeFlipped: |
||||
turns = const AlwaysStoppedAnimation(180 / 360); |
||||
break; |
||||
default: |
||||
turns = const AlwaysStoppedAnimation(0); |
||||
} |
||||
|
||||
return Container( |
||||
color: Colors.black, |
||||
width: widget.width, |
||||
height: widget.height, |
||||
child: Center( |
||||
child: RotationTransition( |
||||
turns: turns, |
||||
child: SizedBox( |
||||
width: w, |
||||
height: h, |
||||
child: Texture(textureId: _textureID), |
||||
), |
||||
), |
||||
), |
||||
); |
||||
} |
||||
return const SizedBox.shrink(); |
||||
} |
||||
} |
@ -0,0 +1,54 @@
|
||||
import 'package:embedder_texture/embedder_texture.dart'; |
||||
import 'package:flutter/foundation.dart'; |
||||
import 'package:flutter/services.dart'; |
||||
|
||||
import 'embedder_texture_platform_interface.dart'; |
||||
|
||||
/// An implementation of [LinuxOpenglPlatform] that uses method channels. |
||||
class MethodChannelEmbedderTexture extends EmbedderTexturePlatform { |
||||
/// The method channel used to interact with the native platform. |
||||
@visibleForTesting |
||||
final methodChannel = const MethodChannel('embedder_texture'); |
||||
|
||||
@override |
||||
Future<Map<dynamic, dynamic>> create(double width, double height) async { |
||||
final data = |
||||
await methodChannel.invokeMethod<Map<dynamic, dynamic>?>('create', { |
||||
'width': width.round(), |
||||
'height': height.round(), |
||||
}); |
||||
return data ?? {}; |
||||
} |
||||
|
||||
@override |
||||
Future<bool> remove(int textureId) async { |
||||
return await methodChannel.invokeMethod<bool>('remove', { |
||||
'textureId': textureId, |
||||
}) ?? |
||||
false; |
||||
} |
||||
|
||||
@override |
||||
Stream<OrientationEvent> onChangeOrientation() async* { |
||||
await for (final orientation |
||||
in const EventChannel('embedder_texture_orientation') |
||||
.receiveBroadcastStream()) { |
||||
switch (orientation) { |
||||
case 0: |
||||
yield OrientationEvent.portrait; |
||||
break; |
||||
case 90: |
||||
yield OrientationEvent.landscape; |
||||
break; |
||||
case 180: |
||||
yield OrientationEvent.portraitFlipped; |
||||
break; |
||||
case 270: |
||||
yield OrientationEvent.landscapeFlipped; |
||||
break; |
||||
default: |
||||
yield OrientationEvent.undefined; |
||||
} |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,38 @@
|
||||
import 'package:embedder_texture/embedder_texture.dart'; |
||||
import 'package:plugin_platform_interface/plugin_platform_interface.dart'; |
||||
|
||||
import 'embedder_texture_method_channel.dart'; |
||||
|
||||
abstract class EmbedderTexturePlatform extends PlatformInterface { |
||||
/// Constructs a LinuxOpenglPlatform. |
||||
EmbedderTexturePlatform() : super(token: _token); |
||||
|
||||
static final Object _token = Object(); |
||||
|
||||
static EmbedderTexturePlatform _instance = MethodChannelEmbedderTexture(); |
||||
|
||||
/// The default instance of [LinuxOpenglPlatform] to use. |
||||
/// |
||||
/// Defaults to [MethodChannelLinuxOpengl]. |
||||
static EmbedderTexturePlatform get instance => _instance; |
||||
|
||||
/// Platform-specific implementations should set this with their own |
||||
/// platform-specific class that extends [LinuxOpenglPlatform] when |
||||
/// they register themselves. |
||||
static set instance(EmbedderTexturePlatform instance) { |
||||
PlatformInterface.verifyToken(instance, _token); |
||||
_instance = instance; |
||||
} |
||||
|
||||
Stream<OrientationEvent> onChangeOrientation() { |
||||
throw UnimplementedError('onChangeOrientation() has not been implemented.'); |
||||
} |
||||
|
||||
Future<Map<dynamic, dynamic>> create(double width, double height) { |
||||
throw UnimplementedError('create() has not been implemented.'); |
||||
} |
||||
|
||||
Future<bool> remove(int textureId) { |
||||
throw UnimplementedError('remove() has not been implemented.'); |
||||
} |
||||
} |
@ -0,0 +1,24 @@
|
||||
cmake_minimum_required(VERSION 3.10) |
||||
|
||||
set(PROJECT_NAME "embedder_texture") |
||||
project(${PROJECT_NAME} LANGUAGES CXX) |
||||
|
||||
set(PLUGIN_NAME "embedder_texture_plugin") |
||||
|
||||
list(APPEND PLUGIN_SOURCES |
||||
"fl_my_texture_gl.cc" |
||||
"embedder_texture_plugin.cc" |
||||
) |
||||
|
||||
add_library(${PLUGIN_NAME} SHARED |
||||
${PLUGIN_SOURCES} |
||||
) |
||||
|
||||
apply_standard_settings(${PLUGIN_NAME}) |
||||
|
||||
set_target_properties(${PLUGIN_NAME} PROPERTIES CXX_VISIBILITY_PRESET hidden) |
||||
target_compile_definitions(${PLUGIN_NAME} PRIVATE FLUTTER_PLUGIN_IMPL) |
||||
|
||||
target_include_directories(${PLUGIN_NAME} INTERFACE "${CMAKE_CURRENT_SOURCE_DIR}/include") |
||||
target_link_libraries(${PLUGIN_NAME} PRIVATE flutter) |
||||
target_link_libraries(${PLUGIN_NAME} PUBLIC GL) |
@ -0,0 +1,173 @@
|
||||
#include "include/embedder_texture/embedder_texture_plugin.h" |
||||
#include "include/fl_my_texture_gl.h" |
||||
|
||||
#include <flutter_linux/flutter_linux.h> |
||||
#include <flutter_linux/fl_view.h> |
||||
#include <GLES2/gl2.h> |
||||
|
||||
#include "embedder_texture_plugin_private.h" |
||||
|
||||
#define EMBEDDER_TEXTURE_PLUGIN(obj) \ |
||||
(G_TYPE_CHECK_INSTANCE_CAST((obj), embedder_texture_plugin_get_type(), \
|
||||
LinuxOpenglPlugin)) |
||||
|
||||
struct _LinuxOpenglPlugin |
||||
{ |
||||
GObject parent_instance; |
||||
|
||||
unsigned int width = 0; |
||||
unsigned int height = 0; |
||||
unsigned int texture_id = 0; |
||||
|
||||
FlTexture *texture = nullptr; |
||||
FlTextureRegistrar *texture_registrar = nullptr; |
||||
|
||||
FlMyTextureGL *myTexture = nullptr; |
||||
FlView *fl_view = nullptr; |
||||
}; |
||||
|
||||
G_DEFINE_TYPE(LinuxOpenglPlugin, embedder_texture_plugin, g_object_get_type()) |
||||
|
||||
// Called when a method call is received from Flutter.
|
||||
static void embedder_texture_plugin_handle_method_call( |
||||
LinuxOpenglPlugin *self, |
||||
FlMethodCall *method_call) |
||||
{ |
||||
|
||||
g_autoptr(FlMethodResponse) response = nullptr; |
||||
|
||||
const gchar *method = fl_method_call_get_name(method_call); |
||||
|
||||
if (strcmp(method, "create") == 0) |
||||
{ |
||||
response = create(self, method_call); |
||||
} |
||||
else if (strcmp(method, "remove") == 0) |
||||
{ |
||||
response = remove(self, method_call); |
||||
} |
||||
else |
||||
{ |
||||
response = FL_METHOD_RESPONSE(fl_method_not_implemented_response_new()); |
||||
} |
||||
|
||||
fl_method_call_respond(method_call, response, nullptr); |
||||
} |
||||
|
||||
FlMethodResponse *create( |
||||
LinuxOpenglPlugin *self, |
||||
FlMethodCall *method_call) |
||||
{ |
||||
GError *error = NULL; |
||||
FlValue *args = fl_method_call_get_args(method_call); |
||||
FlValue *w = fl_value_lookup_string(args, "width"); |
||||
FlValue *h = fl_value_lookup_string(args, "height"); |
||||
|
||||
if (w != nullptr) |
||||
{ |
||||
self->width = fl_value_get_float(w); |
||||
} |
||||
|
||||
if (h != nullptr) |
||||
{ |
||||
self->height = fl_value_get_float(h); |
||||
} |
||||
|
||||
if (self->width != 0 && self->height != 0) |
||||
{ |
||||
static GLfloat pixels[] = |
||||
{ |
||||
1, 0, 0, |
||||
0, 1, 0, |
||||
0, 0, 1, |
||||
1, 1, 1 |
||||
}; |
||||
|
||||
// create in open gl
|
||||
glGenTextures(1, &self->texture_id); |
||||
glBindTexture(GL_TEXTURE_2D, self->texture_id); |
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); |
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); |
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); |
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); |
||||
|
||||
// create
|
||||
self->myTexture = fl_my_texture_gl_new(GL_TEXTURE_2D, self->texture_id, self->width, self->height); |
||||
self->texture = FL_TEXTURE(self->myTexture); |
||||
|
||||
// reg
|
||||
fl_texture_registrar_register_texture(self->texture_registrar, self->texture); |
||||
|
||||
// draw
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 2, 2, 0, GL_RGB, GL_FLOAT, pixels); |
||||
|
||||
// send id
|
||||
g_autoptr(FlValue) result = fl_value_new_int(reinterpret_cast<int64_t>(self->texture)); |
||||
return FL_METHOD_RESPONSE(fl_method_success_response_new(result)); |
||||
} |
||||
|
||||
return FL_METHOD_RESPONSE(fl_method_error_response_new( |
||||
"500", |
||||
"Method create() called without passing width or height parameters!", |
||||
nullptr)); |
||||
} |
||||
|
||||
FlMethodResponse *remove( |
||||
LinuxOpenglPlugin *self, |
||||
FlMethodCall *method_call) |
||||
{ |
||||
FlValue *args = fl_method_call_get_args(method_call); |
||||
FlValue *id = fl_value_lookup_string(args, "textureId"); |
||||
|
||||
if (id != nullptr) |
||||
{ |
||||
int textureId = fl_value_get_int(id); |
||||
fl_texture_registrar_unregister_texture(self->texture_registrar, self->texture); |
||||
g_autoptr(FlValue) result = fl_value_new_null(); |
||||
return FL_METHOD_RESPONSE(fl_method_success_response_new(result)); |
||||
} |
||||
|
||||
return FL_METHOD_RESPONSE(fl_method_error_response_new( |
||||
"500", |
||||
"Method remove() called without passing textureId parameters!", |
||||
nullptr)); |
||||
} |
||||
|
||||
static void embedder_texture_plugin_dispose(GObject *object) |
||||
{ |
||||
G_OBJECT_CLASS(embedder_texture_plugin_parent_class)->dispose(object); |
||||
} |
||||
|
||||
static void embedder_texture_plugin_class_init(LinuxOpenglPluginClass *klass) |
||||
{ |
||||
G_OBJECT_CLASS(klass)->dispose = embedder_texture_plugin_dispose; |
||||
} |
||||
|
||||
static void embedder_texture_plugin_init(LinuxOpenglPlugin *self) {} |
||||
|
||||
static void method_call_cb(FlMethodChannel *channel, FlMethodCall *method_call, |
||||
gpointer user_data) |
||||
{ |
||||
LinuxOpenglPlugin *plugin = EMBEDDER_TEXTURE_PLUGIN(user_data); |
||||
embedder_texture_plugin_handle_method_call(plugin, method_call); |
||||
} |
||||
|
||||
void embedder_texture_plugin_register_with_registrar(FlPluginRegistrar *registrar) |
||||
{ |
||||
LinuxOpenglPlugin *plugin = EMBEDDER_TEXTURE_PLUGIN( |
||||
g_object_new(embedder_texture_plugin_get_type(), nullptr)); |
||||
|
||||
plugin->fl_view = fl_plugin_registrar_get_view(registrar); |
||||
plugin->texture_registrar = fl_plugin_registrar_get_texture_registrar(registrar); |
||||
|
||||
g_autoptr(FlStandardMethodCodec) codec = fl_standard_method_codec_new(); |
||||
g_autoptr(FlMethodChannel) channel = |
||||
fl_method_channel_new(fl_plugin_registrar_get_messenger(registrar), |
||||
"embedder_texture", |
||||
FL_METHOD_CODEC(codec)); |
||||
fl_method_channel_set_method_call_handler(channel, method_call_cb, |
||||
g_object_ref(plugin), |
||||
g_object_unref); |
||||
|
||||
g_object_unref(plugin); |
||||
} |
@ -0,0 +1,7 @@
|
||||
#include <flutter_linux/flutter_linux.h> |
||||
|
||||
#include "include/embedder_texture/embedder_texture_plugin.h" |
||||
|
||||
FlMethodResponse *create(LinuxOpenglPlugin *self, FlMethodCall *method_call); |
||||
|
||||
FlMethodResponse *remove(LinuxOpenglPlugin *self, FlMethodCall *method_call); |
@ -0,0 +1,44 @@
|
||||
#include "include/fl_my_texture_gl.h" |
||||
|
||||
G_DEFINE_TYPE(FlMyTextureGL, |
||||
fl_my_texture_gl, |
||||
fl_texture_gl_get_type()) |
||||
|
||||
static gboolean fl_my_texture_gl_populate(FlTextureGL *texture, |
||||
uint32_t *target, |
||||
uint32_t *name, |
||||
uint32_t *width, |
||||
uint32_t *height, |
||||
GError **error) |
||||
{ |
||||
FlMyTextureGL* f = (FlMyTextureGL*) texture; |
||||
*target = f->target; |
||||
*name = f->name; |
||||
*width = f->width; |
||||
*height = f->height; |
||||
return true; |
||||
} |
||||
|
||||
FlMyTextureGL *fl_my_texture_gl_new(uint32_t target, |
||||
uint32_t name, |
||||
uint32_t width, |
||||
uint32_t height) |
||||
{ |
||||
auto r = FL_MY_TEXTURE_GL(g_object_new(fl_my_texture_gl_get_type(), nullptr)); |
||||
r->target = target; |
||||
r->name = name; |
||||
r->width = width; |
||||
r->height = height; |
||||
return r; |
||||
} |
||||
|
||||
static void fl_my_texture_gl_class_init( |
||||
FlMyTextureGLClass *klass) |
||||
{ |
||||
FL_TEXTURE_GL_CLASS(klass)->populate = |
||||
fl_my_texture_gl_populate; |
||||
} |
||||
|
||||
static void fl_my_texture_gl_init(FlMyTextureGL *self) |
||||
{ |
||||
} |
@ -0,0 +1,26 @@
|
||||
#ifndef FLUTTER_PLUGIN_EMBEDDER_TEXTURE_PLUGIN_H_ |
||||
#define FLUTTER_PLUGIN_EMBEDDER_TEXTURE_PLUGIN_H_ |
||||
|
||||
#include <flutter_linux/flutter_linux.h> |
||||
|
||||
G_BEGIN_DECLS |
||||
|
||||
#ifdef FLUTTER_PLUGIN_IMPL |
||||
#define FLUTTER_PLUGIN_EXPORT __attribute__((visibility("default"))) |
||||
#else |
||||
#define FLUTTER_PLUGIN_EXPORT |
||||
#endif |
||||
|
||||
typedef struct _LinuxOpenglPlugin LinuxOpenglPlugin; |
||||
typedef struct { |
||||
GObjectClass parent_class; |
||||
} LinuxOpenglPluginClass; |
||||
|
||||
FLUTTER_PLUGIN_EXPORT GType embedder_texture_plugin_get_type(); |
||||
|
||||
FLUTTER_PLUGIN_EXPORT void embedder_texture_plugin_register_with_registrar( |
||||
FlPluginRegistrar* registrar); |
||||
|
||||
G_END_DECLS |
||||
|
||||
#endif // FLUTTER_PLUGIN_EMBEDDER_TEXTURE_PLUGIN_H_
|
@ -0,0 +1,28 @@
|
||||
#ifndef FLUTTER_MY_TEXTURE_H |
||||
#define FLUTTER_MY_TEXTURE_H |
||||
|
||||
#include <gtk/gtk.h> |
||||
#include <glib-object.h> |
||||
#include "embedder_texture/embedder_texture_plugin.h" |
||||
#include <flutter_linux/flutter_linux.h> |
||||
|
||||
G_DECLARE_FINAL_TYPE(FlMyTextureGL, |
||||
fl_my_texture_gl, |
||||
FL, |
||||
MY_TEXTURE_GL, |
||||
FlTextureGL) |
||||
|
||||
struct _FlMyTextureGL |
||||
{ |
||||
FlTextureGL parent_instance; |
||||
uint32_t target; |
||||
uint32_t name; |
||||
uint32_t width; |
||||
uint32_t height; |
||||
}; |
||||
|
||||
FlMyTextureGL *fl_my_texture_gl_new(uint32_t target, |
||||
uint32_t name, |
||||
uint32_t width, |
||||
uint32_t height); |
||||
#endif // FLUTTER_MY_TEXTURE_H
|
@ -0,0 +1,25 @@
|
||||
name: embedder_texture |
||||
description: Example create texture. |
||||
version: 0.0.1 |
||||
|
||||
environment: |
||||
sdk: '>=3.0.6 <4.0.0' |
||||
flutter: ">=3.3.0" |
||||
|
||||
dependencies: |
||||
flutter: |
||||
sdk: flutter |
||||
plugin_platform_interface: ^2.0.2 |
||||
|
||||
dev_dependencies: |
||||
flutter_test: |
||||
sdk: flutter |
||||
flutter_lints: ^2.0.0 |
||||
|
||||
flutter: |
||||
plugin: |
||||
platforms: |
||||
linux: |
||||
pluginClass: EmbedderTexturePlugin |
||||
aurora: |
||||
pluginClass: EmbedderTexturePlugin |
Loading…
Reference in new issue