Bazel 编译 iOS Render framework
This commit is contained in:
parent
63e679d99c
commit
e2bfbbbfb4
|
@ -417,3 +417,7 @@ libedgetpu_dependencies()
|
|||
|
||||
load("@coral_crosstool//:configure.bzl", "cc_crosstool")
|
||||
cc_crosstool(name = "crosstool")
|
||||
android_sdk_repository(name = "androidsdk", path = "/Users/wangrenzhu/Library/Android/sdk")
|
||||
android_ndk_repository(name = "androidndk", api_level=21, path = "/Users/wangrenzhu/Library/Android/sdk/ndk/21.2.6472646")
|
||||
# android_sdk_repository(name = "androidsdk", path = "/Users/wangrenzhu/Android/sdk")
|
||||
# android_ndk_repository(name = "androidndk", api_level=21, path = "/Users/wangrenzhu/Android/sdk/ndk/android-ndk-r21")
|
||||
|
|
423
WORKSPACE-e
Normal file
423
WORKSPACE-e
Normal file
|
@ -0,0 +1,423 @@
|
|||
workspace(name = "mediapipe")
|
||||
|
||||
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
|
||||
|
||||
http_archive(
|
||||
name = "bazel_skylib",
|
||||
type = "tar.gz",
|
||||
urls = [
|
||||
"https://github.com/bazelbuild/bazel-skylib/releases/download/1.0.3/bazel-skylib-1.0.3.tar.gz",
|
||||
"https://mirror.bazel.build/github.com/bazelbuild/bazel-skylib/releases/download/1.0.3/bazel-skylib-1.0.3.tar.gz",
|
||||
],
|
||||
sha256 = "1c531376ac7e5a180e0237938a2536de0c54d93f5c278634818e0efc952dd56c",
|
||||
)
|
||||
load("@bazel_skylib//:workspace.bzl", "bazel_skylib_workspace")
|
||||
bazel_skylib_workspace()
|
||||
load("@bazel_skylib//lib:versions.bzl", "versions")
|
||||
versions.check(minimum_bazel_version = "3.7.2")
|
||||
|
||||
# ABSL cpp library lts_2021_03_24, patch 2.
|
||||
http_archive(
|
||||
name = "com_google_absl",
|
||||
urls = [
|
||||
"https://github.com/abseil/abseil-cpp/archive/refs/tags/20210324.2.tar.gz",
|
||||
],
|
||||
# Remove after https://github.com/abseil/abseil-cpp/issues/326 is solved.
|
||||
patches = [
|
||||
"@//third_party:com_google_absl_f863b622fe13612433fdf43f76547d5edda0c93001.diff"
|
||||
],
|
||||
patch_args = [
|
||||
"-p1",
|
||||
],
|
||||
strip_prefix = "abseil-cpp-20210324.2",
|
||||
sha256 = "59b862f50e710277f8ede96f083a5bb8d7c9595376146838b9580be90374ee1f"
|
||||
)
|
||||
|
||||
http_archive(
|
||||
name = "rules_cc",
|
||||
strip_prefix = "rules_cc-2f8c04c04462ab83c545ab14c0da68c3b4c96191",
|
||||
# The commit can be updated if the build passes. Last updated 6/23/22.
|
||||
urls = ["https://github.com/bazelbuild/rules_cc/archive/2f8c04c04462ab83c545ab14c0da68c3b4c96191.zip"],
|
||||
)
|
||||
|
||||
http_archive(
|
||||
name = "rules_foreign_cc",
|
||||
strip_prefix = "rules_foreign_cc-0.1.0",
|
||||
url = "https://github.com/bazelbuild/rules_foreign_cc/archive/0.1.0.zip",
|
||||
)
|
||||
|
||||
load("@rules_foreign_cc//:workspace_definitions.bzl", "rules_foreign_cc_dependencies")
|
||||
|
||||
rules_foreign_cc_dependencies()
|
||||
|
||||
# This is used to select all contents of the archives for CMake-based packages to give CMake access to them.
|
||||
all_content = """filegroup(name = "all", srcs = glob(["**"]), visibility = ["//visibility:public"])"""
|
||||
|
||||
# GoogleTest/GoogleMock framework. Used by most unit-tests.
|
||||
# Last updated 2021-07-02.
|
||||
http_archive(
|
||||
name = "com_google_googletest",
|
||||
urls = ["https://github.com/google/googletest/archive/4ec4cd23f486bf70efcc5d2caa40f24368f752e3.zip"],
|
||||
strip_prefix = "googletest-4ec4cd23f486bf70efcc5d2caa40f24368f752e3",
|
||||
sha256 = "de682ea824bfffba05b4e33b67431c247397d6175962534305136aa06f92e049",
|
||||
)
|
||||
|
||||
# Google Benchmark library v1.6.1 released on 2022-01-10.
|
||||
http_archive(
|
||||
name = "com_google_benchmark",
|
||||
urls = ["https://github.com/google/benchmark/archive/refs/tags/v1.6.1.tar.gz"],
|
||||
strip_prefix = "benchmark-1.6.1",
|
||||
sha256 = "6132883bc8c9b0df5375b16ab520fac1a85dc9e4cf5be59480448ece74b278d4",
|
||||
build_file = "@//third_party:benchmark.BUILD",
|
||||
)
|
||||
|
||||
# gflags needed by glog
|
||||
http_archive(
|
||||
name = "com_github_gflags_gflags",
|
||||
strip_prefix = "gflags-2.2.2",
|
||||
sha256 = "19713a36c9f32b33df59d1c79b4958434cb005b5b47dc5400a7a4b078111d9b5",
|
||||
url = "https://github.com/gflags/gflags/archive/v2.2.2.zip",
|
||||
)
|
||||
|
||||
# 2020-08-21
|
||||
http_archive(
|
||||
name = "com_github_glog_glog",
|
||||
strip_prefix = "glog-0a2e5931bd5ff22fd3bf8999eb8ce776f159cda6",
|
||||
sha256 = "58c9b3b6aaa4dd8b836c0fd8f65d0f941441fb95e27212c5eeb9979cfd3592ab",
|
||||
urls = [
|
||||
"https://github.com/google/glog/archive/0a2e5931bd5ff22fd3bf8999eb8ce776f159cda6.zip",
|
||||
],
|
||||
)
|
||||
http_archive(
|
||||
name = "com_github_glog_glog_no_gflags",
|
||||
strip_prefix = "glog-0a2e5931bd5ff22fd3bf8999eb8ce776f159cda6",
|
||||
sha256 = "58c9b3b6aaa4dd8b836c0fd8f65d0f941441fb95e27212c5eeb9979cfd3592ab",
|
||||
build_file = "@//third_party:glog_no_gflags.BUILD",
|
||||
urls = [
|
||||
"https://github.com/google/glog/archive/0a2e5931bd5ff22fd3bf8999eb8ce776f159cda6.zip",
|
||||
],
|
||||
patches = [
|
||||
"@//third_party:com_github_glog_glog_9779e5ea6ef59562b030248947f787d1256132ae.diff",
|
||||
],
|
||||
patch_args = [
|
||||
"-p1",
|
||||
],
|
||||
)
|
||||
|
||||
# easyexif
|
||||
http_archive(
|
||||
name = "easyexif",
|
||||
url = "https://github.com/mayanklahiri/easyexif/archive/master.zip",
|
||||
strip_prefix = "easyexif-master",
|
||||
build_file = "@//third_party:easyexif.BUILD",
|
||||
)
|
||||
|
||||
# libyuv
|
||||
http_archive(
|
||||
name = "libyuv",
|
||||
# Error: operand type mismatch for `vbroadcastss' caused by commit 8a13626e42f7fdcf3a6acbb0316760ee54cda7d8.
|
||||
urls = ["https://chromium.googlesource.com/libyuv/libyuv/+archive/2525698acba9bf9b701ba6b4d9584291a1f62257.tar.gz"],
|
||||
build_file = "@//third_party:libyuv.BUILD",
|
||||
)
|
||||
|
||||
# Note: protobuf-javalite is no longer released as a separate download, it's included in the main Java download.
|
||||
# ...but the Java download is currently broken, so we use the "source" download.
|
||||
http_archive(
|
||||
name = "com_google_protobuf_javalite",
|
||||
sha256 = "87407cd28e7a9c95d9f61a098a53cf031109d451a7763e7dd1253abf8b4df422",
|
||||
strip_prefix = "protobuf-3.19.1",
|
||||
urls = ["https://github.com/protocolbuffers/protobuf/archive/v3.19.1.tar.gz"],
|
||||
)
|
||||
|
||||
http_archive(
|
||||
name = "com_google_protobuf",
|
||||
sha256 = "87407cd28e7a9c95d9f61a098a53cf031109d451a7763e7dd1253abf8b4df422",
|
||||
strip_prefix = "protobuf-3.19.1",
|
||||
urls = ["https://github.com/protocolbuffers/protobuf/archive/v3.19.1.tar.gz"],
|
||||
patches = [
|
||||
"@//third_party:com_google_protobuf_fixes.diff"
|
||||
],
|
||||
patch_args = [
|
||||
"-p1",
|
||||
],
|
||||
)
|
||||
|
||||
http_archive(
|
||||
name = "com_google_audio_tools",
|
||||
strip_prefix = "multichannel-audio-tools-master",
|
||||
urls = ["https://github.com/google/multichannel-audio-tools/archive/master.zip"],
|
||||
)
|
||||
|
||||
# 2020-07-09
|
||||
http_archive(
|
||||
name = "pybind11_bazel",
|
||||
strip_prefix = "pybind11_bazel-203508e14aab7309892a1c5f7dd05debda22d9a5",
|
||||
urls = ["https://github.com/pybind/pybind11_bazel/archive/203508e14aab7309892a1c5f7dd05debda22d9a5.zip"],
|
||||
sha256 = "75922da3a1bdb417d820398eb03d4e9bd067c4905a4246d35a44c01d62154d91",
|
||||
)
|
||||
|
||||
# Point to the commit that deprecates the usage of Eigen::MappedSparseMatrix.
|
||||
http_archive(
|
||||
name = "pybind11",
|
||||
urls = [
|
||||
"https://github.com/pybind/pybind11/archive/70a58c577eaf067748c2ec31bfd0b0a614cffba6.zip",
|
||||
],
|
||||
sha256 = "b971842fab1b5b8f3815a2302331782b7d137fef0e06502422bc4bc360f4956c",
|
||||
strip_prefix = "pybind11-70a58c577eaf067748c2ec31bfd0b0a614cffba6",
|
||||
build_file = "@pybind11_bazel//:pybind11.BUILD",
|
||||
)
|
||||
|
||||
# Point to the commit that deprecates the usage of Eigen::MappedSparseMatrix.
|
||||
http_archive(
|
||||
name = "ceres_solver",
|
||||
url = "https://github.com/ceres-solver/ceres-solver/archive/123fba61cf2611a3c8bddc9d91416db26b10b558.zip",
|
||||
patches = [
|
||||
"@//third_party:ceres_solver_compatibility_fixes.diff"
|
||||
],
|
||||
patch_args = [
|
||||
"-p1",
|
||||
],
|
||||
strip_prefix = "ceres-solver-123fba61cf2611a3c8bddc9d91416db26b10b558",
|
||||
sha256 = "8b7b16ceb363420e0fd499576daf73fa338adb0b1449f58bea7862766baa1ac7"
|
||||
)
|
||||
|
||||
http_archive(
|
||||
name = "opencv",
|
||||
build_file_content = all_content,
|
||||
strip_prefix = "opencv-3.4.10",
|
||||
urls = ["https://github.com/opencv/opencv/archive/3.4.10.tar.gz"],
|
||||
)
|
||||
|
||||
new_local_repository(
|
||||
name = "linux_opencv",
|
||||
build_file = "@//third_party:opencv_linux.BUILD",
|
||||
path = "/usr",
|
||||
)
|
||||
|
||||
new_local_repository(
|
||||
name = "linux_ffmpeg",
|
||||
build_file = "@//third_party:ffmpeg_linux.BUILD",
|
||||
path = "/usr"
|
||||
)
|
||||
|
||||
new_local_repository(
|
||||
name = "macos_opencv",
|
||||
build_file = "@//third_party:opencv_macos.BUILD",
|
||||
# For local MacOS builds, the path should point to an opencv@3 installation.
|
||||
# If you edit the path here, you will also need to update the corresponding
|
||||
# prefix in "opencv_macos.BUILD".
|
||||
path = "/usr/local",
|
||||
)
|
||||
|
||||
new_local_repository(
|
||||
name = "macos_ffmpeg",
|
||||
build_file = "@//third_party:ffmpeg_macos.BUILD",
|
||||
path = "/usr/local/opt/ffmpeg",
|
||||
)
|
||||
|
||||
new_local_repository(
|
||||
name = "windows_opencv",
|
||||
build_file = "@//third_party:opencv_windows.BUILD",
|
||||
path = "C:\\opencv\\build",
|
||||
)
|
||||
|
||||
http_archive(
|
||||
name = "android_opencv",
|
||||
build_file = "@//third_party:opencv_android.BUILD",
|
||||
strip_prefix = "OpenCV-android-sdk",
|
||||
type = "zip",
|
||||
url = "https://github.com/opencv/opencv/releases/download/3.4.3/opencv-3.4.3-android-sdk.zip",
|
||||
)
|
||||
|
||||
# After OpenCV 3.2.0, the pre-compiled opencv2.framework has google protobuf symbols, which will
|
||||
# trigger duplicate symbol errors in the linking stage of building a mediapipe ios app.
|
||||
# To get a higher version of OpenCV for iOS, opencv2.framework needs to be built from source with
|
||||
# '-DBUILD_PROTOBUF=OFF -DBUILD_opencv_dnn=OFF'.
|
||||
http_archive(
|
||||
name = "ios_opencv",
|
||||
sha256 = "7dd536d06f59e6e1156b546bd581523d8df92ce83440002885ec5abc06558de2",
|
||||
build_file = "@//third_party:opencv_ios.BUILD",
|
||||
type = "zip",
|
||||
url = "https://github.com/opencv/opencv/releases/download/3.2.0/opencv-3.2.0-ios-framework.zip",
|
||||
)
|
||||
|
||||
http_archive(
|
||||
name = "stblib",
|
||||
strip_prefix = "stb-b42009b3b9d4ca35bc703f5310eedc74f584be58",
|
||||
sha256 = "13a99ad430e930907f5611325ec384168a958bf7610e63e60e2fd8e7b7379610",
|
||||
urls = ["https://github.com/nothings/stb/archive/b42009b3b9d4ca35bc703f5310eedc74f584be58.tar.gz"],
|
||||
build_file = "@//third_party:stblib.BUILD",
|
||||
patches = [
|
||||
"@//third_party:stb_image_impl.diff"
|
||||
],
|
||||
patch_args = [
|
||||
"-p1",
|
||||
],
|
||||
)
|
||||
|
||||
# iOS basic build deps.
|
||||
|
||||
http_archive(
|
||||
name = "build_bazel_rules_apple",
|
||||
sha256 = "77e8bf6fda706f420a55874ae6ee4df0c9d95da6c7838228b26910fc82eea5a2",
|
||||
url = "https://github.com/bazelbuild/rules_apple/releases/download/0.32.0/rules_apple.0.32.0.tar.gz",
|
||||
patches = [
|
||||
# Bypass checking ios unit test runner when building MP ios applications.
|
||||
"@//third_party:build_bazel_rules_apple_bypass_test_runner_check.diff"
|
||||
],
|
||||
patch_args = [
|
||||
"-p1",
|
||||
],
|
||||
)
|
||||
|
||||
load(
|
||||
"@build_bazel_rules_apple//apple:repositories.bzl",
|
||||
"apple_rules_dependencies",
|
||||
)
|
||||
|
||||
apple_rules_dependencies()
|
||||
|
||||
load(
|
||||
"@build_bazel_rules_swift//swift:repositories.bzl",
|
||||
"swift_rules_dependencies",
|
||||
)
|
||||
|
||||
swift_rules_dependencies()
|
||||
|
||||
http_archive(
|
||||
name = "build_bazel_apple_support",
|
||||
sha256 = "741366f79d900c11e11d8efd6cc6c66a31bfb2451178b58e0b5edc6f1db17b35",
|
||||
urls = [
|
||||
"https://github.com/bazelbuild/apple_support/releases/download/0.10.0/apple_support.0.10.0.tar.gz"
|
||||
],
|
||||
)
|
||||
|
||||
load(
|
||||
"@build_bazel_apple_support//lib:repositories.bzl",
|
||||
"apple_support_dependencies",
|
||||
)
|
||||
|
||||
apple_support_dependencies()
|
||||
|
||||
# More iOS deps.
|
||||
|
||||
http_archive(
|
||||
name = "google_toolbox_for_mac",
|
||||
url = "https://github.com/google/google-toolbox-for-mac/archive/v2.2.1.zip",
|
||||
sha256 = "e3ac053813c989a88703556df4dc4466e424e30d32108433ed6beaec76ba4fdc",
|
||||
strip_prefix = "google-toolbox-for-mac-2.2.1",
|
||||
build_file = "@//third_party:google_toolbox_for_mac.BUILD",
|
||||
)
|
||||
|
||||
# Maven dependencies.
|
||||
|
||||
RULES_JVM_EXTERNAL_TAG = "4.0"
|
||||
RULES_JVM_EXTERNAL_SHA = "31701ad93dbfe544d597dbe62c9a1fdd76d81d8a9150c2bf1ecf928ecdf97169"
|
||||
|
||||
http_archive(
|
||||
name = "rules_jvm_external",
|
||||
strip_prefix = "rules_jvm_external-%s" % RULES_JVM_EXTERNAL_TAG,
|
||||
sha256 = RULES_JVM_EXTERNAL_SHA,
|
||||
url = "https://github.com/bazelbuild/rules_jvm_external/archive/%s.zip" % RULES_JVM_EXTERNAL_TAG,
|
||||
)
|
||||
|
||||
load("@rules_jvm_external//:defs.bzl", "maven_install")
|
||||
|
||||
# Important: there can only be one maven_install rule. Add new maven deps here.
|
||||
maven_install(
|
||||
artifacts = [
|
||||
"androidx.concurrent:concurrent-futures:1.0.0-alpha03",
|
||||
"androidx.lifecycle:lifecycle-common:2.3.1",
|
||||
"androidx.activity:activity:1.2.2",
|
||||
"androidx.exifinterface:exifinterface:1.3.3",
|
||||
"androidx.fragment:fragment:1.3.4",
|
||||
"androidx.annotation:annotation:aar:1.1.0",
|
||||
"androidx.appcompat:appcompat:aar:1.1.0-rc01",
|
||||
"androidx.camera:camera-core:1.0.0-beta10",
|
||||
"androidx.camera:camera-camera2:1.0.0-beta10",
|
||||
"androidx.camera:camera-lifecycle:1.0.0-beta10",
|
||||
"androidx.constraintlayout:constraintlayout:aar:1.1.3",
|
||||
"androidx.core:core:aar:1.1.0-rc03",
|
||||
"androidx.legacy:legacy-support-v4:aar:1.0.0",
|
||||
"androidx.recyclerview:recyclerview:aar:1.1.0-beta02",
|
||||
"androidx.test.espresso:espresso-core:3.1.1",
|
||||
"com.github.bumptech.glide:glide:4.11.0",
|
||||
"com.google.android.material:material:aar:1.0.0-rc01",
|
||||
"com.google.auto.value:auto-value:1.8.1",
|
||||
"com.google.auto.value:auto-value-annotations:1.8.1",
|
||||
"com.google.code.findbugs:jsr305:latest.release",
|
||||
"com.google.android.datatransport:transport-api:3.0.0",
|
||||
"com.google.android.datatransport:transport-backend-cct:3.1.0",
|
||||
"com.google.android.datatransport:transport-runtime:3.1.0",
|
||||
"com.google.flogger:flogger-system-backend:0.6",
|
||||
"com.google.flogger:flogger:0.6",
|
||||
"com.google.guava:guava:27.0.1-android",
|
||||
"com.google.guava:listenablefuture:1.0",
|
||||
"junit:junit:4.12",
|
||||
"org.hamcrest:hamcrest-library:1.3",
|
||||
],
|
||||
repositories = [
|
||||
"https://maven.google.com",
|
||||
"https://dl.google.com/dl/android/maven2",
|
||||
"https://repo1.maven.org/maven2",
|
||||
"https://jcenter.bintray.com",
|
||||
],
|
||||
fetch_sources = True,
|
||||
version_conflict_policy = "pinned",
|
||||
)
|
||||
|
||||
# Needed by TensorFlow
|
||||
http_archive(
|
||||
name = "io_bazel_rules_closure",
|
||||
sha256 = "e0a111000aeed2051f29fcc7a3f83be3ad8c6c93c186e64beb1ad313f0c7f9f9",
|
||||
strip_prefix = "rules_closure-cf1e44edb908e9616030cc83d085989b8e6cd6df",
|
||||
urls = [
|
||||
"http://mirror.tensorflow.org/github.com/bazelbuild/rules_closure/archive/cf1e44edb908e9616030cc83d085989b8e6cd6df.tar.gz",
|
||||
"https://github.com/bazelbuild/rules_closure/archive/cf1e44edb908e9616030cc83d085989b8e6cd6df.tar.gz", # 2019-04-04
|
||||
],
|
||||
)
|
||||
|
||||
# Tensorflow repo should always go after the other external dependencies.
|
||||
# 2022-02-15
|
||||
_TENSORFLOW_GIT_COMMIT = "a3419acc751dfc19caf4d34a1594e1f76810ec58"
|
||||
_TENSORFLOW_SHA256 = "b95b2a83632d4055742ae1a2dcc96b45da6c12a339462dbc76c8bca505308e3a"
|
||||
http_archive(
|
||||
name = "org_tensorflow",
|
||||
urls = [
|
||||
"https://github.com/tensorflow/tensorflow/archive/%s.tar.gz" % _TENSORFLOW_GIT_COMMIT,
|
||||
],
|
||||
patches = [
|
||||
"@//third_party:org_tensorflow_compatibility_fixes.diff",
|
||||
# Diff is generated with a script, don't update it manually.
|
||||
"@//third_party:org_tensorflow_custom_ops.diff",
|
||||
],
|
||||
patch_args = [
|
||||
"-p1",
|
||||
],
|
||||
strip_prefix = "tensorflow-%s" % _TENSORFLOW_GIT_COMMIT,
|
||||
sha256 = _TENSORFLOW_SHA256,
|
||||
)
|
||||
|
||||
load("@org_tensorflow//tensorflow:workspace3.bzl", "tf_workspace3")
|
||||
tf_workspace3()
|
||||
load("@org_tensorflow//tensorflow:workspace2.bzl", "tf_workspace2")
|
||||
tf_workspace2()
|
||||
|
||||
# Edge TPU
|
||||
http_archive(
|
||||
name = "libedgetpu",
|
||||
sha256 = "14d5527a943a25bc648c28a9961f954f70ba4d79c0a9ca5ae226e1831d72fe80",
|
||||
strip_prefix = "libedgetpu-3164995622300286ef2bb14d7fdc2792dae045b7",
|
||||
urls = [
|
||||
"https://github.com/google-coral/libedgetpu/archive/3164995622300286ef2bb14d7fdc2792dae045b7.tar.gz"
|
||||
],
|
||||
)
|
||||
load("@libedgetpu//:workspace.bzl", "libedgetpu_dependencies")
|
||||
libedgetpu_dependencies()
|
||||
|
||||
load("@coral_crosstool//:configure.bzl", "cc_crosstool")
|
||||
cc_crosstool(name = "crosstool")
|
||||
android_sdk_repository(name = "androidsdk", path = "/Users/wangrenzhu/Library/Android/sdk")
|
||||
android_ndk_repository(name = "androidndk", api_level=21, path = "/Users/wangrenzhu/Library/Android/sdk/ndk/21.2.6472646")
|
||||
# android_sdk_repository(name = "androidsdk", path = "/Users/wangrenzhu/Android/sdk")
|
||||
# android_ndk_repository(name = "androidndk", api_level=21, path = "/Users/wangrenzhu/Android/sdk/ndk/android-ndk-r21")
|
|
@ -12,17 +12,6 @@
|
|||
"mediapipe/examples/ios",
|
||||
"mediapipe/examples/ios/facedetectioncpu",
|
||||
"mediapipe/examples/ios/facedetectiongpu",
|
||||
"mediapipe/examples/ios/faceeffect",
|
||||
"mediapipe/examples/ios/facemeshgpu",
|
||||
"mediapipe/examples/ios/handdetectiongpu",
|
||||
"mediapipe/examples/ios/handtrackinggpu",
|
||||
"mediapipe/examples/ios/holistictrackinggpu",
|
||||
"mediapipe/examples/ios/iristrackinggpu",
|
||||
"mediapipe/examples/ios/objectdetectioncpu",
|
||||
"mediapipe/examples/ios/objectdetectiongpu",
|
||||
"mediapipe/examples/ios/objectdetectiontrackinggpu",
|
||||
"mediapipe/examples/ios/posetrackinggpu",
|
||||
"mediapipe/examples/ios/selfiesegmentationgpu",
|
||||
"mediapipe/objc"
|
||||
],
|
||||
"projectName" : "Mediapipe",
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
load("//mediapipe/framework/tool:mediapipe_graph.bzl", "mediapipe_binary_graph")
|
||||
load("@build_bazel_rules_apple//apple:ios.bzl", "ios_framework")
|
||||
|
||||
package(default_visibility = ["//visibility:private"])
|
||||
|
||||
|
|
52
mediapipe/objc/Info.plist
Normal file
52
mediapipe/objc/Info.plist
Normal file
|
@ -0,0 +1,52 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
||||
<key>CFBundleDisplayName</key>
|
||||
<string>olapipe</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>olapipe</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>com.ola.olapipe</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>olapipe</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
<key>LSRequiresIPhoneOS</key>
|
||||
<true/>
|
||||
<key>NSAppTransportSecurity</key>
|
||||
<dict>
|
||||
<key>NSAllowsArbitraryLoads</key>
|
||||
<true/>
|
||||
</dict>
|
||||
<key>NSCameraUsageDescription</key>
|
||||
<string>需要使用摄像头输入</string>
|
||||
<key>UILaunchStoryboardName</key>
|
||||
<string>LaunchScreen</string>
|
||||
<key>UIRequiredDeviceCapabilities</key>
|
||||
<array>
|
||||
<string>armv7</string>
|
||||
</array>
|
||||
<key>UISupportedInterfaceOrientations</key>
|
||||
<array>
|
||||
<string>UIInterfaceOrientationPortrait</string>
|
||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||
</array>
|
||||
<key>UISupportedInterfaceOrientations~ipad</key>
|
||||
<array>
|
||||
<string>UIInterfaceOrientationPortrait</string>
|
||||
<string>UIInterfaceOrientationPortraitUpsideDown</string>
|
||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
0
mediapipe/render/BUILD
Normal file
0
mediapipe/render/BUILD
Normal file
338
mediapipe/render/android/AndroidDirectAccessFrameBuffer.cpp
Normal file
338
mediapipe/render/android/AndroidDirectAccessFrameBuffer.cpp
Normal file
|
@ -0,0 +1,338 @@
|
|||
//
|
||||
// Created by jormin on 2021/4/30.
|
||||
//
|
||||
|
||||
#include "AndroidDirectAccessFrameBuffer.h"
|
||||
|
||||
/**
|
||||
* {@see https://android.googlesource.com/platform/cts/+/master/tests/tests/nativehardware/jni/AHardwareBufferGLTest.cpp}
|
||||
*/
|
||||
namespace QImage {
|
||||
|
||||
}
|
||||
|
||||
// NS_GI_BEGIN
|
||||
|
||||
// USING_NS_GI
|
||||
// using namespace QImage;
|
||||
|
||||
// AndroidDirectAccessFrameBuffer::AndroidDirectAccessFrameBuffer(Context *context, int width,
|
||||
// int height,
|
||||
// const TextureAttributes textureAttributes)
|
||||
// : QImage::Framebuffer() {
|
||||
// _context = context;
|
||||
// useTextureCache = true;
|
||||
// _width = width;
|
||||
// _height = height;
|
||||
// _textureAttributes = textureAttributes;
|
||||
|
||||
// /**
|
||||
// * As a general rule, you should never call virtual functions in constructors or destructors.
|
||||
// * If you do, those calls will never go to a more derived class than the currently executing constructor or destructor.
|
||||
// * In other words, during construction and destruction, virtual functions aren't virtual.
|
||||
// */
|
||||
// AndroidDirectAccessFrameBuffer::_generateFramebuffer(true/*not use*/);
|
||||
|
||||
// _context->_framebuffers.push_back(this);
|
||||
// }
|
||||
|
||||
|
||||
// AndroidDirectAccessFrameBuffer::~AndroidDirectAccessFrameBuffer() {
|
||||
// if (_imageEGL) {
|
||||
// QImage::Log("AHardwareBuffer", "release _imageEGL");
|
||||
// eglDestroyImageKHR(eglGetDisplay(EGL_DEFAULT_DISPLAY), _imageEGL);
|
||||
// _imageEGL = nullptr;
|
||||
// }
|
||||
// if (_graphicBuf) {
|
||||
// QImage::Log("AHardwareBuffer", "release AHardwareBuffer");
|
||||
// QImage::AndroidHardwareBufferCompat::GetInstance().Release(_graphicBuf);
|
||||
// _graphicBuf = nullptr;
|
||||
|
||||
// if (_graphicBufDes != nullptr) {
|
||||
// delete _graphicBufDes;
|
||||
// _graphicBufDes = nullptr;
|
||||
// }
|
||||
|
||||
// //TODO 确认release的时候,是否需要我们自己释放这块内存
|
||||
// // _hardwareBufferReadData = nullptr;
|
||||
// }
|
||||
// //TODO 需要验证FrameBuffer里面的texture和fb是否成功释放了
|
||||
// }
|
||||
|
||||
// void AndroidDirectAccessFrameBuffer::lockAddress() {
|
||||
// if (!_support) {
|
||||
// return;
|
||||
// }
|
||||
|
||||
// if (_hasLock) {
|
||||
// return;
|
||||
// }
|
||||
|
||||
// void *data = nullptr;
|
||||
// int result = AndroidHardwareBufferCompat::GetInstance().Lock(_graphicBuf,
|
||||
// AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN,
|
||||
// -1, nullptr, &data);
|
||||
// if (result != 0) {
|
||||
// LogE("AHardwareBuffer", "Lock pixel error : %d", result);
|
||||
// return;
|
||||
// }
|
||||
// _hardwareBufferReadData = data;
|
||||
// _hasLock = true;
|
||||
// }
|
||||
|
||||
// /**
|
||||
// * unlock之后,不要继续使用_hardwareBufferReadData,会存在GPU写CPU读并行导致异常问题
|
||||
// */
|
||||
// void AndroidDirectAccessFrameBuffer::unlockAddress() {
|
||||
// if (!_support) {
|
||||
// return;
|
||||
// }
|
||||
|
||||
// if (!_hasLock) {
|
||||
// return;
|
||||
// }
|
||||
|
||||
// int unlockResult = AndroidHardwareBufferCompat::GetInstance().Unlock(_graphicBuf, nullptr);
|
||||
|
||||
// if (unlockResult != 0) {
|
||||
// LogE("AHardwareBuffer", "Unlock pixel error : %d", unlockResult);
|
||||
// return;
|
||||
// }
|
||||
|
||||
// _hardwareBufferReadData = nullptr;
|
||||
// _hasLock = false;
|
||||
// }
|
||||
|
||||
// int AndroidDirectAccessFrameBuffer::getBytesPerRow() {
|
||||
// if (!_support) {
|
||||
// return 0;
|
||||
// }
|
||||
// return _graphicBufDes->stride * 4;
|
||||
|
||||
// }
|
||||
|
||||
// void *AndroidDirectAccessFrameBuffer::frameBufferGetBaseAddress() {
|
||||
// if (_support) {
|
||||
// return _hardwareBufferReadData;
|
||||
// }
|
||||
// return nullptr;
|
||||
// }
|
||||
|
||||
// static void
|
||||
// getGLFormat(AHardwareBuffer_Desc *desc, int *internal_format, int *format, int *type) {
|
||||
// switch ((*desc).format) {
|
||||
// case GL_RGB565:
|
||||
// *internal_format = GL_RGB;
|
||||
// *format = GL_RGB;
|
||||
// *type = GL_UNSIGNED_SHORT_5_6_5;
|
||||
// break;
|
||||
// case GL_RGB8:
|
||||
// *internal_format = GL_RGB;
|
||||
// *format = GL_RGB;
|
||||
// *type = GL_UNSIGNED_BYTE;
|
||||
// break;
|
||||
// case GL_RGBA8:
|
||||
// *internal_format = GL_RGBA;
|
||||
// *format = GL_RGBA;
|
||||
// *type = GL_UNSIGNED_BYTE;
|
||||
// break;
|
||||
// case GL_SRGB8_ALPHA8:
|
||||
// // Available through GL_EXT_sRGB.
|
||||
// *internal_format = GL_SRGB_ALPHA_EXT;
|
||||
// *format = GL_RGBA;
|
||||
// *type = GL_UNSIGNED_BYTE;
|
||||
// break;
|
||||
// case GL_DEPTH_COMPONENT16:
|
||||
// // Available through GL_OES_depth_texture.
|
||||
// // Note that these are treated as luminance textures, not as red textures.
|
||||
// *internal_format = GL_DEPTH_COMPONENT;
|
||||
// *format = GL_DEPTH_COMPONENT;
|
||||
// *type = GL_UNSIGNED_SHORT;
|
||||
// break;
|
||||
// case GL_DEPTH24_STENCIL8:
|
||||
// // Available through GL_OES_packed_depth_stencil.
|
||||
// *internal_format = GL_DEPTH_STENCIL_OES;
|
||||
// *format = GL_DEPTH_STENCIL;
|
||||
// *type = GL_UNSIGNED_INT_24_8;
|
||||
// break;
|
||||
// case AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM :
|
||||
// // only support this format now
|
||||
// *internal_format = GL_RGBA;
|
||||
// *format = GL_RGBA;
|
||||
// *type = GL_UNSIGNED_BYTE;
|
||||
// break;
|
||||
// default:
|
||||
// LogE("AHardwareBuffer", "covert to gl format error");
|
||||
// assert(false);
|
||||
// }
|
||||
// }
|
||||
|
||||
// void AndroidDirectAccessFrameBuffer::_generateFramebuffer(bool needGenerateTexture) {
|
||||
|
||||
// bool result = _generateHardwareBuffer();
|
||||
|
||||
// if (!result) {
|
||||
// LogE("AHardwareBuffer", "not support because of create hardware buffer error ");
|
||||
// //check result
|
||||
// _support = false;
|
||||
// return;
|
||||
// }
|
||||
|
||||
// CHECK_GL(glGenFramebuffers(1, &_framebuffer));
|
||||
// CHECK_GL(glBindFramebuffer(GL_FRAMEBUFFER, _framebuffer));
|
||||
|
||||
// _generateTexture();
|
||||
|
||||
// CHECK_GL(glBindTexture(GL_TEXTURE_2D, _texture));
|
||||
|
||||
// int format = -1;
|
||||
// int type = -1;
|
||||
// int internal_format = -1;
|
||||
|
||||
// getGLFormat(_graphicBufDes, &internal_format, &format, &type);
|
||||
|
||||
// Log("AHardwareBuffer", "covert to gl format ( %d -> [internal:%d , format:%d , type: %d] )",
|
||||
// _graphicBufDes->format, internal_format, format, type);
|
||||
|
||||
|
||||
// CHECK_GL(glTexImage2D(GL_TEXTURE_2D, 0, internal_format, _width, _height, 0, format, type,
|
||||
// 0));
|
||||
|
||||
// CHECK_GL(glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
|
||||
// _texture, 0));
|
||||
|
||||
// //bind texture to hardwarebuffer
|
||||
// CHECK_GL(PlatformEGLAndroidCompat::GetInstance().glEGLImageTargetTexture2DOES(GL_TEXTURE_2D,
|
||||
// _imageEGL));
|
||||
|
||||
// CHECK_GL(glBindTexture(GL_TEXTURE_2D, 0));
|
||||
// CHECK_GL(glBindFramebuffer(GL_FRAMEBUFFER, 0));
|
||||
|
||||
// QImage::Log("AHardwareBuffer",
|
||||
// "AHardwareBuffer create finish ( framebuffer:%d, texture:%d , w:%d , h:%d , stride:%d )",
|
||||
// _framebuffer, _texture, _width, _height, _graphicBufDes->stride);
|
||||
|
||||
// _support = true;
|
||||
// }
|
||||
|
||||
|
||||
// void AndroidDirectAccessFrameBuffer::_generateTexture() {
|
||||
|
||||
// CHECK_GL(glGenTextures(1, &_texture));
|
||||
|
||||
// QImage::Log("AHardwareBuffer", "glGenTextures %d", _texture);
|
||||
|
||||
// CHECK_GL(glBindTexture(GL_TEXTURE_2D, _texture));
|
||||
// CHECK_GL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
|
||||
// _textureAttributes.minFilter));
|
||||
// CHECK_GL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
|
||||
// _textureAttributes.magFilter));
|
||||
// CHECK_GL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, _textureAttributes.wrapS));
|
||||
// CHECK_GL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, _textureAttributes.wrapT));
|
||||
|
||||
// QImage::Log("AHardwareBuffer", "finish glGenTextures");
|
||||
|
||||
// CHECK_GL(glBindTexture(GL_TEXTURE_2D, 0));
|
||||
// }
|
||||
|
||||
// bool AndroidDirectAccessFrameBuffer::_generateHardwareBuffer() {
|
||||
|
||||
// AHardwareBuffer_Desc tryDesc;
|
||||
|
||||
// int hardwareBufferFormat;
|
||||
// switch (_textureAttributes.format) {
|
||||
// case GL_RGBA8:
|
||||
// case GL_RGBA:
|
||||
// hardwareBufferFormat = AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM;
|
||||
// break;
|
||||
// default:
|
||||
// //not support other format now
|
||||
// assert(false);
|
||||
// }
|
||||
|
||||
// //暂时不支持minmap的缩放方法
|
||||
// switch (_textureAttributes.magFilter) {
|
||||
// case GL_LINEAR:
|
||||
// case GL_NEAREST:
|
||||
// break;
|
||||
// default:
|
||||
// LogE("AHardwareBuffer", "not support magFilter type : %d",
|
||||
// _textureAttributes.magFilter);
|
||||
// //not support other format now
|
||||
// assert(false);
|
||||
// }
|
||||
|
||||
// switch (_textureAttributes.minFilter) {
|
||||
// case GL_LINEAR:
|
||||
// case GL_NEAREST:
|
||||
// break;
|
||||
// default:
|
||||
// LogE("AHardwareBuffer", "not support magFilter type : %d",
|
||||
// _textureAttributes.minFilter);
|
||||
// //not support other format now
|
||||
// assert(false);
|
||||
// }
|
||||
|
||||
// // filling in the usage for HardwareBuffer
|
||||
// tryDesc.format = hardwareBufferFormat;
|
||||
// tryDesc.height = _height;
|
||||
// tryDesc.width = _width;
|
||||
// tryDesc.layers = 1;
|
||||
// tryDesc.rfu0 = 0;
|
||||
// tryDesc.rfu1 = 0;
|
||||
// tryDesc.stride = 0;
|
||||
// tryDesc.usage =
|
||||
// AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN | AHARDWAREBUFFER_USAGE_CPU_WRITE_NEVER |
|
||||
// AHARDWAREBUFFER_USAGE_GPU_COLOR_OUTPUT;
|
||||
|
||||
// QImage::Log("AHardwareBuffer", "start create AHardwareBuffer_Desc (%d, %d) ", _width,
|
||||
// _height);
|
||||
|
||||
// // create GraphicBuffer
|
||||
// int errorCode = AndroidHardwareBufferCompat::GetInstance().Allocate(&tryDesc, &_graphicBuf);
|
||||
|
||||
|
||||
// if (errorCode != 0) {
|
||||
// LogE("AHardwareBuffer", "AHardwareBuffer_allocate error = %d ", errorCode);
|
||||
// //TODO 不支持,需要进行统计或者降级!!
|
||||
// return false;
|
||||
// }
|
||||
|
||||
// if (_graphicBufDes == nullptr) {
|
||||
// _graphicBufDes = new AHardwareBuffer_Desc;
|
||||
// }
|
||||
// //实际的hardware buffer的参数
|
||||
// AndroidHardwareBufferCompat::GetInstance().Describe(_graphicBuf, _graphicBufDes);
|
||||
|
||||
// QImage::Log("AHardwareBuffer", "AHardwareBuffer_allocate success (%d, %d) stride : %d ",
|
||||
// _graphicBufDes->width, _graphicBufDes->height, _graphicBufDes->stride);
|
||||
|
||||
// // get the native buffer
|
||||
// EGLClientBuffer clientBuf = PlatformEGLAndroidCompat::GetInstance().eglGetNativeClientBufferANDROID(
|
||||
// _graphicBuf);
|
||||
|
||||
// // obtaining the EGL display
|
||||
// EGLDisplay disp = eglGetDisplay(EGL_DEFAULT_DISPLAY);
|
||||
|
||||
// // specifying the image attributes
|
||||
// EGLint eglImageAttributes[] = {EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE};
|
||||
|
||||
|
||||
// _imageEGL = PlatformEGLAndroidCompat::GetInstance().eglCreateImageKHR(disp, EGL_NO_CONTEXT,
|
||||
// EGL_NATIVE_BUFFER_ANDROID,
|
||||
// clientBuf,
|
||||
// eglImageAttributes);
|
||||
|
||||
// //AHardwareBuffer allocation succeeded, but binding it to an EGLImage failed. "
|
||||
// //This is usually caused by a version mismatch between the gralloc implementation and "
|
||||
// //the OpenGL/EGL driver. Please contact your GPU vendor to resolve this problem."
|
||||
// if (_imageEGL == EGL_NO_IMAGE_KHR) {
|
||||
// LogE("AHardwareBuffer", "eglCreateImageKHR error");
|
||||
// assert(false);
|
||||
// }
|
||||
|
||||
// return true;
|
||||
// }
|
||||
|
||||
|
||||
// NS_GI_END
|
77
mediapipe/render/android/AndroidDirectAccessFrameBuffer.h
Normal file
77
mediapipe/render/android/AndroidDirectAccessFrameBuffer.h
Normal file
|
@ -0,0 +1,77 @@
|
|||
//
|
||||
// Created by jormin on 2021/4/30.
|
||||
//
|
||||
|
||||
#ifndef QUARAMERA_ANDROIDDIRECTACCESSFRAMEBUFFER_H
|
||||
#define QUARAMERA_ANDROIDDIRECTACCESSFRAMEBUFFER_H
|
||||
|
||||
|
||||
// #include "GPUImageMacros.h"
|
||||
// #include "Framebuffer.hpp"
|
||||
// #include "GLES/gl.h"
|
||||
// #include "PlatformEGLAndroidCompat.h"
|
||||
// #include "android_hardware_buffer_compat.h"
|
||||
// #include "EGLAndroid.h"
|
||||
|
||||
|
||||
/**
|
||||
* 目前仅仅支持hardwarebuffer的高效读取,如果以后要支持upload的话,需要改造
|
||||
*/
|
||||
|
||||
namespace QImage {
|
||||
class AndroidDirectAccessFrameBuffer {
|
||||
~AndroidDirectAccessFrameBuffer() {};
|
||||
AndroidDirectAccessFrameBuffer() {};
|
||||
};
|
||||
}
|
||||
|
||||
// NS_GI_BEGIN
|
||||
|
||||
|
||||
// class AndroidDirectAccessFrameBuffer : public QImage::Framebuffer {
|
||||
// public:
|
||||
|
||||
|
||||
// AndroidDirectAccessFrameBuffer(Context *context, int width, int height,
|
||||
// const TextureAttributes textureAttributes = defaultTextureAttribures);
|
||||
|
||||
|
||||
// virtual ~AndroidDirectAccessFrameBuffer() override;
|
||||
|
||||
// void lockAddress() override;
|
||||
|
||||
// void unlockAddress() override;
|
||||
|
||||
// void *frameBufferGetBaseAddress() override;
|
||||
|
||||
// int getBytesPerRow() override;
|
||||
|
||||
// void _generateTexture() override;
|
||||
|
||||
// void _generateFramebuffer(bool needGenerateTexture = true) override;
|
||||
|
||||
// bool support() {
|
||||
// return _support;
|
||||
// }
|
||||
|
||||
// private :
|
||||
|
||||
// bool _generateHardwareBuffer();
|
||||
|
||||
// EGLImageKHR _imageEGL = EGL_NO_IMAGE_KHR;
|
||||
// void *_hardwareBufferReadData = nullptr;
|
||||
|
||||
// AHardwareBuffer *_graphicBuf = nullptr;
|
||||
// AHardwareBuffer_Desc *_graphicBufDes = nullptr;
|
||||
|
||||
// bool _support = false;
|
||||
|
||||
// bool _hasLock = false;
|
||||
|
||||
|
||||
// };
|
||||
|
||||
// NS_GI_END
|
||||
|
||||
|
||||
#endif //QUARAMERA_ANDROIDDIRECTACCESSFRAMEBUFFER_H
|
76
mediapipe/render/android/EGLAndroid.cpp
Normal file
76
mediapipe/render/android/EGLAndroid.cpp
Normal file
|
@ -0,0 +1,76 @@
|
|||
//
|
||||
// Created by jormin on 2021/4/30.
|
||||
//
|
||||
|
||||
#include "EGLAndroid.h"
|
||||
#include "android_hardware_buffer_compat.h"
|
||||
#include "PlatformEGLAndroidCompat.h"
|
||||
|
||||
NS_GI_BEGIN
|
||||
|
||||
std::mutex EGLAndroid::mMutex;
|
||||
|
||||
int EGLAndroid::mGLMajorVersion = -1;
|
||||
int EGLAndroid::mGLMinorVersion = -1;
|
||||
|
||||
|
||||
bool EGLAndroid::supportHardwareBuffer() {
|
||||
//ios not support
|
||||
#if defined(__APPLE__)
|
||||
if(true){
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
//GL版本 > 3.0
|
||||
if (EGLAndroid::getGLMajorVersion() < 3) {
|
||||
return false;
|
||||
}
|
||||
|
||||
//AHardwareBuffer要求android系统>=7.0
|
||||
if (!AndroidHardwareBufferCompat::IsSupportAvailable()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
//EGL接口动态dlopen成功
|
||||
if (!PlatformEGLAndroidCompat::GetInstance().isSupport()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool EGLAndroid::supportPBO() {
|
||||
//GL版本 > 3.0
|
||||
if (EGLAndroid::getGLMajorVersion() < 3) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
int EGLAndroid::getGLMajorVersion() {
|
||||
std::unique_lock<std::mutex> lk(mMutex);
|
||||
if (mGLMajorVersion != -1) {
|
||||
return mGLMajorVersion;
|
||||
}
|
||||
_initGLInfo();
|
||||
return mGLMajorVersion;
|
||||
}
|
||||
|
||||
int EGLAndroid::getGLMinorVersion() {
|
||||
std::unique_lock<std::mutex> lk(mMutex);
|
||||
if (mGLMinorVersion != -1) {
|
||||
return mGLMinorVersion;
|
||||
}
|
||||
_initGLInfo();
|
||||
return mGLMinorVersion;
|
||||
}
|
||||
|
||||
void EGLAndroid::_initGLInfo() {
|
||||
CHECK_GL(glGetIntegerv(GL_MAJOR_VERSION, &mGLMajorVersion));
|
||||
CHECK_GL(glGetIntegerv(GL_MINOR_VERSION, &mGLMinorVersion));
|
||||
}
|
||||
|
||||
|
||||
NS_GI_END
|
38
mediapipe/render/android/EGLAndroid.h
Normal file
38
mediapipe/render/android/EGLAndroid.h
Normal file
|
@ -0,0 +1,38 @@
|
|||
//
|
||||
// Created by jormin on 2021/4/30.
|
||||
//
|
||||
|
||||
#ifndef QUARAMERA_EGLANDROID_H
|
||||
#define QUARAMERA_EGLANDROID_H
|
||||
|
||||
#include "GPUImageMacros.h"
|
||||
#include <mutex>
|
||||
#import <GLES3/gl3.h>
|
||||
#include "android_hardware_buffer_compat.h"
|
||||
#include "PlatformEGLAndroidCompat.h"
|
||||
|
||||
NS_GI_BEGIN
|
||||
|
||||
class EGLAndroid {
|
||||
public :
|
||||
static int getGLMajorVersion();
|
||||
|
||||
static int getGLMinorVersion();
|
||||
|
||||
static bool supportHardwareBuffer();
|
||||
|
||||
static bool supportPBO();
|
||||
|
||||
private :
|
||||
|
||||
static void _initGLInfo();
|
||||
|
||||
static std::mutex mMutex;
|
||||
|
||||
static int mGLMajorVersion;
|
||||
static int mGLMinorVersion;
|
||||
|
||||
|
||||
}; NS_GI_END
|
||||
|
||||
#endif //QUARAMERA_EGLANDROID_H
|
11
mediapipe/render/android/Hardwarebuffer.cpp
Normal file
11
mediapipe/render/android/Hardwarebuffer.cpp
Normal file
|
@ -0,0 +1,11 @@
|
|||
#include "Hardwarebuffer.hpp"
|
||||
|
||||
namespace QImage {
|
||||
HardwareBuffer::HardwareBuffer() {
|
||||
|
||||
}
|
||||
|
||||
HardwareBuffer::~HardwareBuffer() {
|
||||
|
||||
}
|
||||
}
|
12
mediapipe/render/android/Hardwarebuffer.hpp
Normal file
12
mediapipe/render/android/Hardwarebuffer.hpp
Normal file
|
@ -0,0 +1,12 @@
|
|||
#ifndef HARDWAREBUFFER_H
|
||||
#define HARDWAREBUFFER_H
|
||||
|
||||
namespace QImage {
|
||||
class HardwareBuffer {
|
||||
public:
|
||||
HardwareBuffer();
|
||||
~HardwareBuffer();
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
139
mediapipe/render/android/PlatformEGLAndroidCompat.cpp
Normal file
139
mediapipe/render/android/PlatformEGLAndroidCompat.cpp
Normal file
|
@ -0,0 +1,139 @@
|
|||
//
|
||||
// Created by jormin on 2021/4/22.
|
||||
//
|
||||
|
||||
#include "PlatformEGLAndroidCompat.h"
|
||||
//
|
||||
//
|
||||
//AHardwareBuffer_Desc
|
||||
|
||||
|
||||
#include "EGL/egl.h"
|
||||
#include "GLES/gl.h"
|
||||
#include "EGL/egl.h"
|
||||
#include "GLES/glext.h"
|
||||
#include <GLES2/gl2ext.h>
|
||||
#include <sys/system_properties.h>
|
||||
|
||||
#include <cstdlib>
|
||||
#include <EGL/egl.h>
|
||||
#include <EGL/eglext.h>
|
||||
#include <dlfcn.h>
|
||||
#include <GLES/glext.h>
|
||||
|
||||
#define LOG_TAG "PlatformEGLAndroidCompat"
|
||||
|
||||
#include "no_destructor.h"
|
||||
|
||||
|
||||
NS_GI_BEGIN
|
||||
#define UTILS_PRIVATE __attribute__((visibility("hidden")))
|
||||
|
||||
// The Android NDK doesn't exposes extensions, fake it with eglGetProcAddress
|
||||
namespace glext {
|
||||
|
||||
UTILS_PRIVATE PFNEGLDESTROYIMAGEKHRPROC eglDestroyImageKHR = {};
|
||||
|
||||
UTILS_PRIVATE PFNEGLGETNATIVECLIENTBUFFERANDROIDPROC eglGetNativeClientBufferANDROID = {};
|
||||
|
||||
UTILS_PRIVATE PFNGLEGLIMAGETARGETTEXTURE2DOESPROC glEGLImageTargetTexture2DOES = {};
|
||||
|
||||
UTILS_PRIVATE PFNEGLCREATEIMAGEKHRPROC eglCreateImageKHR = {};
|
||||
|
||||
}
|
||||
using namespace glext;
|
||||
|
||||
PlatformEGLAndroidCompat::PlatformEGLAndroidCompat() noexcept {
|
||||
mIsSupport = _createDriver();
|
||||
}
|
||||
|
||||
bool PlatformEGLAndroidCompat::isSupport() {
|
||||
return mIsSupport;
|
||||
}
|
||||
|
||||
|
||||
// static
|
||||
PlatformEGLAndroidCompat &PlatformEGLAndroidCompat::GetInstance() noexcept {
|
||||
static NoDestructor<PlatformEGLAndroidCompat> compat;
|
||||
return *compat;
|
||||
}
|
||||
|
||||
void
|
||||
PlatformEGLAndroidCompat::glEGLImageTargetTexture2DOES(GLenum target, GLeglImageOES image) {
|
||||
glext::glEGLImageTargetTexture2DOES(target, image);
|
||||
}
|
||||
|
||||
|
||||
bool PlatformEGLAndroidCompat::eglDestroyImageKHR(EGLDisplay dpy, EGLImageKHR image) {
|
||||
return glext::eglDestroyImageKHR(dpy, image);
|
||||
}
|
||||
|
||||
|
||||
EGLImageKHR
|
||||
PlatformEGLAndroidCompat::eglCreateImageKHR(EGLDisplay dpy, EGLContext ctx, EGLenum target,
|
||||
EGLClientBuffer buffer, const EGLint *attrib_list) {
|
||||
return glext::eglCreateImageKHR(dpy, ctx, target, buffer, attrib_list);
|
||||
}
|
||||
|
||||
|
||||
EGLClientBuffer PlatformEGLAndroidCompat::eglGetNativeClientBufferANDROID(
|
||||
const struct AHardwareBuffer *buffer) {
|
||||
return glext::eglGetNativeClientBufferANDROID(buffer);
|
||||
}
|
||||
|
||||
|
||||
bool PlatformEGLAndroidCompat::_createDriver() noexcept {
|
||||
const char *const driver_absolute_path = "/system/lib/egl/libEGL_mali.so";
|
||||
// On Gingerbread you have to load symbols manually from Mali driver because
|
||||
// Android EGL library has a bug.
|
||||
// From ICE CREAM SANDWICH you can freely use the eglGetProcAddress function.
|
||||
// You might be able to get away with just eglGetProcAddress (no dlopen).
|
||||
// Try it, else revert to the following code
|
||||
void *dso = dlopen(driver_absolute_path, RTLD_LAZY);
|
||||
if (dso != 0) {
|
||||
glext::eglCreateImageKHR = (PFNEGLCREATEIMAGEKHRPROC) dlsym(dso, "eglCreateImageKHR");
|
||||
glext::eglDestroyImageKHR = (PFNEGLDESTROYIMAGEKHRPROC) dlsym(dso,
|
||||
"eglDestroyImageKHR");
|
||||
} else {
|
||||
QImage::Log("PlatformEGLAndroidCompat",
|
||||
"dlopen: FAILED! Loading functions in common way!");
|
||||
glext::eglCreateImageKHR = (PFNEGLCREATEIMAGEKHRPROC) eglGetProcAddress(
|
||||
"eglCreateImageKHR");
|
||||
glext::eglDestroyImageKHR = (PFNEGLDESTROYIMAGEKHRPROC) eglGetProcAddress(
|
||||
"eglDestroyImageKHR");
|
||||
}
|
||||
|
||||
if (glext::eglCreateImageKHR == nullptr) {
|
||||
QImage::Log("PlatformEGLAndroidCompat",
|
||||
"Error: Failed to find eglCreateImageKHR at %s:%in", __FILE__, __LINE__);
|
||||
return false;
|
||||
}
|
||||
if (glext::eglDestroyImageKHR == nullptr) {
|
||||
QImage::Log("PlatformEGLAndroidCompat",
|
||||
"Error: Failed to find eglDestroyImageKHR at %s:%in", __FILE__, __LINE__);
|
||||
return false;
|
||||
}
|
||||
|
||||
glext::eglGetNativeClientBufferANDROID = (PFNEGLGETNATIVECLIENTBUFFERANDROIDPROC) eglGetProcAddress(
|
||||
"eglGetNativeClientBufferANDROID");
|
||||
|
||||
glext::glEGLImageTargetTexture2DOES = (PFNGLEGLIMAGETARGETTEXTURE2DOESPROC) eglGetProcAddress(
|
||||
"glEGLImageTargetTexture2DOES");
|
||||
|
||||
if (glext::eglGetNativeClientBufferANDROID == nullptr) {
|
||||
QImage::Log("PlatformEGLAndroidCompat",
|
||||
"Error: Failed to find eglGetNativeClientBufferANDROID at %s:%in",
|
||||
__FILE__, __LINE__);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (glext::glEGLImageTargetTexture2DOES == nullptr) {
|
||||
QImage::Log("PlatformEGLAndroidCompat",
|
||||
"Error: Failed to find glEGLImageTargetTexture2DOES at %s:%in", __FILE__,
|
||||
__LINE__);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
NS_GI_END
|
52
mediapipe/render/android/PlatformEGLAndroidCompat.h
Normal file
52
mediapipe/render/android/PlatformEGLAndroidCompat.h
Normal file
|
@ -0,0 +1,52 @@
|
|||
//
|
||||
// Created by jormin on 2021/4/22.
|
||||
//
|
||||
|
||||
#ifndef QUARAMERA_PLATFORM_EGL_ANDROID_H
|
||||
#define QUARAMERA_PLATFORM_EGL_ANDROID_H
|
||||
|
||||
#include "EGL/egl.h"
|
||||
#include "GLES/gl.h"
|
||||
#include "EGL/egl.h"
|
||||
#include "GLES/glext.h"
|
||||
#include <GLES2/gl2ext.h>
|
||||
#include <sys/system_properties.h>
|
||||
|
||||
#include <cstdlib>
|
||||
#include <EGL/egl.h>
|
||||
#include <EGL/eglext.h>
|
||||
#include <dlfcn.h>
|
||||
#include <GLES/glext.h>
|
||||
#include "GPUImageMacros.h"
|
||||
|
||||
NS_GI_BEGIN class PlatformEGLAndroidCompat {
|
||||
public:
|
||||
static PlatformEGLAndroidCompat &GetInstance() noexcept;
|
||||
|
||||
virtual ~PlatformEGLAndroidCompat() = default;
|
||||
|
||||
PlatformEGLAndroidCompat() noexcept;
|
||||
|
||||
virtual void glEGLImageTargetTexture2DOES(GLenum target, GLeglImageOES image);
|
||||
|
||||
virtual bool eglDestroyImageKHR(EGLDisplay dpy, EGLImageKHR image);
|
||||
|
||||
virtual EGLImageKHR
|
||||
eglCreateImageKHR(EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer,
|
||||
const EGLint *attrib_list);
|
||||
|
||||
virtual EGLClientBuffer
|
||||
eglGetNativeClientBufferANDROID(const struct AHardwareBuffer *buffer);
|
||||
|
||||
virtual bool isSupport();
|
||||
|
||||
private:
|
||||
static bool _createDriver() noexcept;
|
||||
|
||||
int mOSVersion = 0;
|
||||
|
||||
bool mIsSupport = false;
|
||||
};
|
||||
|
||||
NS_GI_END
|
||||
#endif //QUARAMERA_PLATFORM_EGL_ANDROID_H
|
118
mediapipe/render/android/android_hardware_buffer_compat.cc
Normal file
118
mediapipe/render/android/android_hardware_buffer_compat.cc
Normal file
|
@ -0,0 +1,118 @@
|
|||
// Copyright 2017 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
#include "android_hardware_buffer_compat.h"
|
||||
#include <dlfcn.h>
|
||||
#include <sys/system_properties.h>
|
||||
|
||||
#define DCHECK(func) func;
|
||||
|
||||
namespace QImage {
|
||||
int AndroidHardwareBufferCompat::sdk_ver_ = 0;
|
||||
|
||||
AndroidHardwareBufferCompat::AndroidHardwareBufferCompat() {
|
||||
|
||||
//TODO
|
||||
DCHECK(IsSupportAvailable());
|
||||
|
||||
|
||||
// TODO(klausw): If the Chromium build requires __ANDROID_API__ >= 26 at some
|
||||
// point in the future, we could directly use the global functions instead of
|
||||
// dynamic loading. However, since this would be incompatible with pre-Oreo
|
||||
// devices, this is unlikely to happen in the foreseeable future, so just
|
||||
// unconditionally use dynamic loading.
|
||||
// cf. base/android/linker/modern_linker_jni.cc
|
||||
void *main_dl_handle = dlopen(nullptr, RTLD_NOW);
|
||||
*reinterpret_cast<void **>(&allocate_) = dlsym(main_dl_handle, "AHardwareBuffer_allocate");
|
||||
//TODO
|
||||
DCHECK(allocate_);
|
||||
*reinterpret_cast<void **>(&acquire_) = dlsym(main_dl_handle, "AHardwareBuffer_acquire");
|
||||
//TODO
|
||||
|
||||
DCHECK(acquire_);
|
||||
*reinterpret_cast<void **>(&describe_) = dlsym(main_dl_handle, "AHardwareBuffer_describe");
|
||||
//TODO
|
||||
|
||||
DCHECK(describe_);
|
||||
*reinterpret_cast<void **>(&lock_) = dlsym(main_dl_handle, "AHardwareBuffer_lock");
|
||||
DCHECK(lock_);
|
||||
*reinterpret_cast<void **>(&recv_handle_) = dlsym(main_dl_handle,
|
||||
"AHardwareBuffer_recvHandleFromUnixSocket");
|
||||
DCHECK(recv_handle_);
|
||||
*reinterpret_cast<void **>(&release_) = dlsym(main_dl_handle, "AHardwareBuffer_release");
|
||||
// DCHECK(release_);
|
||||
*reinterpret_cast<void **>(&send_handle_) = dlsym(main_dl_handle,
|
||||
"AHardwareBuffer_sendHandleToUnixSocket");
|
||||
// DCHECK(send_handle_);
|
||||
*reinterpret_cast<void **>(&unlock_) = dlsym(main_dl_handle, "AHardwareBuffer_unlock");
|
||||
// DCHECK(unlock_);
|
||||
}
|
||||
|
||||
// static
|
||||
bool AndroidHardwareBufferCompat::IsSupportAvailable() {
|
||||
char scratch[PROP_VALUE_MAX + 1];
|
||||
if (sdk_ver_ == 0) {
|
||||
int length = __system_property_get("ro.build.version.release", scratch);
|
||||
int androidVersion = length >= 0 ? atoi(scratch) : 1;
|
||||
if (!androidVersion) {
|
||||
sdk_ver_ = 1000; // if androidVersion is 0, it means "future"
|
||||
} else {
|
||||
length = __system_property_get("ro.build.version.sdk", scratch);
|
||||
sdk_ver_ = length >= 0 ? atoi(scratch) : 1;
|
||||
}
|
||||
}
|
||||
// Android O
|
||||
return sdk_ver_ >= 26;
|
||||
}
|
||||
|
||||
// static
|
||||
AndroidHardwareBufferCompat &AndroidHardwareBufferCompat::GetInstance() {
|
||||
static QImage::NoDestructor<AndroidHardwareBufferCompat> compat;
|
||||
return *compat;
|
||||
}
|
||||
|
||||
int AndroidHardwareBufferCompat::Allocate(const AHardwareBuffer_Desc *desc,
|
||||
AHardwareBuffer **out_buffer) {
|
||||
DCHECK(IsSupportAvailable());
|
||||
return allocate_(desc, out_buffer);
|
||||
}
|
||||
|
||||
void AndroidHardwareBufferCompat::Acquire(AHardwareBuffer *buffer) {
|
||||
DCHECK(IsSupportAvailable());
|
||||
acquire_(buffer);
|
||||
}
|
||||
|
||||
void AndroidHardwareBufferCompat::Describe(const AHardwareBuffer *buffer,
|
||||
AHardwareBuffer_Desc *out_desc) {
|
||||
DCHECK(IsSupportAvailable());
|
||||
describe_(buffer, out_desc);
|
||||
}
|
||||
|
||||
int AndroidHardwareBufferCompat::Lock(AHardwareBuffer *buffer, uint64_t usage, int32_t fence,
|
||||
const ARect *rect, void **out_virtual_address) {
|
||||
DCHECK(IsSupportAvailable());
|
||||
return lock_(buffer, usage, fence, rect, out_virtual_address);
|
||||
}
|
||||
|
||||
int AndroidHardwareBufferCompat::RecvHandleFromUnixSocket(int socket_fd,
|
||||
AHardwareBuffer **out_buffer) {
|
||||
DCHECK(IsSupportAvailable());
|
||||
return recv_handle_(socket_fd, out_buffer);
|
||||
}
|
||||
|
||||
void AndroidHardwareBufferCompat::Release(AHardwareBuffer *buffer) {
|
||||
DCHECK(IsSupportAvailable());
|
||||
release_(buffer);
|
||||
}
|
||||
|
||||
int AndroidHardwareBufferCompat::SendHandleToUnixSocket(const AHardwareBuffer *buffer,
|
||||
int socket_fd) {
|
||||
DCHECK(IsSupportAvailable());
|
||||
return send_handle_(buffer, socket_fd);
|
||||
}
|
||||
|
||||
int AndroidHardwareBufferCompat::Unlock(AHardwareBuffer *buffer, int32_t *fence) {
|
||||
DCHECK(IsSupportAvailable());
|
||||
return unlock_(buffer, fence);
|
||||
}
|
||||
}
|
80
mediapipe/render/android/android_hardware_buffer_compat.h
Normal file
80
mediapipe/render/android/android_hardware_buffer_compat.h
Normal file
|
@ -0,0 +1,80 @@
|
|||
// Copyright 2017 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
#ifndef BASE_ANDROID_ANDROID_HARDWARE_BUFFER_COMPAT_H_
|
||||
#define BASE_ANDROID_ANDROID_HARDWARE_BUFFER_COMPAT_H_
|
||||
|
||||
#include <android/hardware_buffer.h>
|
||||
#include <android/sensor.h>
|
||||
#include "base_export.h"
|
||||
#include "android_macros.h"
|
||||
#include "no_destructor.h"
|
||||
|
||||
extern "C" {
|
||||
using PFAHardwareBuffer_allocate = int (*)(const AHardwareBuffer_Desc *desc,
|
||||
AHardwareBuffer **outBuffer);
|
||||
using PFAHardwareBuffer_acquire = void (*)(AHardwareBuffer *buffer);
|
||||
using PFAHardwareBuffer_describe = void (*)(const AHardwareBuffer *buffer,
|
||||
AHardwareBuffer_Desc *outDesc);
|
||||
using PFAHardwareBuffer_lock = int (*)(AHardwareBuffer *buffer,
|
||||
uint64_t usage,
|
||||
int32_t fence,
|
||||
const ARect *rect,
|
||||
void **outVirtualAddress);
|
||||
using PFAHardwareBuffer_recvHandleFromUnixSocket =
|
||||
int (*)(int socketFd, AHardwareBuffer **outBuffer);
|
||||
using PFAHardwareBuffer_release = void (*)(AHardwareBuffer *buffer);
|
||||
using PFAHardwareBuffer_sendHandleToUnixSocket =
|
||||
int (*)(const AHardwareBuffer *buffer, int socketFd);
|
||||
using PFAHardwareBuffer_unlock = int (*)(AHardwareBuffer *buffer,
|
||||
int32_t *fence);
|
||||
}
|
||||
namespace QImage {
|
||||
// This class provides runtime support for working with AHardwareBuffer objects
|
||||
// on Android O systems without requiring building for the Android O NDK level.
|
||||
// Don't call GetInstance() unless IsSupportAvailable() returns true.
|
||||
class BASE_EXPORT AndroidHardwareBufferCompat {
|
||||
public:
|
||||
static bool IsSupportAvailable();
|
||||
|
||||
static AndroidHardwareBufferCompat &GetInstance();
|
||||
|
||||
int Allocate(const AHardwareBuffer_Desc *desc, AHardwareBuffer **outBuffer);
|
||||
|
||||
void Acquire(AHardwareBuffer *buffer);
|
||||
|
||||
void Describe(const AHardwareBuffer *buffer, AHardwareBuffer_Desc *outDesc);
|
||||
|
||||
int Lock(AHardwareBuffer *buffer,
|
||||
uint64_t usage,
|
||||
int32_t fence,
|
||||
const ARect *rect,
|
||||
void **out_virtual_address);
|
||||
|
||||
int RecvHandleFromUnixSocket(int socketFd, AHardwareBuffer **outBuffer);
|
||||
|
||||
void Release(AHardwareBuffer *buffer);
|
||||
|
||||
int SendHandleToUnixSocket(const AHardwareBuffer *buffer, int socketFd);
|
||||
|
||||
int Unlock(AHardwareBuffer *buffer, int32_t *fence);
|
||||
|
||||
private:
|
||||
friend class NoDestructor<AndroidHardwareBufferCompat>;
|
||||
|
||||
AndroidHardwareBufferCompat();
|
||||
|
||||
PFAHardwareBuffer_allocate allocate_;
|
||||
PFAHardwareBuffer_acquire acquire_;
|
||||
PFAHardwareBuffer_describe describe_;
|
||||
PFAHardwareBuffer_lock lock_;
|
||||
PFAHardwareBuffer_recvHandleFromUnixSocket recv_handle_;
|
||||
PFAHardwareBuffer_release release_;
|
||||
PFAHardwareBuffer_sendHandleToUnixSocket send_handle_;
|
||||
PFAHardwareBuffer_unlock unlock_;
|
||||
DISALLOW_COPY_AND_ASSIGN(AndroidHardwareBufferCompat);
|
||||
|
||||
static int sdk_ver_;
|
||||
};
|
||||
} // namespace base
|
||||
#endif // BASE_ANDROID_ANDROID_HARDWARE_BUFFER_COMPAT_H_
|
38
mediapipe/render/android/android_macros.h
Normal file
38
mediapipe/render/android/android_macros.h
Normal file
|
@ -0,0 +1,38 @@
|
|||
// Copyright 2014 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
// This file contains macros and macro-like constructs (e.g., templates) that
|
||||
// are commonly used throughout Chromium source. (It may also contain things
|
||||
// that are closely related to things that are commonly used that belong in this
|
||||
// file.)
|
||||
#ifndef BASE_MACROS_H_
|
||||
#define BASE_MACROS_H_
|
||||
// ALL DISALLOW_xxx MACROS ARE DEPRECATED; DO NOT USE IN NEW CODE.
|
||||
// Use explicit deletions instead. See the section on copyability/movability in
|
||||
// //styleguide/c++/c++-dos-and-donts.md for more information.
|
||||
// DEPRECATED: See above. Makes a class uncopyable.
|
||||
#define DISALLOW_COPY(TypeName) \
|
||||
TypeName(const TypeName&) = delete
|
||||
// DEPRECATED: See above. Makes a class unassignable.
|
||||
#define DISALLOW_ASSIGN(TypeName) TypeName& operator=(const TypeName&) = delete
|
||||
// DEPRECATED: See above. Makes a class uncopyable and unassignable.
|
||||
#define DISALLOW_COPY_AND_ASSIGN(TypeName) \
|
||||
DISALLOW_COPY(TypeName); \
|
||||
DISALLOW_ASSIGN(TypeName)
|
||||
// DEPRECATED: See above. Disallow all implicit constructors, namely the
|
||||
// default constructor, copy constructor and operator= functions.
|
||||
#define DISALLOW_IMPLICIT_CONSTRUCTORS(TypeName) \
|
||||
TypeName() = delete; \
|
||||
DISALLOW_COPY_AND_ASSIGN(TypeName)
|
||||
// Used to explicitly mark the return value of a function as unused. If you are
|
||||
// really sure you don't want to do anything with the return value of a function
|
||||
// that has been marked WARN_UNUSED_RESULT, wrap it with this. Example:
|
||||
//
|
||||
// std::unique_ptr<MyType> my_var = ...;
|
||||
// if (TakeOwnership(my_var.get()) == SUCCESS)
|
||||
// ignore_result(my_var.release());
|
||||
//
|
||||
template<typename T>
|
||||
inline void ignore_result(const T&) {
|
||||
}
|
||||
#endif // BASE_MACROS_H_
|
23
mediapipe/render/android/base_export.h
Normal file
23
mediapipe/render/android/base_export.h
Normal file
|
@ -0,0 +1,23 @@
|
|||
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
#ifndef BASE_BASE_EXPORT_H_
|
||||
#define BASE_BASE_EXPORT_H_
|
||||
#if defined(COMPONENT_BUILD)
|
||||
#if defined(WIN32)
|
||||
#if defined(BASE_IMPLEMENTATION)
|
||||
#define BASE_EXPORT __declspec(dllexport)
|
||||
#else
|
||||
#define BASE_EXPORT __declspec(dllimport)
|
||||
#endif // defined(BASE_IMPLEMENTATION)
|
||||
#else // defined(WIN32)
|
||||
#if defined(BASE_IMPLEMENTATION)
|
||||
#define BASE_EXPORT __attribute__((visibility("default")))
|
||||
#else
|
||||
#define BASE_EXPORT
|
||||
#endif // defined(BASE_IMPLEMENTATION)
|
||||
#endif
|
||||
#else // defined(COMPONENT_BUILD)
|
||||
#define BASE_EXPORT
|
||||
#endif
|
||||
#endif // BASE_BASE_EXPORT_H_
|
141
mediapipe/render/android/build_info.h
Normal file
141
mediapipe/render/android/build_info.h
Normal file
|
@ -0,0 +1,141 @@
|
|||
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
#ifndef BASE_ANDROID_BUILD_INFO_H_
|
||||
#define BASE_ANDROID_BUILD_INFO_H_
|
||||
#include <jni.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "base_export.h"
|
||||
#include "macros.h"
|
||||
#include "base/memory/singleton.h"
|
||||
namespace QImage {
|
||||
namespace android {
|
||||
// This enumeration maps to the values returned by BuildInfo::sdk_int(),
|
||||
// indicating the Android release associated with a given SDK version.
|
||||
enum SdkVersion {
|
||||
SDK_VERSION_JELLY_BEAN = 16,
|
||||
SDK_VERSION_JELLY_BEAN_MR1 = 17,
|
||||
SDK_VERSION_JELLY_BEAN_MR2 = 18,
|
||||
SDK_VERSION_KITKAT = 19,
|
||||
SDK_VERSION_KITKAT_WEAR = 20,
|
||||
SDK_VERSION_LOLLIPOP = 21,
|
||||
SDK_VERSION_LOLLIPOP_MR1 = 22,
|
||||
SDK_VERSION_MARSHMALLOW = 23,
|
||||
SDK_VERSION_NOUGAT = 24,
|
||||
SDK_VERSION_NOUGAT_MR1 = 25,
|
||||
SDK_VERSION_OREO = 26,
|
||||
SDK_VERSION_O_MR1 = 27,
|
||||
SDK_VERSION_P = 28,
|
||||
SDK_VERSION_Q = 29,
|
||||
SDK_VERSION_R = 30,
|
||||
};
|
||||
// BuildInfo is a singleton class that stores android build and device
|
||||
// information. It will be called from Android specific code and gets used
|
||||
// primarily in crash reporting.
|
||||
class BASE_EXPORT BuildInfo {
|
||||
public:
|
||||
~BuildInfo() {}
|
||||
// Static factory method for getting the singleton BuildInfo instance.
|
||||
// Note that ownership is not conferred on the caller and the BuildInfo in
|
||||
// question isn't actually freed until shutdown. This is ok because there
|
||||
// should only be one instance of BuildInfo ever created.
|
||||
static BuildInfo* GetInstance();
|
||||
// Const char* is used instead of std::strings because these values must be
|
||||
// available even if the process is in a crash state. Sadly
|
||||
// std::string.c_str() doesn't guarantee that memory won't be allocated when
|
||||
// it is called.
|
||||
const char* device() const {
|
||||
return device_;
|
||||
}
|
||||
const char* manufacturer() const {
|
||||
return manufacturer_;
|
||||
}
|
||||
const char* model() const {
|
||||
return model_;
|
||||
}
|
||||
const char* brand() const {
|
||||
return brand_;
|
||||
}
|
||||
const char* android_build_id() const {
|
||||
return android_build_id_;
|
||||
}
|
||||
const char* android_build_fp() const {
|
||||
return android_build_fp_;
|
||||
}
|
||||
const char* gms_version_code() const {
|
||||
return gms_version_code_;
|
||||
}
|
||||
const char* host_package_name() const { return host_package_name_; }
|
||||
const char* host_version_code() const { return host_version_code_; }
|
||||
const char* host_package_label() const { return host_package_label_; }
|
||||
const char* package_version_code() const {
|
||||
return package_version_code_;
|
||||
}
|
||||
const char* package_version_name() const {
|
||||
return package_version_name_;
|
||||
}
|
||||
const char* package_name() const {
|
||||
return package_name_;
|
||||
}
|
||||
// Will be empty string if no app id is assigned.
|
||||
const char* firebase_app_id() const { return firebase_app_id_; }
|
||||
const char* custom_themes() const { return custom_themes_; }
|
||||
const char* resources_version() const { return resources_version_; }
|
||||
const char* build_type() const {
|
||||
return build_type_;
|
||||
}
|
||||
const char* board() const { return board_; }
|
||||
const char* installer_package_name() const { return installer_package_name_; }
|
||||
const char* abi_name() const { return abi_name_; }
|
||||
int sdk_int() const {
|
||||
return sdk_int_;
|
||||
}
|
||||
// Returns the targetSdkVersion of the currently running app. If called from a
|
||||
// library, this returns the embedding app's targetSdkVersion.
|
||||
//
|
||||
// This can only be compared to finalized SDK versions, never against
|
||||
// pre-release Android versions. For pre-release Android versions, see the
|
||||
// targetsAtLeast*() methods in BuildInfo.java.
|
||||
int target_sdk_version() const { return target_sdk_version_; }
|
||||
bool is_debug_android() const { return is_debug_android_; }
|
||||
bool is_tv() const { return is_tv_; }
|
||||
const char* version_incremental() const { return version_incremental_; }
|
||||
private:
|
||||
friend struct BuildInfoSingletonTraits;
|
||||
explicit BuildInfo(const std::vector<std::string>& params);
|
||||
// Const char* is used instead of std::strings because these values must be
|
||||
// available even if the process is in a crash state. Sadly
|
||||
// std::string.c_str() doesn't guarantee that memory won't be allocated when
|
||||
// it is called.
|
||||
const char* const brand_;
|
||||
const char* const device_;
|
||||
const char* const android_build_id_;
|
||||
const char* const manufacturer_;
|
||||
const char* const model_;
|
||||
const int sdk_int_;
|
||||
const char* const build_type_;
|
||||
const char* const board_;
|
||||
const char* const host_package_name_;
|
||||
const char* const host_version_code_;
|
||||
const char* const host_package_label_;
|
||||
const char* const package_name_;
|
||||
const char* const package_version_code_;
|
||||
const char* const package_version_name_;
|
||||
const char* const android_build_fp_;
|
||||
const char* const gms_version_code_;
|
||||
const char* const installer_package_name_;
|
||||
const char* const abi_name_;
|
||||
const char* const firebase_app_id_;
|
||||
const char* const custom_themes_;
|
||||
const char* const resources_version_;
|
||||
// Not needed by breakpad.
|
||||
const int target_sdk_version_;
|
||||
const bool is_debug_android_;
|
||||
const bool is_tv_;
|
||||
const char* const version_incremental_;
|
||||
DISALLOW_COPY_AND_ASSIGN(BuildInfo);
|
||||
};
|
||||
} // namespace android
|
||||
} // namespace base
|
||||
#endif // BASE_ANDROID_BUILD_INFO_H_
|
38
mediapipe/render/android/macros.h
Normal file
38
mediapipe/render/android/macros.h
Normal file
|
@ -0,0 +1,38 @@
|
|||
// Copyright 2014 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
// This file contains macros and macro-like constructs (e.g., templates) that
|
||||
// are commonly used throughout Chromium source. (It may also contain things
|
||||
// that are closely related to things that are commonly used that belong in this
|
||||
// file.)
|
||||
#ifndef BASE_MACROS_H_
|
||||
#define BASE_MACROS_H_
|
||||
// ALL DISALLOW_xxx MACROS ARE DEPRECATED; DO NOT USE IN NEW CODE.
|
||||
// Use explicit deletions instead. See the section on copyability/movability in
|
||||
// //styleguide/c++/c++-dos-and-donts.md for more information.
|
||||
// DEPRECATED: See above. Makes a class uncopyable.
|
||||
#define DISALLOW_COPY(TypeName) \
|
||||
TypeName(const TypeName&) = delete
|
||||
// DEPRECATED: See above. Makes a class unassignable.
|
||||
#define DISALLOW_ASSIGN(TypeName) TypeName& operator=(const TypeName&) = delete
|
||||
// DEPRECATED: See above. Makes a class uncopyable and unassignable.
|
||||
#define DISALLOW_COPY_AND_ASSIGN(TypeName) \
|
||||
DISALLOW_COPY(TypeName); \
|
||||
DISALLOW_ASSIGN(TypeName)
|
||||
// DEPRECATED: See above. Disallow all implicit constructors, namely the
|
||||
// default constructor, copy constructor and operator= functions.
|
||||
#define DISALLOW_IMPLICIT_CONSTRUCTORS(TypeName) \
|
||||
TypeName() = delete; \
|
||||
DISALLOW_COPY_AND_ASSIGN(TypeName)
|
||||
// Used to explicitly mark the return value of a function as unused. If you are
|
||||
// really sure you don't want to do anything with the return value of a function
|
||||
// that has been marked WARN_UNUSED_RESULT, wrap it with this. Example:
|
||||
//
|
||||
// std::unique_ptr<MyType> my_var = ...;
|
||||
// if (TakeOwnership(my_var.get()) == SUCCESS)
|
||||
// ignore_result(my_var.release());
|
||||
//
|
||||
template<typename T>
|
||||
inline void ignore_result(const T&) {
|
||||
}
|
||||
#endif // BASE_MACROS_H_
|
83
mediapipe/render/android/no_destructor.h
Normal file
83
mediapipe/render/android/no_destructor.h
Normal file
|
@ -0,0 +1,83 @@
|
|||
// Copyright 2018 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
#ifndef BASE_NO_DESTRUCTOR_H_
|
||||
#define BASE_NO_DESTRUCTOR_H_
|
||||
#include <new>
|
||||
namespace QImage {
|
||||
// A wrapper that makes it easy to create an object of type T with static
|
||||
// storage duration that:
|
||||
// - is only constructed on first access
|
||||
// - never invokes the destructor
|
||||
// in order to satisfy the styleguide ban on global constructors and
|
||||
// destructors.
|
||||
//
|
||||
// Runtime constant example:
|
||||
// const std::string& GetLineSeparator() {
|
||||
// // Forwards to std::string(size_t, char, const Allocator&) constructor.
|
||||
// static const base::NoDestructor<std::string> s(5, '-');
|
||||
// return *s;
|
||||
// }
|
||||
//
|
||||
// More complex initialization with a lambda:
|
||||
// const std::string& GetSessionNonce() {
|
||||
// static const base::NoDestructor<std::string> nonce([] {
|
||||
// std::string s(16);
|
||||
// crypto::RandString(s.data(), s.size());
|
||||
// return s;
|
||||
// }());
|
||||
// return *nonce;
|
||||
// }
|
||||
//
|
||||
// NoDestructor<T> stores the object inline, so it also avoids a pointer
|
||||
// indirection and a malloc. Also note that since C++11 static local variable
|
||||
// initialization is thread-safe and so is this pattern. Code should prefer to
|
||||
// use NoDestructor<T> over:
|
||||
// - A function scoped static T* or T& that is dynamically initialized.
|
||||
// - A global base::LazyInstance<T>.
|
||||
//
|
||||
// Note that since the destructor is never run, this *will* leak memory if used
|
||||
// as a stack or member variable. Furthermore, a NoDestructor<T> should never
|
||||
// have global scope as that may require a static initializer.
|
||||
template <typename T>
|
||||
class NoDestructor {
|
||||
public:
|
||||
// Not constexpr; just write static constexpr T x = ...; if the value should
|
||||
// be a constexpr.
|
||||
template <typename... Args>
|
||||
explicit NoDestructor(Args&&... args) {
|
||||
new (storage_) T(std::forward<Args>(args)...);
|
||||
}
|
||||
// Allows copy and move construction of the contained type, to allow
|
||||
// construction from an initializer list, e.g. for std::vector.
|
||||
explicit NoDestructor(const T& x) { new (storage_) T(x); }
|
||||
explicit NoDestructor(T&& x) { new (storage_) T(std::move(x)); }
|
||||
NoDestructor(const NoDestructor&) = delete;
|
||||
NoDestructor& operator=(const NoDestructor&) = delete;
|
||||
~NoDestructor() = default;
|
||||
const T& operator*() const { return *get(); }
|
||||
T& operator*() { return *get(); }
|
||||
const T* operator->() const { return get(); }
|
||||
T* operator->() { return get(); }
|
||||
const T* get() const { return reinterpret_cast<const T*>(storage_); }
|
||||
T* get() { return reinterpret_cast<T*>(storage_); }
|
||||
private:
|
||||
alignas(T) char storage_[sizeof(T)];
|
||||
#if defined(LEAK_SANITIZER)
|
||||
// TODO(https://crbug.com/812277): This is a hack to work around the fact
|
||||
// that LSan doesn't seem to treat NoDestructor as a root for reachability
|
||||
// analysis. This means that code like this:
|
||||
// static base::NoDestructor<std::vector<int>> v({1, 2, 3});
|
||||
// is considered a leak. Using the standard leak sanitizer annotations to
|
||||
// suppress leaks doesn't work: std::vector is implicitly constructed before
|
||||
// calling the base::NoDestructor constructor.
|
||||
//
|
||||
// Unfortunately, I haven't been able to demonstrate this issue in simpler
|
||||
// reproductions: until that's resolved, hold an explicit pointer to the
|
||||
// placement-new'd object in leak sanitizer mode to help LSan realize that
|
||||
// objects allocated by the contained type are still reachable.
|
||||
T* storage_ptr_ = reinterpret_cast<T*>(storage_);
|
||||
#endif // defined(LEAK_SANITIZER)
|
||||
};
|
||||
} // namespace base
|
||||
#endif // BASE_NO_DESTRUCTOR_H_
|
164
mediapipe/render/core/BUILD
Normal file
164
mediapipe/render/core/BUILD
Normal file
|
@ -0,0 +1,164 @@
|
|||
|
||||
load("@bazel_skylib//lib:selects.bzl", "selects")
|
||||
load("@build_bazel_rules_apple//apple:ios.bzl", "ios_unit_test")
|
||||
load("//mediapipe/framework/port:build_config.bzl", "mediapipe_cc_proto_library", "mediapipe_proto_library")
|
||||
load("//mediapipe/framework:more_selects.bzl", "more_selects")
|
||||
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
|
||||
GL_BASE_LINK_OPTS = select({
|
||||
"//conditions:default": [],
|
||||
"//mediapipe:android": [
|
||||
"-lGLESv3",
|
||||
"-lEGL",
|
||||
"-ljnigraphics",
|
||||
# Note: on Android, libGLESv3.so is normally a symlink to
|
||||
# libGLESv2.so, so we don't need to link to it. In fact, we
|
||||
# do not _want_ to link to it, or we would be unable to load
|
||||
# on API level < 18, where the symlink is missing entirely.
|
||||
# Note: if we ever find a strange version of Android where the
|
||||
# GLESv3 library is not a symlink, we will have to load it at
|
||||
# runtime. Weak GLESv3 symbols will still be resolved if we
|
||||
# load it early enough.
|
||||
],
|
||||
"//mediapipe:ios": [
|
||||
"-framework OpenGLES",
|
||||
"-framework CoreVideo",
|
||||
],
|
||||
"//mediapipe:macos": [
|
||||
"-framework OpenGL",
|
||||
"-framework CoreVideo",
|
||||
],
|
||||
})
|
||||
|
||||
# This is @unused internally.
|
||||
GL_BASE_LINK_OPTS_OSS = GL_BASE_LINK_OPTS + select({
|
||||
"//conditions:default": [
|
||||
# Use GLES/EGL on linux.
|
||||
# Requires support from graphics card driver (nvidia,mesa,etc..)
|
||||
# and libraries to be installed.
|
||||
# Ex: libegl1-mesa-dev libgles2-mesa-dev, or libegl1-nvidia libgles2-nvidia, etc...
|
||||
"-lGLESv3",
|
||||
"-lEGL",
|
||||
"-ljnigraphics",
|
||||
],
|
||||
"//mediapipe:android": [],
|
||||
"//mediapipe:ios": [
|
||||
"-framework AVFoundation",
|
||||
"-framework CoreVideo",
|
||||
"-framework CoreGraphics",
|
||||
"-framework CoreMedia",
|
||||
"-framework GLKit",
|
||||
"-framework QuartzCore",],
|
||||
})
|
||||
|
||||
cc_library(
|
||||
name = "gpuimageutil",
|
||||
srcs = ["GPUImageUtil.cpp"],
|
||||
hdrs = ["GPUImageUtil.h"],
|
||||
visibility = ["//path/to/package:__pkg__"],
|
||||
deps = select({
|
||||
"//mediapipe:android": [],
|
||||
"//mediapipe:apple": [],
|
||||
"//conditions:default": [],
|
||||
}),
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "gpuimagemacros",
|
||||
hdrs = ["GPUImageMacros.h"],
|
||||
features = ["-layering_check"],
|
||||
|
||||
linkopts = select({
|
||||
"//conditions:default": [],
|
||||
"//mediapipe:ios": [
|
||||
"-framework OpenGLES",
|
||||
"-framework CoreVideo",
|
||||
"-framework AVFoundation",
|
||||
],
|
||||
"//mediapipe:macos": [
|
||||
"-framework OpenGL",
|
||||
"-framework CoreVideo",
|
||||
],
|
||||
}),
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [":gpuimageutil"] + select({
|
||||
"//mediapipe:android": [],
|
||||
"//mediapipe:apple": [],
|
||||
"//conditions:default": [],
|
||||
}),
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name="ref",
|
||||
srcs=["Ref.cpp"],
|
||||
hdrs=["Ref.hpp"],
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [":gpuimagemacros"]
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name="gpuimagemath",
|
||||
srcs=["math.cpp"],
|
||||
hdrs=["math.hpp"],
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
":gpuimagemacros",
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
|
||||
|
||||
cc_library(
|
||||
name = "core",
|
||||
srcs = [
|
||||
"FramebufferCache.cpp",
|
||||
"Framebuffer.cpp",
|
||||
"Target.cpp",
|
||||
"Context.cpp",
|
||||
"Filter.cpp",
|
||||
"GLProgram.cpp",
|
||||
"Source.cpp",
|
||||
"SourceImage.cpp",
|
||||
"IOSTarget.cpp",
|
||||
"SourceCamera.cpp",
|
||||
"TargetView.cpp",
|
||||
"FilterGroup.cpp"
|
||||
],
|
||||
hdrs = [
|
||||
"FramebufferCache.hpp",
|
||||
"Framebuffer.hpp",
|
||||
"Target.hpp",
|
||||
"Filter.hpp",
|
||||
"Context.hpp",
|
||||
"GLProgram.hpp",
|
||||
"Source.hpp",
|
||||
"SourceImage.hpp",
|
||||
"CVFramebuffer.hpp",
|
||||
"GPUImageTarget.h",
|
||||
"IOSTarget.hpp",
|
||||
"GPUImage-x.h",
|
||||
"SourceCamera.hpp",
|
||||
"TargetView.hpp",
|
||||
"FilterGroup.hpp",
|
||||
],
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
":gpuimageutil",
|
||||
":gpuimagemacros",
|
||||
":ref",
|
||||
"//mediapipe/render/core/math:math",
|
||||
":gpuimagemath"
|
||||
],
|
||||
copts = select({
|
||||
"//mediapipe:apple": [
|
||||
"-x objective-c++",
|
||||
"-fobjc-arc", # enable reference-counting
|
||||
],
|
||||
"//conditions:default": [],
|
||||
}),
|
||||
)
|
||||
|
||||
|
360
mediapipe/render/core/CVFramebuffer.cpp
Normal file
360
mediapipe/render/core/CVFramebuffer.cpp
Normal file
|
@ -0,0 +1,360 @@
|
|||
//
|
||||
// CVFramebuffer.cpp
|
||||
// Quaramera
|
||||
//
|
||||
// Created by wangrenzhu on 2021/4/30.
|
||||
//
|
||||
#include "CVFramebuffer.hpp"
|
||||
#include <assert.h>
|
||||
#include <algorithm>
|
||||
#include "Context.hpp"
|
||||
#include "GPUImageUtil.h"
|
||||
#include "GPUImageMacros.h"
|
||||
#include <Foundation/Foundation.h>
|
||||
#include <OpenGLES/EAGLIOSurface.h>
|
||||
#include <CoreVideo/CoreVideo.h>
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
|
||||
NS_GI_BEGIN
|
||||
|
||||
CVFramebuffer::CVFramebuffer(Context *context,
|
||||
int width,
|
||||
int height,
|
||||
const TextureAttributes textureAttributes,
|
||||
GLuint textureId) : QImage::Framebuffer()
|
||||
{
|
||||
_context = context;
|
||||
useTextureCache = true;
|
||||
_width = width;
|
||||
_height = height;
|
||||
_textureAttributes = textureAttributes;
|
||||
_texture = textureId;
|
||||
_generateFramebuffer(false);
|
||||
_context->_framebuffers.push_back(this);
|
||||
}
|
||||
|
||||
CVFramebuffer::CVFramebuffer(Context *context,
|
||||
int width,
|
||||
int height,
|
||||
bool onlyGenerateTexture/* = false*/,
|
||||
const TextureAttributes textureAttributes) : QImage::Framebuffer()
|
||||
{
|
||||
_context = context;
|
||||
useTextureCache = true;
|
||||
_width = width;
|
||||
_height = height;
|
||||
_textureAttributes = textureAttributes;
|
||||
_hasFB = !onlyGenerateTexture;
|
||||
if (_hasFB) {
|
||||
_generateFramebuffer();
|
||||
} else {
|
||||
_generateTexture();
|
||||
}
|
||||
|
||||
_context->_framebuffers.push_back(this);
|
||||
}
|
||||
|
||||
CVFramebuffer::CVFramebuffer(Context *context,
|
||||
int width, int height,
|
||||
GLuint handle, IOSurfaceID surfaceID,
|
||||
const TextureAttributes textureAttributes) : QImage::Framebuffer() {
|
||||
_context = context;
|
||||
useTextureCache = true;
|
||||
_width = width;
|
||||
_height = height;
|
||||
_texture = handle;
|
||||
_textureAttributes = textureAttributes;
|
||||
_ioSurfaceId = surfaceID;
|
||||
if (@available(iOS 11.0, *)) {
|
||||
renderIOSurface = IOSurfaceLookup(surfaceID); //可能为空
|
||||
if (renderIOSurface) {
|
||||
NSDictionary *cvBufferProperties = @{(id)kCVPixelBufferIOSurfacePropertiesKey : @{},
|
||||
(id)kCVPixelBufferIOSurfaceOpenGLESTextureCompatibilityKey: @(YES),
|
||||
(id)kCVPixelBufferOpenGLCompatibilityKey : @(YES),
|
||||
};
|
||||
|
||||
CVPixelBufferCreateWithIOSurface(kCFAllocatorDefault, renderIOSurface,
|
||||
(__bridge CFDictionaryRef)cvBufferProperties, &renderTarget);
|
||||
GLenum internalFormat = textureAttributes.internalFormat;
|
||||
GLenum extformat = GL_BGRA_EXT;
|
||||
|
||||
if (internalFormat == GL_LUMINANCE) {
|
||||
extformat = GL_R16F_EXT;
|
||||
}
|
||||
|
||||
#if !TARGET_OS_SIMULATOR
|
||||
CHECK_GL(glBindTexture(GL_TEXTURE_2D, _texture));
|
||||
EAGLContext *currentContext = this->getContext()->getEglContext();
|
||||
[EAGLContext setCurrentContext:currentContext];
|
||||
BOOL rs = [currentContext texImageIOSurface:renderIOSurface target:GL_TEXTURE_2D
|
||||
internalFormat:internalFormat
|
||||
width:_width height:_height
|
||||
format:extformat
|
||||
type:_textureAttributes.type plane:0];
|
||||
|
||||
if (rs) {
|
||||
LogE("CVFramebuffer", "IOSurface binding 成功");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
assert(0);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void CVFramebuffer::SetRenderTarget(CVPixelBufferRef pixel_buffer) {
|
||||
if (renderTarget) {
|
||||
CVPixelBufferRelease(renderTarget);
|
||||
}
|
||||
if (_glTexture) {
|
||||
CFRelease(_glTexture);
|
||||
}
|
||||
renderTarget = CVPixelBufferRetain(pixel_buffer);
|
||||
assert(_width == (int)CVPixelBufferGetWidth(renderTarget));
|
||||
assert(_height == (int)CVPixelBufferGetHeight(renderTarget));
|
||||
|
||||
CVOpenGLESTextureCacheCreateTextureFromImage(kCFAllocatorDefault,
|
||||
_context->iOSGLTextureCache,
|
||||
renderTarget, NULL,
|
||||
GL_TEXTURE_2D, GL_RGBA,
|
||||
(GLsizei)_width,
|
||||
(GLsizei)_height,
|
||||
GL_BGRA, GL_UNSIGNED_BYTE,
|
||||
0, &_glTexture);
|
||||
_texture = CVOpenGLESTextureGetName(_glTexture);
|
||||
|
||||
_bindFramebuffer();
|
||||
}
|
||||
|
||||
CVFramebuffer::~CVFramebuffer()
|
||||
{
|
||||
Log("", "Delete Framebuffer");
|
||||
if (NULL != _glTexture) {
|
||||
CFRelease(_glTexture);
|
||||
}
|
||||
|
||||
if (NULL != renderTarget) {
|
||||
CVPixelBufferUnlockBaseAddress(renderTarget, 0);
|
||||
CVPixelBufferRelease(renderTarget);
|
||||
}
|
||||
|
||||
if (NULL != renderIOSurface) {
|
||||
if (@available(iOS 11.0, *)) {
|
||||
IOSurfaceDecrementUseCount(renderIOSurface);
|
||||
CFRelease(renderIOSurface);
|
||||
}
|
||||
}
|
||||
|
||||
bool bDeleteTex = (_texture != -1);
|
||||
bool bDeleteFB = (_framebuffer != -1);
|
||||
|
||||
for (auto const &framebuffer : _context->_framebuffers) {
|
||||
if (!framebuffer || framebuffer == this) continue;
|
||||
if (bDeleteTex) {
|
||||
if (_texture == framebuffer->getTexture()) {
|
||||
bDeleteTex = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (bDeleteFB) {
|
||||
if (framebuffer->hasFramebuffer() &&
|
||||
_framebuffer == framebuffer->getFramebuffer()) {
|
||||
bDeleteFB = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<Framebuffer*>::iterator itr = std::find(_context->_framebuffers.begin(), _context->_framebuffers.end(), this);
|
||||
if (itr != _context->_framebuffers.end()) {
|
||||
_context->_framebuffers.erase(itr);
|
||||
}
|
||||
|
||||
if (bDeleteTex) {
|
||||
CHECK_GL(glDeleteTextures(1, &_texture));
|
||||
_texture = -1;
|
||||
}
|
||||
if (bDeleteFB) {
|
||||
CHECK_GL(glDeleteFramebuffers(1, &_framebuffer));
|
||||
_framebuffer = -1;
|
||||
}
|
||||
}
|
||||
|
||||
void CVFramebuffer::lockAddress()
|
||||
{
|
||||
if (renderTarget != NULL) {
|
||||
CVPixelBufferLockBaseAddress(renderTarget, kCVPixelBufferLock_ReadOnly);
|
||||
}
|
||||
}
|
||||
|
||||
void CVFramebuffer::unlockAddress()
|
||||
{
|
||||
if (renderTarget != NULL) {
|
||||
CVPixelBufferUnlockBaseAddress(renderTarget, kCVPixelBufferLock_ReadOnly);
|
||||
}
|
||||
}
|
||||
|
||||
int CVFramebuffer::getBytesPerRow()
|
||||
{
|
||||
if (renderTarget != NULL) {
|
||||
return (int)CVPixelBufferGetBytesPerRow(renderTarget);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void* CVFramebuffer::frameBufferGetBaseAddress()
|
||||
{
|
||||
if (renderTarget != NULL) {
|
||||
return CVPixelBufferGetBaseAddress(renderTarget);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void CVFramebuffer::_generateTexture()
|
||||
{
|
||||
|
||||
if (@available(iOS 11.0, *)) {
|
||||
CHECK_GL(glGenTextures(1, &_texture));
|
||||
CHECK_GL(glBindTexture(GL_TEXTURE_2D, _texture));
|
||||
CHECK_GL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
|
||||
_textureAttributes.minFilter));
|
||||
CHECK_GL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
|
||||
_textureAttributes.magFilter));
|
||||
CHECK_GL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, _textureAttributes.wrapS));
|
||||
CHECK_GL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, _textureAttributes.wrapT));
|
||||
|
||||
} else {
|
||||
|
||||
NSDictionary *cvBufferProperties = @{(id)kCVPixelBufferIOSurfacePropertiesKey : @{},
|
||||
(id)kCVPixelBufferIOSurfaceOpenGLESTextureCompatibilityKey: @(YES),
|
||||
(id)kCVPixelBufferOpenGLCompatibilityKey : @(YES),
|
||||
};
|
||||
__unused CVReturn cvret = CVPixelBufferCreate(kCFAllocatorDefault,
|
||||
_width,
|
||||
_height,
|
||||
kCVPixelFormatType_32BGRA,
|
||||
(__bridge CFDictionaryRef)cvBufferProperties,
|
||||
&renderTarget);
|
||||
|
||||
if (cvret != kCVReturnSuccess) {
|
||||
Log("", "Failed to create CVPixelBuffer");
|
||||
}
|
||||
|
||||
cvret = CVOpenGLESTextureCacheCreateTextureFromImage(kCFAllocatorDefault,
|
||||
_context->iOSGLTextureCache,
|
||||
renderTarget,
|
||||
nil,
|
||||
GL_TEXTURE_2D,
|
||||
GL_RGBA,
|
||||
_width, _height,
|
||||
GL_BGRA,
|
||||
GL_UNSIGNED_BYTE,
|
||||
0,
|
||||
&_glTexture);
|
||||
if (cvret != kCVReturnSuccess) {
|
||||
Log("", "Failed to create _glTexture");
|
||||
}
|
||||
|
||||
_texture = CVOpenGLESTextureGetName(_glTexture);
|
||||
|
||||
CHECK_GL(glBindTexture(GL_TEXTURE_2D, _texture));
|
||||
CHECK_GL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
|
||||
_textureAttributes.minFilter));
|
||||
CHECK_GL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
|
||||
_textureAttributes.magFilter));
|
||||
CHECK_GL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, _textureAttributes.wrapS));
|
||||
CHECK_GL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, _textureAttributes.wrapT));
|
||||
CHECK_GL(glBindTexture(GL_TEXTURE_2D, 0));
|
||||
}
|
||||
}
|
||||
|
||||
void CVFramebuffer::_generateFramebuffer(bool needGenerateTexture)
|
||||
{
|
||||
|
||||
|
||||
CHECK_GL(glGenFramebuffers(1, &_framebuffer));
|
||||
|
||||
if (needGenerateTexture) {
|
||||
_generateTexture();
|
||||
}
|
||||
|
||||
_bindFramebuffer();
|
||||
|
||||
}
|
||||
|
||||
|
||||
void CVFramebuffer::_bindFramebuffer() {
|
||||
if (@available(iOS 11.0, *)) {
|
||||
NSDictionary *cvBufferProperties = @{(id)kCVPixelBufferIOSurfacePropertiesKey : @{},
|
||||
(id)kCVPixelBufferIOSurfaceOpenGLESTextureCompatibilityKey: @(YES),
|
||||
(id)kCVPixelBufferOpenGLCompatibilityKey : @(YES),
|
||||
};
|
||||
CHECK_GL(glBindTexture(GL_TEXTURE_2D, _texture));
|
||||
EAGLContext *currentContext = this->getContext()->getEglContext();
|
||||
|
||||
unsigned bytesPerElement = 4;
|
||||
|
||||
size_t bytesPerRow = IOSurfaceAlignProperty(kIOSurfaceBytesPerRow, _width * bytesPerElement);
|
||||
size_t totalBytes = IOSurfaceAlignProperty(kIOSurfaceAllocSize, _height * bytesPerRow);
|
||||
id cvformat = @(kCVPixelFormatType_32BGRA);
|
||||
|
||||
if (_textureAttributes.format == GL_LUMINANCE) {
|
||||
cvformat = @(kCVPixelFormatType_16Gray);
|
||||
}
|
||||
|
||||
NSDictionary *dict = @{
|
||||
(id)kIOSurfaceWidth : @(_width),
|
||||
(id)kIOSurfaceHeight : @(_height),
|
||||
(id)kIOSurfacePixelFormat : cvformat,
|
||||
(id)kIOSurfaceBytesPerElement : @(bytesPerElement),
|
||||
(id)kIOSurfaceBytesPerRow : @(bytesPerRow),
|
||||
(id)kIOSurfaceAllocSize : @(totalBytes),
|
||||
(id)kIOSurfaceIsGlobal: @YES
|
||||
};
|
||||
|
||||
renderIOSurface = IOSurfaceCreate((CFDictionaryRef)dict);
|
||||
_ioSurfaceId = IOSurfaceGetID(renderIOSurface);
|
||||
|
||||
GLenum internalFormat = _textureAttributes.internalFormat;
|
||||
GLenum extformat = GL_BGRA_EXT;
|
||||
|
||||
if (internalFormat == GL_LUMINANCE) {
|
||||
extformat = GL_R16F_EXT;
|
||||
}
|
||||
|
||||
CVPixelBufferCreateWithIOSurface(kCFAllocatorDefault, renderIOSurface,
|
||||
(__bridge CFDictionaryRef)cvBufferProperties, &renderTarget);
|
||||
#if !TARGET_OS_SIMULATOR
|
||||
BOOL rs = [currentContext texImageIOSurface:renderIOSurface target:GL_TEXTURE_2D
|
||||
internalFormat:internalFormat
|
||||
width:_width height:_height
|
||||
format:extformat
|
||||
type:_textureAttributes.type plane:0];
|
||||
IOSurfaceIncrementUseCount(renderIOSurface);
|
||||
if (rs) {
|
||||
LogE("CVFramebuffer", "IOSurface binding 成功");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
CHECK_GL(glBindTexture(GL_TEXTURE_2D, 0));
|
||||
|
||||
CHECK_GL(glBindFramebuffer(GL_FRAMEBUFFER, _framebuffer));
|
||||
CHECK_GL(glBindTexture(GL_TEXTURE_2D, _texture));
|
||||
|
||||
CHECK_GL(glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
|
||||
_texture, 0));
|
||||
|
||||
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
|
||||
assert(status == GL_FRAMEBUFFER_COMPLETE);
|
||||
|
||||
CHECK_GL(glBindTexture(GL_TEXTURE_2D, 0));
|
||||
CHECK_GL(glBindFramebuffer(GL_FRAMEBUFFER, 0));
|
||||
// QImage::Log("Quaramera", "_generateFramebuffer %d ", _framebuffer);
|
||||
assert(_framebuffer < 100);
|
||||
}
|
||||
|
||||
|
||||
NS_GI_END
|
60
mediapipe/render/core/CVFramebuffer.hpp
Normal file
60
mediapipe/render/core/CVFramebuffer.hpp
Normal file
|
@ -0,0 +1,60 @@
|
|||
//
|
||||
// CVFramebuffer.hpp
|
||||
// Quaramera
|
||||
//
|
||||
// Created by wangrenzhu on 2021/4/30.
|
||||
//
|
||||
|
||||
#ifndef CVFramebuffer_hpp
|
||||
#define CVFramebuffer_hpp
|
||||
|
||||
#include <stdio.h>
|
||||
#include <OpenGLES/ES3/gl.h>
|
||||
#include <OpenGLES/ES3/glext.h>
|
||||
#include <CoreVideo/CoreVideo.h>
|
||||
#include <vector>
|
||||
#include "Ref.hpp"
|
||||
#include "Framebuffer.hpp"
|
||||
|
||||
namespace QImage {
|
||||
|
||||
|
||||
class CVFramebuffer : public QImage::Framebuffer {
|
||||
public:
|
||||
|
||||
CVFramebuffer(Context *context, int width, int height,
|
||||
const TextureAttributes textureAttributes = defaultTextureAttribures,
|
||||
GLuint textureId = -1);
|
||||
CVFramebuffer(Context *context, int width, int height, bool onlyGenerateTexture = false,
|
||||
const TextureAttributes textureAttributes = defaultTextureAttribures);
|
||||
|
||||
CVFramebuffer(Context *context,
|
||||
int width, int height,
|
||||
GLuint handle, IOSurfaceID surfaceID,
|
||||
const TextureAttributes textureAttributes = defaultTextureAttribures);
|
||||
|
||||
void SetRenderTarget(CVPixelBufferRef pixel_buffer);
|
||||
virtual ~CVFramebuffer();
|
||||
|
||||
void lockAddress() override;
|
||||
void unlockAddress() override;
|
||||
void* frameBufferGetBaseAddress() override;
|
||||
int getBytesPerRow() override;
|
||||
CVPixelBufferRef renderTarget = 0;
|
||||
IOSurfaceRef renderIOSurface = 0;
|
||||
private:
|
||||
|
||||
void _generateTexture() override;
|
||||
void _bindFramebuffer();
|
||||
void _generateFramebuffer(bool needGenerateTexture = true) override;
|
||||
|
||||
CVOpenGLESTextureRef _glTexture = 0;
|
||||
IOSurfaceID _ioSurfaceId = -1;
|
||||
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif /* CVFramebuffer_hpp */
|
430
mediapipe/render/core/Context.cpp
Executable file
430
mediapipe/render/core/Context.cpp
Executable file
|
@ -0,0 +1,430 @@
|
|||
/*
|
||||
* GPUImage-x
|
||||
*
|
||||
* Copyright (C) 2017 Yijin Wang, Yiqian Wang
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#if defined(__APPLE__)
|
||||
#import <OpenGLES/EAGLDrawable.h>
|
||||
#import <OpenGLES/ES3/glext.h>
|
||||
|
||||
#endif
|
||||
#include "Filter.hpp"
|
||||
#include "Context.hpp"
|
||||
#include "GPUImageUtil.h"
|
||||
|
||||
NS_GI_BEGIN
|
||||
|
||||
Context* Context::_instance = 0;
|
||||
std::mutex Context::_mutex;
|
||||
std::string Context::activatedContextKey = "";
|
||||
std::map<std::string, Context*> Context::_ContextCache;
|
||||
|
||||
Context::Context()
|
||||
:_curShaderProgram(0)
|
||||
,isCapturingFrame(false)
|
||||
,captureUpToFilter(0)
|
||||
,capturedFrameData(0)
|
||||
,_eglContext(0)
|
||||
,_eglOfflinerenderContext(0)
|
||||
,_eglContextIO(0)
|
||||
,vertexArray(-1)
|
||||
{
|
||||
_framebufferCache = new FramebufferCache(this);
|
||||
|
||||
#if defined(__APPLE__)
|
||||
_eglContextIO = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES3];
|
||||
shareGroup = [_eglContextIO sharegroup];
|
||||
_eglContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES3 sharegroup:shareGroup];
|
||||
|
||||
_eglOfflinerenderContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES3 sharegroup:shareGroup];
|
||||
_eglUpipeContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES3 sharegroup:shareGroup];
|
||||
|
||||
NSDictionary * cacheAttributes = @{ (NSString *)kCVOpenGLESTextureCacheMaximumTextureAgeKey: @(0.0) };
|
||||
|
||||
__unused CVReturn cvret;
|
||||
cvret = CVOpenGLESTextureCacheCreate(kCFAllocatorDefault,
|
||||
(__bridge CFDictionaryRef _Nullable)(cacheAttributes),
|
||||
_eglContext,
|
||||
nil,
|
||||
&iOSGLTextureCache);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
Context::~Context() {
|
||||
glFinish();
|
||||
delete _framebufferCache;
|
||||
|
||||
#if defined(__ANDROID__) || defined(ANDROID)
|
||||
if (_eglContextIO)
|
||||
{
|
||||
delete _eglContextIO;
|
||||
_eglContextIO = 0;
|
||||
}
|
||||
|
||||
if (_eglOfflinerenderContext)
|
||||
{
|
||||
delete _eglOfflinerenderContext;
|
||||
_eglOfflinerenderContext = 0;
|
||||
}
|
||||
|
||||
if (_eglContext)
|
||||
{
|
||||
delete _eglContext;
|
||||
_eglContext = 0;
|
||||
}
|
||||
#else
|
||||
_eglContextIO = NULL;
|
||||
_eglContext = NULL;
|
||||
_eglOfflinerenderContext = NULL;
|
||||
_eglUpipeContext = NULL;
|
||||
shareGroup = NULL;
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
for (auto const &program : _programs) {
|
||||
if (program->getID() != -1) {
|
||||
glDeleteProgram(program->getID());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#if defined(__APPLE__)
|
||||
if (iOSGLTextureCache) {
|
||||
|
||||
CVOpenGLESTextureCacheFlush(iOSGLTextureCache, 0);
|
||||
CFRelease(iOSGLTextureCache);
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
Context* Context::getInstance() {
|
||||
std::unique_lock<std::mutex> lock(_mutex);
|
||||
if (!_instance)
|
||||
{
|
||||
_instance = new (std::nothrow) Context;
|
||||
|
||||
if (!Context::activatedContextKey.empty()) {
|
||||
_ContextCache[Context::activatedContextKey] = _instance;
|
||||
}
|
||||
}
|
||||
if (_ContextCache.find(Context::activatedContextKey) != _ContextCache.end()) {
|
||||
return _ContextCache[activatedContextKey];
|
||||
} else {
|
||||
return _instance;
|
||||
}
|
||||
};
|
||||
|
||||
void Context::init() {
|
||||
destroy();
|
||||
getInstance();
|
||||
}
|
||||
|
||||
void Context::destroy() {
|
||||
std::unique_lock<std::mutex> lock(_mutex);
|
||||
if (!Context::activatedContextKey.empty() && _ContextCache.find(Context::activatedContextKey) != _ContextCache.end()) {
|
||||
Context *instance = _ContextCache[Context::activatedContextKey];
|
||||
_ContextCache.erase(activatedContextKey);
|
||||
delete instance;
|
||||
instance = 0;
|
||||
} else if (_instance) {
|
||||
delete _instance;
|
||||
_instance = 0;
|
||||
}
|
||||
}
|
||||
|
||||
FramebufferCache* Context::getFramebufferCache() const {
|
||||
return _framebufferCache;
|
||||
}
|
||||
|
||||
void Context::setActiveShaderProgram(GLProgram* shaderProgram) {
|
||||
if (_curShaderProgram != shaderProgram)
|
||||
{
|
||||
_curShaderProgram = shaderProgram;
|
||||
shaderProgram->use();
|
||||
} else if(shaderProgram){
|
||||
//double check gl current program id
|
||||
GLint cur_program_id ;
|
||||
CHECK_GL(glGetIntegerv(GL_CURRENT_PROGRAM, &cur_program_id));
|
||||
if( cur_program_id != shaderProgram->getID()){
|
||||
_curShaderProgram = shaderProgram;
|
||||
shaderProgram->use();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void Context::cleanupFramebuffers() {
|
||||
_framebufferCache->purge();
|
||||
_framebuffers.clear();
|
||||
}
|
||||
|
||||
void Context::purge() {
|
||||
// _framebufferCache->purge();
|
||||
// _framebuffers.clear();
|
||||
//
|
||||
#if defined(__APPLE__)
|
||||
if (iOSGLTextureCache) {
|
||||
|
||||
CVOpenGLESTextureCacheFlush(iOSGLTextureCache, 0);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(__APPLE__)
|
||||
void Context::useAsCurrent(ContextType type/* = GPUImageContext*/, bool force/* = false*/)
|
||||
{
|
||||
if (type == IOContext)
|
||||
{
|
||||
if ([EAGLContext currentContext] != _eglContextIO || force)
|
||||
{
|
||||
[EAGLContext setCurrentContext:_eglContextIO];
|
||||
}
|
||||
}
|
||||
else if (type == OfflineRenderContext)
|
||||
{
|
||||
if ([EAGLContext currentContext] != _eglOfflinerenderContext || force)
|
||||
{
|
||||
[EAGLContext setCurrentContext:_eglOfflinerenderContext];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ([EAGLContext currentContext] != _eglContext || force)
|
||||
{
|
||||
[EAGLContext setCurrentContext:_eglContext];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Context::renewOfflineRenderContext()
|
||||
{
|
||||
EAGLSharegroup *group = [_eglContext sharegroup];
|
||||
_eglOfflinerenderContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES3 sharegroup:group];
|
||||
}
|
||||
|
||||
void Context::presentBufferForDisplay() {
|
||||
[_eglContext presentRenderbuffer:GL_RENDERBUFFER ];
|
||||
}
|
||||
|
||||
|
||||
#else
|
||||
void Context::useAsCurrent(ContextType type/* = GPUImageContext*/, bool force /* = false*/)
|
||||
{
|
||||
if (type == IOContext)
|
||||
{
|
||||
if (_eglContextIO != NULL && (eglGetCurrentContext() != _eglContextIO->context() || force)) {
|
||||
_eglContextIO->useAsCurrent();
|
||||
}
|
||||
}
|
||||
else if (type == OfflineRenderContext)
|
||||
{
|
||||
if (_eglOfflinerenderContext != NULL && (eglGetCurrentContext() != _eglOfflinerenderContext->context() || force)) {
|
||||
_eglOfflinerenderContext->useAsCurrent();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//use java EGL instead
|
||||
// _eglContext->useAsCurrent();
|
||||
}
|
||||
}
|
||||
|
||||
void Context::renewOfflineRenderContext()
|
||||
{
|
||||
if (_eglOfflinerenderContext)
|
||||
{
|
||||
EGLContext sharedContext = _eglOfflinerenderContext->sharedContext;
|
||||
delete _eglOfflinerenderContext;
|
||||
_eglOfflinerenderContext = 0;
|
||||
_eglOfflinerenderContext = new EAGLContext(sharedContext);
|
||||
}
|
||||
}
|
||||
|
||||
void Context::reset() {
|
||||
_curShaderProgram = nullptr;
|
||||
}
|
||||
|
||||
void Context::initEGLContext(EGLContext shareContext) {
|
||||
purge();
|
||||
if (_eglContextIO)
|
||||
{
|
||||
delete _eglContextIO;
|
||||
_eglContextIO = 0;
|
||||
}
|
||||
|
||||
if (_eglOfflinerenderContext)
|
||||
{
|
||||
delete _eglOfflinerenderContext;
|
||||
_eglOfflinerenderContext = 0;
|
||||
}
|
||||
|
||||
if (_eglContext)
|
||||
{
|
||||
delete _eglContext;
|
||||
_eglContext = 0;
|
||||
}
|
||||
_eglContextIO = new EAGLContext(shareContext);
|
||||
_eglOfflinerenderContext = new EAGLContext(shareContext);
|
||||
//use java EGL instead
|
||||
// _eglContext = new EAGLContext(shareContext);
|
||||
}
|
||||
|
||||
Context::EAGLContext::EAGLContext(EGLContext sharedContext) : sharedContext(sharedContext)
|
||||
{
|
||||
EGLint eglConfigAttrs[] =
|
||||
{
|
||||
EGL_DEPTH_SIZE, 24,
|
||||
EGL_RED_SIZE, 8,
|
||||
EGL_GREEN_SIZE, 8,
|
||||
EGL_BLUE_SIZE, 8,
|
||||
EGL_ALPHA_SIZE, 8,
|
||||
EGL_STENCIL_SIZE, 8,
|
||||
EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,
|
||||
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
|
||||
EGL_NONE
|
||||
};
|
||||
EGLint eglContextAttrs[] =
|
||||
{
|
||||
EGL_CONTEXT_CLIENT_VERSION, 3,
|
||||
EGL_NONE
|
||||
};
|
||||
EGLint pbufferAttribList[] =
|
||||
{
|
||||
EGL_WIDTH, 512,
|
||||
EGL_HEIGHT, 512,
|
||||
EGL_LARGEST_PBUFFER, EGL_TRUE,
|
||||
EGL_NONE
|
||||
};
|
||||
// egl display
|
||||
_eglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
|
||||
|
||||
EGLint majorVersion;
|
||||
EGLint minorVersion;
|
||||
eglInitialize(_eglDisplay,&majorVersion,&minorVersion);
|
||||
|
||||
// egl config
|
||||
EGLConfig config;
|
||||
EGLint numConfigs = 0;
|
||||
eglChooseConfig(_eglDisplay,eglConfigAttrs,&config,1,&numConfigs);
|
||||
|
||||
_pbuffer = eglCreatePbufferSurface(_eglDisplay,config,pbufferAttribList);
|
||||
|
||||
_context = eglCreateContext(_eglDisplay,config,sharedContext,eglContextAttrs);
|
||||
|
||||
}
|
||||
|
||||
Context::EAGLContext::~EAGLContext()
|
||||
{
|
||||
eglDestroySurface(_eglDisplay,_pbuffer);
|
||||
eglDestroyContext(_eglDisplay,_context);
|
||||
}
|
||||
|
||||
void Context::EAGLContext::useAsCurrent()
|
||||
{
|
||||
eglMakeCurrent(_eglDisplay, _pbuffer, _pbuffer, _context);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
const GLfloat * Context::textureCoordinatesForRotation(QImage::RotationMode rotationMode)
|
||||
{
|
||||
static const GLfloat noRotationTextureCoordinates[] = {
|
||||
0.0f, 0.0f,
|
||||
1.0f, 0.0f,
|
||||
0.0f, 1.0f,
|
||||
1.0f, 1.0f,
|
||||
};
|
||||
|
||||
static const GLfloat rotateLeftTextureCoordinates[] = {
|
||||
1.0f, 0.0f,
|
||||
1.0f, 1.0f,
|
||||
0.0f, 0.0f,
|
||||
0.0f, 1.0f,
|
||||
};
|
||||
|
||||
static const GLfloat rotateRightTextureCoordinates[] = {
|
||||
0.0f, 1.0f,
|
||||
0.0f, 0.0f,
|
||||
1.0f, 1.0f,
|
||||
1.0f, 0.0f,
|
||||
};
|
||||
|
||||
static const GLfloat verticalFlipTextureCoordinates[] = {
|
||||
0.0f, 1.0f,
|
||||
1.0f, 1.0f,
|
||||
0.0f, 0.0f,
|
||||
1.0f, 0.0f,
|
||||
};
|
||||
|
||||
static const GLfloat horizontalFlipTextureCoordinates[] = {
|
||||
1.0f, 0.0f,
|
||||
0.0f, 0.0f,
|
||||
1.0f, 1.0f,
|
||||
0.0f, 1.0f,
|
||||
};
|
||||
|
||||
static const GLfloat rotateRightVerticalFlipTextureCoordinates[] = {
|
||||
0.0f, 0.0f,
|
||||
0.0f, 1.0f,
|
||||
1.0f, 0.0f,
|
||||
1.0f, 1.0f,
|
||||
};
|
||||
|
||||
static const GLfloat rotateRightHorizontalFlipTextureCoordinates[] = {
|
||||
1.0f, 1.0f,
|
||||
1.0f, 0.0f,
|
||||
0.0f, 1.0f,
|
||||
0.0f, 0.0f,
|
||||
};
|
||||
|
||||
static const GLfloat rotate180TextureCoordinates[] = {
|
||||
1.0f, 1.0f,
|
||||
0.0f, 1.0f,
|
||||
1.0f, 0.0f,
|
||||
0.0f, 0.0f,
|
||||
};
|
||||
|
||||
switch(rotationMode)
|
||||
{
|
||||
case NoRotation: return noRotationTextureCoordinates;
|
||||
case RotateLeft: return rotateLeftTextureCoordinates;
|
||||
case RotateRight: return rotateRightTextureCoordinates;
|
||||
case FlipVertical: return verticalFlipTextureCoordinates;
|
||||
case FlipHorizontal: return horizontalFlipTextureCoordinates;
|
||||
case RotateRightFlipVertical: return rotateRightVerticalFlipTextureCoordinates;
|
||||
case RotateRightFlipHorizontal: return rotateRightHorizontalFlipTextureCoordinates;
|
||||
case Rotate180: return rotate180TextureCoordinates;
|
||||
}
|
||||
}
|
||||
|
||||
void Context::releaseVBOBuffers()
|
||||
{
|
||||
if (vertexArray != -1) {
|
||||
CHECK_GL(glDeleteBuffers(1, &vertexArray));
|
||||
vertexArray = -1;
|
||||
CHECK_GL(glDeleteBuffers(8, elementArray));
|
||||
for (int i = 0; i < 8; i++) {
|
||||
elementArray[i] = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NS_GI_END
|
138
mediapipe/render/core/Context.hpp
Executable file
138
mediapipe/render/core/Context.hpp
Executable file
|
@ -0,0 +1,138 @@
|
|||
/*
|
||||
* GPUImage-x
|
||||
*
|
||||
* Copyright (C) 2017 Yijin Wang, Yiqian Wang
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef Context_hpp
|
||||
#define Context_hpp
|
||||
#include "GPUImageMacros.h"
|
||||
#include "FramebufferCache.hpp"
|
||||
#include "Target.hpp"
|
||||
#include "GLProgram.hpp"
|
||||
#include <mutex>
|
||||
#include <pthread.h>
|
||||
|
||||
|
||||
#if defined(__APPLE__)
|
||||
#import <OpenGLES/EAGL.h>
|
||||
#import <OpenGLES/ES3/gl.h>
|
||||
#import <CoreVideo/CoreVideo.h>
|
||||
#else
|
||||
#include <EGL/egl.h>
|
||||
#endif
|
||||
|
||||
|
||||
NS_GI_BEGIN
|
||||
class Filter;
|
||||
class Context {
|
||||
public:
|
||||
|
||||
Context();
|
||||
~Context();
|
||||
|
||||
static void init();
|
||||
static void destroy();
|
||||
|
||||
static Context* getInstance();
|
||||
|
||||
FramebufferCache* getFramebufferCache() const;
|
||||
void setActiveShaderProgram(GLProgram* shaderProgram);
|
||||
void purge();
|
||||
void cleanupFramebuffers();
|
||||
|
||||
const GLfloat *textureCoordinatesForRotation(QImage::RotationMode rotationMode);
|
||||
|
||||
enum ContextType
|
||||
{
|
||||
GPUImageContext = 0,
|
||||
OfflineRenderContext,
|
||||
IOContext,
|
||||
};
|
||||
|
||||
void useAsCurrent(ContextType type = GPUImageContext, bool force = false);
|
||||
|
||||
#if defined(__APPLE__)
|
||||
EAGLContext* getEglContext() const { return _eglContext; };
|
||||
EAGLContext* getEglUpipeContext() const { return _eglUpipeContext; };
|
||||
void renewOfflineRenderContext();
|
||||
void presentBufferForDisplay();
|
||||
#else
|
||||
EGLContext getEglContext() const { return _eglContext->context(); };
|
||||
void renewOfflineRenderContext();
|
||||
void initEGLContext(EGLContext shareContext);
|
||||
|
||||
void reset();
|
||||
#endif
|
||||
|
||||
// 不要用这个截帧 性能极低
|
||||
bool isCapturingFrame;
|
||||
Filter* captureUpToFilter;
|
||||
unsigned char* capturedFrameData;
|
||||
int captureWidth;
|
||||
int captureHeight;
|
||||
static std::string activatedContextKey;
|
||||
|
||||
//Filter
|
||||
GLuint vertexArray;
|
||||
GLuint elementArray[8];
|
||||
|
||||
void releaseVBOBuffers();
|
||||
|
||||
//Framebuffer
|
||||
std::vector<Framebuffer*> _framebuffers;
|
||||
|
||||
//GLProgram
|
||||
std::vector<GLProgram*> _programs;
|
||||
|
||||
#if defined(__APPLE__)
|
||||
CVOpenGLESTextureCacheRef iOSGLTextureCache;
|
||||
EAGLSharegroup *shareGroup;
|
||||
#endif
|
||||
|
||||
private:
|
||||
static Context* _instance;
|
||||
static std::map<std::string, Context*> _ContextCache;
|
||||
|
||||
static std::mutex _mutex;
|
||||
FramebufferCache* _framebufferCache;
|
||||
GLProgram* _curShaderProgram;
|
||||
|
||||
#if defined(__ANDROID__) || defined(ANDROID)
|
||||
class EAGLContext
|
||||
{
|
||||
public:
|
||||
void useAsCurrent();
|
||||
EGLContext sharedContext;
|
||||
EGLContext context(){return _context;};
|
||||
EAGLContext(EGLContext sharedContext);
|
||||
~EAGLContext();
|
||||
|
||||
private:
|
||||
EGLContext _context;
|
||||
EGLSurface _pbuffer;
|
||||
EGLDisplay _eglDisplay;
|
||||
};
|
||||
#endif
|
||||
|
||||
EAGLContext* _eglContext;
|
||||
EAGLContext* _eglOfflinerenderContext;
|
||||
EAGLContext* _eglContextIO;
|
||||
EAGLContext* _eglUpipeContext;
|
||||
};
|
||||
|
||||
NS_GI_END
|
||||
|
||||
#endif /* Context_hpp */
|
652
mediapipe/render/core/Filter.cpp
Executable file
652
mediapipe/render/core/Filter.cpp
Executable file
|
@ -0,0 +1,652 @@
|
|||
/*
|
||||
* GPUImage-x
|
||||
*
|
||||
* Copyright (C) 2017 Yijin Wang, Yiqian Wang
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
#include "Context.hpp"
|
||||
#include "Filter.hpp"
|
||||
|
||||
NS_GI_BEGIN
|
||||
|
||||
std::map<std::string, std::function<Filter*()>> Filter::_filterFactories;
|
||||
//static GLuint vertexArray = -1;
|
||||
//static GLuint elementArray[8];
|
||||
|
||||
Filter::Filter(Context *context) : Source(context)
|
||||
,_filterProgram(0)
|
||||
,_filterClassName("")
|
||||
{
|
||||
_mvp_matrix.set_identity();
|
||||
_backgroundColor.r = 1.0;
|
||||
_backgroundColor.g = 1.0;
|
||||
_backgroundColor.b = 1.0;
|
||||
_backgroundColor.a = 1.0;
|
||||
}
|
||||
|
||||
Filter::Filter() {
|
||||
|
||||
}
|
||||
|
||||
Filter::~Filter() {
|
||||
if (_filterProgram) {
|
||||
delete _filterProgram;
|
||||
_filterProgram = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void Filter::generateVBOBuffers()
|
||||
{
|
||||
if (_context->vertexArray == -1) {
|
||||
GLfloat textureCoordinates[] = {
|
||||
//noRotationTextureCoordinates
|
||||
-1.0f, -1.0f, //v0
|
||||
0.0f, 0.0f, //c0
|
||||
1.0f, -1.0f, //v1
|
||||
1.0f, 0.0f, //c1
|
||||
-1.0f, 1.0f, //v2
|
||||
0.0f, 1.0f, //c2
|
||||
1.0f, 1.0f, //v3
|
||||
1.0f, 1.0f, //c3
|
||||
|
||||
//rotateLeftTextureCoordinates
|
||||
-1.0f, -1.0f, //v0
|
||||
1.0f, 0.0f, //c0
|
||||
1.0f, -1.0f, //v1
|
||||
1.0f, 1.0f, //c1
|
||||
-1.0f, 1.0f, //v2
|
||||
0.0f, 0.0f, //c2
|
||||
1.0f, 1.0f, //v3
|
||||
0.0f, 1.0f, //c3
|
||||
|
||||
//rotateRightTextureCoordinates
|
||||
-1.0f, -1.0f, //v0
|
||||
0.0f, 1.0f, //c0
|
||||
1.0f, -1.0f, //v1
|
||||
0.0f, 0.0f, //c1
|
||||
-1.0f, 1.0f, //v2
|
||||
1.0f, 1.0f, //c2
|
||||
1.0f, 1.0f, //v3
|
||||
1.0f, 0.0f, //c3
|
||||
|
||||
//attach
|
||||
1.0f, -1.0f, //v1
|
||||
0.0f, 1.0f, //c1
|
||||
-1.0f, 1.0f, //v2
|
||||
1.0f, 0.0f, //c2
|
||||
-1.0f, -1.0f, //v0
|
||||
1.0f, 1.0f, //c0
|
||||
1.0f, 1.0f, //v3
|
||||
0.0f, 0.0f, //c3
|
||||
|
||||
};
|
||||
|
||||
CHECK_GL(glGenBuffers(1, &(_context->vertexArray)));
|
||||
CHECK_GL(glBindBuffer(GL_ARRAY_BUFFER, _context->vertexArray));
|
||||
CHECK_GL(glBufferData(GL_ARRAY_BUFFER, 16 * sizeof(GLfloat) * 4, textureCoordinates, GL_STATIC_DRAW));
|
||||
|
||||
CHECK_GL(glGenBuffers(8, _context->elementArray));
|
||||
{
|
||||
//noRotationTextureCoordinates
|
||||
GLushort indices[4] = {0, 1, 2, 3};
|
||||
CHECK_GL(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _context->elementArray[0]));
|
||||
CHECK_GL(glBufferData(GL_ELEMENT_ARRAY_BUFFER, 4 * sizeof(GLushort), indices, GL_STATIC_DRAW));
|
||||
}
|
||||
|
||||
{
|
||||
//rotateLeftTextureCoordinates
|
||||
GLushort indices[4] = {4, 5, 6, 7};
|
||||
CHECK_GL(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _context->elementArray[1]));
|
||||
CHECK_GL(glBufferData(GL_ELEMENT_ARRAY_BUFFER, 4 * sizeof(GLushort), indices, GL_STATIC_DRAW));
|
||||
}
|
||||
|
||||
{
|
||||
//rotateRightTextureCoordinates
|
||||
GLushort indices[4] = {8, 9, 10, 11};
|
||||
CHECK_GL(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _context->elementArray[2]));
|
||||
CHECK_GL(glBufferData(GL_ELEMENT_ARRAY_BUFFER, 4 * sizeof(GLushort), indices, GL_STATIC_DRAW));
|
||||
}
|
||||
|
||||
{
|
||||
//verticalFlipTextureCoordinates
|
||||
GLushort indices[4] = {8, 5, 6, 11};
|
||||
CHECK_GL(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _context->elementArray[3]));
|
||||
CHECK_GL(glBufferData(GL_ELEMENT_ARRAY_BUFFER, 4 * sizeof(GLushort), indices, GL_STATIC_DRAW));
|
||||
}
|
||||
|
||||
{
|
||||
//horizontalFlipTextureCoordinates
|
||||
GLushort indices[4] = {4, 9, 10, 7};
|
||||
CHECK_GL(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _context->elementArray[4]));
|
||||
CHECK_GL(glBufferData(GL_ELEMENT_ARRAY_BUFFER, 4 * sizeof(GLushort), indices, GL_STATIC_DRAW));
|
||||
}
|
||||
|
||||
{
|
||||
//rotateRightVerticalFlipTextureCoordinates
|
||||
GLushort indices[4] = {0, 12, 13, 3};
|
||||
CHECK_GL(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _context->elementArray[5]));
|
||||
CHECK_GL(glBufferData(GL_ELEMENT_ARRAY_BUFFER, 4 * sizeof(GLushort), indices, GL_STATIC_DRAW));
|
||||
}
|
||||
|
||||
{
|
||||
//rotateRightHorizontalFlipTextureCoordinates
|
||||
GLushort indices[4] = {14, 1, 2, 15};
|
||||
CHECK_GL(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _context->elementArray[6]));
|
||||
CHECK_GL(glBufferData(GL_ELEMENT_ARRAY_BUFFER, 4 * sizeof(GLushort), indices, GL_STATIC_DRAW));
|
||||
}
|
||||
|
||||
{
|
||||
//rotate180TextureCoordinates
|
||||
GLushort indices[4] = {14, 12, 13, 15};
|
||||
CHECK_GL(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _context->elementArray[7]));
|
||||
CHECK_GL(glBufferData(GL_ELEMENT_ARRAY_BUFFER, 4 * sizeof(GLushort), indices, GL_STATIC_DRAW));
|
||||
}
|
||||
|
||||
CHECK_GL(glBindBuffer(GL_ARRAY_BUFFER, 0));
|
||||
CHECK_GL(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0));
|
||||
}
|
||||
}
|
||||
|
||||
//void Filter::releaseVBOBuffers()
|
||||
//{
|
||||
// if (vertexArray != -1) {
|
||||
// CHECK_GL(glDeleteBuffers(0, &vertexArray));
|
||||
// vertexArray = -1;
|
||||
// CHECK_GL(glDeleteBuffers(8, elementArray));
|
||||
// for (int i = 0; i < 8; i++) {
|
||||
// elementArray[i] = -1;
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
|
||||
Filter* Filter::create(Context *context, const std::string& filterClassName) {
|
||||
std::map<std::string, std::function<Filter*()>>::iterator it = _filterFactories.find(filterClassName);
|
||||
if (it == _filterFactories.end())
|
||||
return 0;
|
||||
else {
|
||||
Filter* filter = it->second();
|
||||
filter->setFilterClassName(filterClassName);
|
||||
return it->second();
|
||||
}
|
||||
}
|
||||
|
||||
Filter* Filter::createWithShaderString(Context *context,
|
||||
const std::string& vertexShaderSource,
|
||||
const std::string& fragmentShaderSource) {
|
||||
Filter* filter = new Filter(context);
|
||||
if (!filter->initWithShaderString(context, vertexShaderSource, fragmentShaderSource)) {
|
||||
delete filter;
|
||||
filter = 0;
|
||||
return 0;
|
||||
}
|
||||
return filter;
|
||||
}
|
||||
|
||||
Filter* Filter::createWithFragmentShaderString(Context *context,
|
||||
const std::string& fragmentShaderSource,
|
||||
int inputNumber/* = 1*/) {
|
||||
Filter* filter = new Filter(context);
|
||||
if (!filter->initWithFragmentShaderString(context, fragmentShaderSource,inputNumber)) {
|
||||
delete filter;
|
||||
filter = 0;
|
||||
return 0;
|
||||
}
|
||||
return filter;
|
||||
}
|
||||
|
||||
bool Filter::initWithShaderString(Context *context,
|
||||
const std::string& vertexShaderSource,
|
||||
const std::string& fragmentShaderSource) {
|
||||
|
||||
_filterProgram = GLProgram::createByShaderString(context, vertexShaderSource, fragmentShaderSource);
|
||||
if (_filterProgram == NULL) {
|
||||
return false; //shader创建失败
|
||||
}
|
||||
// _context = context;
|
||||
|
||||
_filterPositionAttribute = _filterProgram->getAttribLocation("position");
|
||||
_uniform_mvp = _filterProgram->getUniformLocation("mvp");
|
||||
getContext()->setActiveShaderProgram(_filterProgram);
|
||||
if (_filterPositionAttribute != -1) {
|
||||
CHECK_GL(glEnableVertexAttribArray(_filterPositionAttribute));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Filter::initWithFragmentShaderString(Context *context,
|
||||
const std::string& fragmentShaderSource,
|
||||
int inputNumber/* = 1*/) {
|
||||
_inputNum = inputNumber;
|
||||
return initWithShaderString(context, _getVertexShaderString(), fragmentShaderSource);
|
||||
}
|
||||
|
||||
std::string Filter::_getVertexShaderString() const {
|
||||
|
||||
if (_inputNum <= 1)
|
||||
{
|
||||
return kDefaultVertexShader;
|
||||
}
|
||||
|
||||
std::string shaderStr = "\
|
||||
attribute vec4 position;\n\
|
||||
attribute vec4 texCoord;\n\
|
||||
varying vec2 vTexCoord;\n\
|
||||
";
|
||||
for (int i = 1; i < _inputNum; ++i) {
|
||||
shaderStr += str_format("\
|
||||
attribute vec4 texCoord%d;\n\
|
||||
varying vec2 vTexCoord%d;\n\
|
||||
", i, i);
|
||||
}
|
||||
shaderStr += "\
|
||||
void main()\n\
|
||||
{\n\
|
||||
gl_Position = position;\n\
|
||||
vTexCoord = texCoord.xy;\n\
|
||||
";
|
||||
for (int i = 1; i < _inputNum; ++i) {
|
||||
shaderStr += str_format("vTexCoord%d = texCoord%d.xy;\n", i, i);
|
||||
}
|
||||
shaderStr += "}\n";
|
||||
|
||||
return shaderStr;
|
||||
}
|
||||
|
||||
void Filter::setInputFramebuffer(Framebuffer* framebuffer,
|
||||
RotationMode rotationMode,
|
||||
int texIdx, bool ignoreForPrepared) {
|
||||
Target::setInputFramebuffer(framebuffer, rotationMode, texIdx, ignoreForPrepared);
|
||||
}
|
||||
|
||||
bool Filter::proceed(float frameTime, bool bUpdateTargets/* = true*/) {
|
||||
if (_framebuffer->isDealloc) {
|
||||
return false;
|
||||
}
|
||||
auto logstr = str_format(" QuarameraLayerGLRender:%s渲染耗时", typeid(*this).name());
|
||||
{
|
||||
#if DEBUG
|
||||
_framebuffer->lock(typeid(*this).name());
|
||||
#else
|
||||
_framebuffer->lock();
|
||||
#endif
|
||||
generateVBOBuffers();
|
||||
|
||||
getContext()->setActiveShaderProgram(_filterProgram);
|
||||
_framebuffer->active();
|
||||
|
||||
_filterProgram->setUniformValue("iTime", _frameCount);
|
||||
_frameCount += 0.1;
|
||||
if (_useScaleResolution) {
|
||||
_filterProgram->setUniformValue("iResolution", _scaleResolution);
|
||||
} else {
|
||||
_filterProgram->setUniformValue("iResolution", Vector2(_framebuffer->getWidth(), _framebuffer->getHeight()));
|
||||
}
|
||||
|
||||
|
||||
if (_uniform_mvp != -1) {
|
||||
_filterProgram->setUniformValue(_uniform_mvp, _mvp_matrix);
|
||||
}
|
||||
CHECK_GL(glBindBuffer(GL_ARRAY_BUFFER, _context->vertexArray));
|
||||
CHECK_GL(glClearColor(_backgroundColor.r, _backgroundColor.g, _backgroundColor.b, _backgroundColor.a));
|
||||
CHECK_GL(glClear(GL_COLOR_BUFFER_BIT));
|
||||
|
||||
int elementIndex = 0;
|
||||
for (std::map<int, InputFrameBufferInfo>::const_iterator it = _inputFramebuffers.begin(); it != _inputFramebuffers.end(); ++it) {
|
||||
int texIdx = it->first;
|
||||
Framebuffer* fb = it->second.frameBuffer;
|
||||
if (fb == NULL) {
|
||||
return false;
|
||||
}
|
||||
CHECK_GL(glActiveTexture(GL_TEXTURE0 + texIdx));
|
||||
CHECK_GL(glBindTexture(GL_TEXTURE_2D, fb->getTexture()));
|
||||
_filterProgram->setUniformValue(
|
||||
texIdx == 0 ? "colorMap" : str_format("colorMap%d", texIdx),
|
||||
texIdx);
|
||||
// texcoord attribute
|
||||
GLuint filterTexCoordAttribute = _filterProgram->getAttribLocation(texIdx == 0 ? "texCoord" : str_format("texCoord%d", texIdx));
|
||||
if (filterTexCoordAttribute != (GLuint)-1)
|
||||
{
|
||||
CHECK_GL(glVertexAttribPointer(filterTexCoordAttribute, 2, GL_FLOAT, 0, 4 * sizeof(GLfloat), (void *)8));
|
||||
CHECK_GL(glEnableVertexAttribArray(filterTexCoordAttribute));
|
||||
}
|
||||
|
||||
elementIndex = it->second.rotationMode;
|
||||
|
||||
|
||||
}
|
||||
CHECK_GL(glVertexAttribPointer(_filterPositionAttribute, 2, GL_FLOAT, 0, 4 * sizeof(GLfloat), (void *)0));
|
||||
CHECK_GL(glEnableVertexAttribArray(_filterPositionAttribute));
|
||||
|
||||
// CHECK_GL(glEnable(GL_BLEND));
|
||||
// CHECK_GL(glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA));
|
||||
|
||||
CHECK_GL(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _context->elementArray[elementIndex]));
|
||||
CHECK_GL(glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_SHORT, 0));
|
||||
|
||||
CHECK_GL(glBindBuffer(GL_ARRAY_BUFFER, 0));
|
||||
CHECK_GL(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0));
|
||||
filter_externDraw();
|
||||
_framebuffer->inactive();
|
||||
Log("Filter", "%s渲染完毕,准备开始Unlock Framebuffer:%s", typeid(*this).name(),
|
||||
_framebuffer->_hashCode.c_str());
|
||||
#if DEBUG
|
||||
_framebuffer->unlock(typeid(*this).name());
|
||||
#else
|
||||
_framebuffer->unlock();
|
||||
#endif
|
||||
unPrepear();
|
||||
}
|
||||
return Source::proceed(frameTime, bUpdateTargets);
|
||||
}
|
||||
|
||||
void Filter::filter_externDraw()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
const GLfloat* Filter::_getTexureCoordinate(const RotationMode& rotationMode) const {
|
||||
static const GLfloat noRotationTextureCoordinates[] = {
|
||||
0.0f, 0.0f,
|
||||
1.0f, 0.0f,
|
||||
0.0f, 1.0f,
|
||||
1.0f, 1.0f,
|
||||
};
|
||||
|
||||
static const GLfloat rotateLeftTextureCoordinates[] = {
|
||||
1.0f, 0.0f,
|
||||
1.0f, 1.0f,
|
||||
0.0f, 0.0f,
|
||||
0.0f, 1.0f,
|
||||
};
|
||||
|
||||
static const GLfloat rotateRightTextureCoordinates[] = {
|
||||
0.0f, 1.0f,
|
||||
0.0f, 0.0f,
|
||||
1.0f, 1.0f,
|
||||
1.0f, 0.0f,
|
||||
};
|
||||
|
||||
static const GLfloat verticalFlipTextureCoordinates[] = {
|
||||
0.0f, 1.0f,
|
||||
1.0f, 1.0f,
|
||||
0.0f, 0.0f,
|
||||
1.0f, 0.0f,
|
||||
};
|
||||
|
||||
static const GLfloat horizontalFlipTextureCoordinates[] = {
|
||||
1.0f, 0.0f,
|
||||
0.0f, 0.0f,
|
||||
1.0f, 1.0f,
|
||||
0.0f, 1.0f,
|
||||
};
|
||||
|
||||
static const GLfloat rotateRightVerticalFlipTextureCoordinates[] = {
|
||||
0.0f, 0.0f,
|
||||
0.0f, 1.0f,
|
||||
1.0f, 0.0f,
|
||||
1.0f, 1.0f,
|
||||
};
|
||||
|
||||
static const GLfloat rotateRightHorizontalFlipTextureCoordinates[] = {
|
||||
1.0f, 1.0f,
|
||||
1.0f, 0.0f,
|
||||
0.0f, 1.0f,
|
||||
0.0f, 0.0f,
|
||||
};
|
||||
|
||||
static const GLfloat rotate180TextureCoordinates[] = {
|
||||
1.0f, 1.0f,
|
||||
0.0f, 1.0f,
|
||||
1.0f, 0.0f,
|
||||
0.0f, 0.0f,
|
||||
};
|
||||
|
||||
switch (rotationMode) {
|
||||
case NoRotation:
|
||||
return noRotationTextureCoordinates;
|
||||
break;
|
||||
case RotateLeft:
|
||||
return rotateLeftTextureCoordinates;
|
||||
break;
|
||||
case RotateRight:
|
||||
return rotateRightTextureCoordinates;
|
||||
break;
|
||||
case FlipVertical:
|
||||
return verticalFlipTextureCoordinates;
|
||||
break;
|
||||
case FlipHorizontal:
|
||||
return horizontalFlipTextureCoordinates;
|
||||
break;
|
||||
case RotateRightFlipVertical:
|
||||
return rotateRightVerticalFlipTextureCoordinates;
|
||||
break;
|
||||
case RotateRightFlipHorizontal:
|
||||
return rotateRightHorizontalFlipTextureCoordinates;
|
||||
break;
|
||||
case Rotate180:
|
||||
return rotate180TextureCoordinates;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void Filter::update(float frameTime) {
|
||||
if (_inputFramebuffers.empty()) return;
|
||||
|
||||
if (!_enable) {
|
||||
_framebuffer = _inputFramebuffers.begin()->second.frameBuffer;
|
||||
Source::updateTargets(frameTime);
|
||||
_framebuffer = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (getContext()->isCapturingFrame && this == getContext()->captureUpToFilter) {
|
||||
int captureWidth = getContext()->captureWidth;
|
||||
int captureHeight = getContext()->captureHeight;
|
||||
|
||||
_framebuffer = getContext()->getFramebufferCache()->fetchFramebuffer(_context, captureWidth, captureHeight);
|
||||
#if DEBUG
|
||||
_framebuffer->lock(typeid(*this).name());
|
||||
#else
|
||||
_framebuffer->lock();
|
||||
#endif
|
||||
proceed(false);
|
||||
|
||||
_framebuffer->active();
|
||||
getContext()->capturedFrameData = new unsigned char[captureWidth * captureHeight * 4];
|
||||
CHECK_GL(glReadPixels(0, 0, captureWidth, captureHeight, GL_RGBA, GL_UNSIGNED_BYTE, getContext()->capturedFrameData));
|
||||
_framebuffer->inactive();
|
||||
#if DEBUG
|
||||
_framebuffer->unlock(typeid(*this).name());
|
||||
#else
|
||||
_framebuffer->unlock();
|
||||
#endif
|
||||
} else {
|
||||
// todo
|
||||
Framebuffer* firstInputFramebuffer = _inputFramebuffers.begin()->second.frameBuffer;
|
||||
RotationMode firstInputRotation = _inputFramebuffers.begin()->second.rotationMode;
|
||||
if (!firstInputFramebuffer) return;
|
||||
|
||||
int rotatedFramebufferWidth = firstInputFramebuffer->getWidth();
|
||||
int rotatedFramebufferHeight = firstInputFramebuffer->getHeight();
|
||||
if (rotationSwapsSize(firstInputRotation))
|
||||
{
|
||||
rotatedFramebufferWidth = firstInputFramebuffer->getHeight();
|
||||
rotatedFramebufferHeight = firstInputFramebuffer->getWidth();
|
||||
}
|
||||
|
||||
if (_framebufferScale != 1.0) {
|
||||
rotatedFramebufferWidth = int(rotatedFramebufferWidth * _framebufferScale);
|
||||
rotatedFramebufferHeight = int(rotatedFramebufferHeight * _framebufferScale);
|
||||
}
|
||||
|
||||
_framebuffer = getContext()->getFramebufferCache()->fetchFramebuffer(_context, rotatedFramebufferWidth, rotatedFramebufferHeight);
|
||||
proceed(frameTime);
|
||||
}
|
||||
// _context->getFramebufferCache()->returnFramebuffer(_framebuffer);
|
||||
_framebuffer = 0;
|
||||
}
|
||||
|
||||
bool Filter::registerProperty(const std::string& name, int defaultValue, const std::string& comment/* = ""*/, std::function<void(int&)> setCallback/* = 0*/) {
|
||||
if (hasProperty(name)) return false;
|
||||
IntProperty property;
|
||||
property.type = "int";
|
||||
property.value = defaultValue;
|
||||
property.comment = comment;
|
||||
property.setCallback = setCallback;
|
||||
_intProperties[name] = property;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Filter::registerProperty(const std::string& name, float defaultValue, const std::string& comment/* = ""*/, std::function<void(float&)> setCallback/* = 0*/) {
|
||||
if (hasProperty(name)) return false;
|
||||
FloatProperty property;
|
||||
property.type = "float";
|
||||
property.value = defaultValue;
|
||||
property.comment = comment;
|
||||
property.setCallback = setCallback;
|
||||
_floatProperties[name] = property;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Filter::registerProperty(const std::string& name, const std::string& defaultValue, const std::string& comment/* = ""*/, std::function<void(std::string&)> setCallback/* = 0*/) {
|
||||
if (hasProperty(name)) return false;
|
||||
StringProperty property;
|
||||
property.type = "string";
|
||||
property.value = defaultValue;
|
||||
property.comment = comment;
|
||||
property.setCallback = setCallback;
|
||||
_stringProperties[name] = property;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Filter::setProperty(const std::string& name, int value) {
|
||||
Property* rawProperty = _getProperty(name);
|
||||
if (!rawProperty) {
|
||||
Log("WARNING", "Filter::setProperty invalid property %s", name.c_str());
|
||||
return false;
|
||||
} else if (rawProperty->type != "int") {
|
||||
Log("WARNING", "Filter::setProperty The property type is expected to be %s", rawProperty->type.c_str());
|
||||
return false;
|
||||
}
|
||||
IntProperty* property = ((IntProperty*)rawProperty);
|
||||
property->value = value;
|
||||
if (property->setCallback)
|
||||
property->setCallback(value);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Filter::setProperty(const std::string& name, float value) {
|
||||
Property* rawProperty = _getProperty(name);
|
||||
if (!rawProperty) {
|
||||
Log("WARNING", "Filter::setProperty invalid property %s", name.c_str());
|
||||
return false;
|
||||
} else if (rawProperty->type != "float") {
|
||||
Log("WARNING", "Filter::setProperty The property type is expected to be %s", rawProperty->type.c_str());
|
||||
return false;
|
||||
}
|
||||
FloatProperty* property = ((FloatProperty*)rawProperty);
|
||||
if (property->setCallback)
|
||||
property->setCallback(value);
|
||||
property->value = value;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Filter::setProperty(const std::string& name, std::string value) {
|
||||
Property* rawProperty = _getProperty(name);
|
||||
if (!rawProperty) {
|
||||
Log("WARNING", "Filter::setProperty invalid property %s", name.c_str());
|
||||
return false;
|
||||
} else if (rawProperty->type != "string") {
|
||||
Log("WARNING", "Filter::setProperty The property type is expected to be %s", rawProperty->type.c_str());
|
||||
return false;
|
||||
}
|
||||
StringProperty* property = ((StringProperty*)rawProperty);
|
||||
property->value = value;
|
||||
if (property->setCallback)
|
||||
property->setCallback(value);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Filter::getProperty(const std::string& name, int& retValue) {
|
||||
Property* property = _getProperty(name);
|
||||
if (!property) return false;
|
||||
retValue = ((IntProperty*)property)->value;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Filter::getProperty(const std::string& name, float& retValue) {
|
||||
Property* property = _getProperty(name);
|
||||
if (!property) return false;
|
||||
retValue = ((FloatProperty*)property)->value;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Filter::getProperty(const std::string& name, std::string& retValue) {
|
||||
Property* property = _getProperty(name);
|
||||
if (!property) return false;
|
||||
retValue = ((StringProperty*)property)->value;
|
||||
return true;
|
||||
}
|
||||
|
||||
Filter::Property* Filter::_getProperty(const std::string& name) {
|
||||
if (_intProperties.find(name) != _intProperties.end()) {
|
||||
return &_intProperties[name];
|
||||
}
|
||||
if (_floatProperties.find(name) != _floatProperties.end()) {
|
||||
return &_floatProperties[name];
|
||||
}
|
||||
if (_stringProperties.find(name) != _stringProperties.end()) {
|
||||
return &_stringProperties[name];
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool Filter::hasProperty(const std::string& name, const std::string type) {
|
||||
Property* property = _getProperty(name);
|
||||
return property && property->type == type ? true : false;
|
||||
}
|
||||
|
||||
bool Filter::hasProperty(const std::string& name) {
|
||||
return _getProperty(name) ? true : false;
|
||||
}
|
||||
|
||||
bool Filter::getPropertyComment(const std::string& name, std::string& retComment) {
|
||||
Property* property = _getProperty(name);
|
||||
if (!property) return false;
|
||||
retComment = std::string("[") + property->type + "] " + property->comment;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Filter::getPropertyType(const std::string& name, std::string& retType) {
|
||||
Property* property = _getProperty(name);
|
||||
if (!property) return false;
|
||||
retType = property->type;
|
||||
return true;
|
||||
}
|
||||
|
||||
Context *Filter::getContext() {
|
||||
if (_context) {
|
||||
return _context;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
NS_GI_END
|
278
mediapipe/render/core/Filter.hpp
Normal file
278
mediapipe/render/core/Filter.hpp
Normal file
|
@ -0,0 +1,278 @@
|
|||
/*
|
||||
* GPUImage-x
|
||||
*
|
||||
* Copyright (C) 2017 Yijin Wang, Yiqian Wang
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef Filter_hpp
|
||||
#define Filter_hpp
|
||||
#include "string"
|
||||
#include "GPUImageMacros.h"
|
||||
#include "Source.hpp"
|
||||
#include "Target.hpp"
|
||||
#include "GLProgram.hpp"
|
||||
#include "Ref.hpp"
|
||||
#include "GPUImageUtil.h"
|
||||
|
||||
|
||||
NS_GI_BEGIN
|
||||
|
||||
|
||||
// Hardcode the vertex shader for standard filters, but this can be overridden
|
||||
const std::string kDefaultVertexShader = SHADER_STRING
|
||||
(
|
||||
attribute vec4 position;
|
||||
attribute vec4 texCoord;
|
||||
|
||||
// uniform mat4 mvp;
|
||||
|
||||
varying vec2 vTexCoord;
|
||||
|
||||
|
||||
void main()
|
||||
{
|
||||
// gl_Position = mvp * position;
|
||||
gl_Position = position;
|
||||
vTexCoord = texCoord.xy;
|
||||
}
|
||||
);
|
||||
|
||||
const std::string kDefaultFragmentShader = SHADER_STRING
|
||||
(
|
||||
varying highp vec2 vTexCoord;
|
||||
uniform sampler2D colorMap;
|
||||
|
||||
void main()
|
||||
{
|
||||
gl_FragColor = texture2D(colorMap, vTexCoord);
|
||||
}
|
||||
);
|
||||
|
||||
const std::string kDefaultDisplayFragmentShader = SHADER_STRING
|
||||
(
|
||||
precision highp float;
|
||||
varying highp vec2 vTexCoord;
|
||||
uniform sampler2D colorMap;
|
||||
void main()
|
||||
{
|
||||
vec4 color = texture2D(colorMap, vTexCoord);
|
||||
gl_FragColor = vec4(color.rgb, 1);
|
||||
}
|
||||
);
|
||||
|
||||
const std::string kDefaultCaptureFragmentShader = SHADER_STRING
|
||||
(
|
||||
precision highp float;
|
||||
varying highp vec2 vTexCoord;
|
||||
uniform sampler2D colorMap;
|
||||
void main()
|
||||
{
|
||||
vec4 color = texture2D(colorMap, vTexCoord);
|
||||
gl_FragColor = vec4(color.rgb, 1);
|
||||
}
|
||||
);
|
||||
|
||||
class Context;
|
||||
class Filter : public Source, public Target {
|
||||
public:
|
||||
virtual ~Filter();
|
||||
|
||||
Filter();
|
||||
|
||||
static Filter* create(Context *context, const std::string& filterClassName);
|
||||
static Filter* createWithShaderString(Context *context,
|
||||
const std::string& vertexShaderSource,
|
||||
const std::string& fragmentShaderSource);
|
||||
static Filter* createWithFragmentShaderString(Context *context,
|
||||
const std::string& fragmentShaderSource,
|
||||
int inputNumber = 1);
|
||||
|
||||
bool initWithShaderString(Context *context, const std::string& vertexShaderSource, const std::string& fragmentShaderSource);
|
||||
virtual bool initWithFragmentShaderString(Context *context,
|
||||
const std::string& fragmentShaderSource,
|
||||
int inputNumber = 1);
|
||||
|
||||
void setFilterClassName(const std::string filterClassName) {
|
||||
_filterClassName = filterClassName;
|
||||
}
|
||||
std::string getFilterClassName() const { return _filterClassName; };
|
||||
|
||||
virtual void update(float frameTime) override;
|
||||
virtual bool proceed(float frameTime = 0.0,
|
||||
bool bUpdateTargets = true) override;
|
||||
|
||||
virtual void setInputFramebuffer(Framebuffer* framebuffer,
|
||||
RotationMode rotationMode = NoRotation,
|
||||
int texIdx = 0, bool ignoreForPrepared = false) override;
|
||||
GLProgram* getProgram() const { return _filterProgram; };
|
||||
|
||||
// property setters & getters
|
||||
virtual bool registerProperty(const std::string& name, int defaultValue, const std::string& comment = "", std::function<void(int&)> setCallback = 0);
|
||||
virtual bool registerProperty(const std::string& name, float defaultValue, const std::string& comment = "", std::function<void(float&)> setCallback = 0);
|
||||
virtual bool registerProperty(const std::string& name, const std::string& defaultValue, const std::string& comment = "", std::function<void(std::string&)> setCallback = 0);
|
||||
bool setProperty(const std::string& name, int value);
|
||||
bool setProperty(const std::string& name, float value);
|
||||
bool setProperty(const std::string& name, std::string value);
|
||||
bool getProperty(const std::string& name, int& retValue);
|
||||
bool getProperty(const std::string& name, float& retValue);
|
||||
bool getProperty(const std::string& name, std::string& retValue);
|
||||
bool hasProperty(const std::string& name);
|
||||
bool hasProperty(const std::string& name, const std::string type);
|
||||
bool getPropertyComment(const std::string& name, std::string& retComment);
|
||||
bool getPropertyType(const std::string& name, std::string& retType);
|
||||
|
||||
bool isEnable() {
|
||||
return _enable;
|
||||
}
|
||||
|
||||
bool isForceEnable() {
|
||||
return _forceEnable;
|
||||
}
|
||||
|
||||
void setEnable(bool enable) {
|
||||
if (_forceEnable) {
|
||||
//强制设定时外部不可更改
|
||||
return;
|
||||
}
|
||||
_enable = enable;
|
||||
}
|
||||
|
||||
void setForceEnable(bool force, bool enable) {
|
||||
_forceEnable = force;
|
||||
_enable = enable;
|
||||
}
|
||||
|
||||
void setContext(Context *context) {
|
||||
_context = context;
|
||||
}
|
||||
#if defined(__ANDROID__) || defined(ANDROID)
|
||||
class Registry {
|
||||
public:
|
||||
Registry(const std::string& name, std::function<Filter*()> createFunc) {
|
||||
Filter::_registerFilterClass(name, createFunc);
|
||||
}
|
||||
};
|
||||
static void _registerFilterClass(const std::string& filterClassName, std::function<Filter*()> createFunc) {
|
||||
//Log("jin", "Filter::registerClass : %s", filterClassName.c_str());
|
||||
_filterFactories[filterClassName] = createFunc;
|
||||
}
|
||||
#endif
|
||||
|
||||
public:
|
||||
virtual void filter_externDraw();
|
||||
struct {
|
||||
float r; float g; float b; float a;
|
||||
} _backgroundColor;
|
||||
|
||||
// 外部告知需要旋转的方向
|
||||
void setTargetRotationMode(RotationMode rotation) {
|
||||
_targetRotation = rotation;
|
||||
};
|
||||
|
||||
RotationMode getTargetRotationMode() {
|
||||
return _targetRotation;
|
||||
}
|
||||
public:
|
||||
|
||||
bool useScaleResolution() {
|
||||
return _useScaleResolution;
|
||||
}
|
||||
|
||||
Vector2 getScaleResolution() {
|
||||
return _scaleResolution;
|
||||
}
|
||||
|
||||
void setScaleResolution(Vector2 resolution) {
|
||||
_useScaleResolution = true;
|
||||
_scaleResolution = resolution;
|
||||
}
|
||||
|
||||
protected:
|
||||
Vector4 _roi = Vector4(0.0, 0.0, 1.0, 1.0);
|
||||
float _rotate = 0.0;
|
||||
|
||||
|
||||
protected:
|
||||
|
||||
RotationMode _targetRotation = NoRotation;
|
||||
GLProgram* _filterProgram = nullptr;
|
||||
GLuint _filterPositionAttribute = -1;
|
||||
GLint _uniform_mvp = -1;
|
||||
|
||||
std::string _filterClassName;
|
||||
float _frameCount = 0.0;
|
||||
|
||||
Filter(Context *context);
|
||||
std::string _getVertexShaderString() const;
|
||||
const GLfloat* _getTexureCoordinate(const RotationMode& rotationMode) const;
|
||||
|
||||
// properties
|
||||
struct Property {
|
||||
std::string type;
|
||||
std::string comment;
|
||||
};
|
||||
virtual Property* _getProperty(const std::string& name);
|
||||
|
||||
struct IntProperty : Property {
|
||||
int value;
|
||||
std::function<void(int&)> setCallback;
|
||||
};
|
||||
std::map<std::string, IntProperty> _intProperties;
|
||||
|
||||
struct FloatProperty : Property {
|
||||
float value;
|
||||
std::function<void(float&)> setCallback;
|
||||
};
|
||||
std::map<std::string, FloatProperty> _floatProperties;
|
||||
|
||||
struct StringProperty : Property {
|
||||
std::string value;
|
||||
std::function<void(std::string&)> setCallback;
|
||||
};
|
||||
std::map<std::string, StringProperty> _stringProperties;
|
||||
|
||||
Context *getContext();
|
||||
protected:
|
||||
void generateVBOBuffers();
|
||||
bool _enable = true;
|
||||
bool _forceEnable = false;
|
||||
Quaramera::Mat4 _mvp_matrix;
|
||||
Vector2 _scaleResolution = Vector2(0.0, 0.0);
|
||||
bool _useScaleResolution = false;
|
||||
|
||||
public:
|
||||
void releaseVBOBuffers();
|
||||
private:
|
||||
static std::map<std::string, std::function<Filter*()>> _filterFactories;
|
||||
};
|
||||
|
||||
//#if defined(__ANDROID__) || defined(ANDROID)
|
||||
//#define REGISTER_FILTER_CLASS(className) \
|
||||
//class className##Registry { \
|
||||
// public: \
|
||||
// static Filter* newInstance() { \
|
||||
// return className::create(); \
|
||||
// } \
|
||||
// private: \
|
||||
// static const Filter::Registry _registry; \
|
||||
//}; \
|
||||
//const Filter::Registry className##Registry::_registry(#className, className##Registry::newInstance);
|
||||
//#elif defined(__APPLE__)
|
||||
#define REGISTER_FILTER_CLASS(className)
|
||||
//#endif
|
||||
|
||||
NS_GI_END
|
||||
|
||||
#endif /* Filter_hpp */
|
236
mediapipe/render/core/FilterGroup.cpp
Executable file
236
mediapipe/render/core/FilterGroup.cpp
Executable file
|
@ -0,0 +1,236 @@
|
|||
/*
|
||||
* GPUImage-x
|
||||
*
|
||||
* Copyright (C) 2017 Yijin Wang, Yiqian Wang
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <algorithm>
|
||||
#if defined(__APPLE__)
|
||||
#include "FilterGroup.hpp"
|
||||
#include "Context.hpp"
|
||||
#else
|
||||
#include "../include/GPUImage-x/filter/FilterGroup.hpp"
|
||||
#include "../include/GPUImage-x/Context.hpp"
|
||||
#endif
|
||||
|
||||
NS_GI_BEGIN
|
||||
|
||||
REGISTER_FILTER_CLASS(FilterGroup)
|
||||
|
||||
FilterGroup::FilterGroup(Context *context) : Filter(context)
|
||||
, _terminalFilter(0)
|
||||
{
|
||||
}
|
||||
|
||||
FilterGroup::~FilterGroup() {
|
||||
removeAllFilters();
|
||||
_terminalFilter = 0;
|
||||
}
|
||||
|
||||
FilterGroup* FilterGroup::create(Context *context) {
|
||||
FilterGroup* ret = new (std::nothrow) FilterGroup(context);
|
||||
if (ret && ret->init(context)) {
|
||||
//ret->autorelease();
|
||||
} else {
|
||||
delete ret;
|
||||
ret = 0;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
FilterGroup* FilterGroup::create(Context *context, std::vector<Filter*> filters) {
|
||||
FilterGroup* ret = new (std::nothrow) FilterGroup(context);
|
||||
if (ret && ret->init(context, filters)) {
|
||||
//ret->autorelease();
|
||||
} else {
|
||||
delete ret;
|
||||
ret = 0;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool FilterGroup::init(Context *context) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool FilterGroup::init(Context *context, std::vector<Filter*> filters) {
|
||||
if (filters.size() == 0) return true;
|
||||
_filters = filters;
|
||||
|
||||
for (auto const& filter : filters ) {
|
||||
Ref* ref = dynamic_cast<Ref*>(filter);
|
||||
if (ref) {
|
||||
ref->retain();
|
||||
}
|
||||
}
|
||||
|
||||
setTerminalFilter(_predictTerminalFilter(filters[filters.size() - 1]));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FilterGroup::hasFilter(const Filter* filter) const {
|
||||
std::vector<Filter*>::const_iterator it = std::find(_filters.begin(), _filters.end(), filter);
|
||||
if (it != _filters.end())
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
void FilterGroup::addFilter(Filter* filter) {
|
||||
if (hasFilter(filter)) return;
|
||||
|
||||
_filters.push_back(filter);
|
||||
|
||||
Ref* ref = dynamic_cast<Ref*>(filter);
|
||||
if (ref) {
|
||||
ref->retain();
|
||||
}
|
||||
|
||||
setTerminalFilter(_predictTerminalFilter(filter));
|
||||
}
|
||||
|
||||
void FilterGroup::removeFilter(Filter* filter) {
|
||||
std::vector<Filter*>::iterator itr = std::find(_filters.begin(), _filters.end(), filter);
|
||||
if (itr != _filters.end()) {
|
||||
Ref* ref = dynamic_cast<Ref*>(*itr);
|
||||
if (ref) {
|
||||
ref->release();
|
||||
}
|
||||
_filters.erase(itr);
|
||||
}
|
||||
}
|
||||
|
||||
void FilterGroup::removeAllFilters() {
|
||||
for (auto const& filter : _filters ) {
|
||||
Ref* ref = dynamic_cast<Ref*>(filter);
|
||||
if (ref) {
|
||||
ref->release();
|
||||
}
|
||||
}
|
||||
_filters.clear();
|
||||
}
|
||||
|
||||
Filter* FilterGroup::_predictTerminalFilter(Filter* filter) {
|
||||
if (filter->getTargets().size() == 0)
|
||||
return filter;
|
||||
else
|
||||
return _predictTerminalFilter(dynamic_cast<Filter*>(filter->getTargets().begin()->first));
|
||||
}
|
||||
|
||||
Source* FilterGroup::addTarget(Target* target) {
|
||||
if (_terminalFilter)
|
||||
return _terminalFilter->addTarget(target);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
Source* FilterGroup::addTarget(Target* target, int texIdx) {
|
||||
if (_terminalFilter)
|
||||
return _terminalFilter->addTarget(target, texIdx);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if defined(__APPLE__)
|
||||
Source* FilterGroup::addTarget(id<GPUImageTarget> target) {
|
||||
if (_terminalFilter)
|
||||
return _terminalFilter->addTarget(target);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
void FilterGroup::removeTarget(Target* target) {
|
||||
if (_terminalFilter)
|
||||
_terminalFilter->removeTarget(target);
|
||||
}
|
||||
|
||||
void FilterGroup::removeAllTargets() {
|
||||
if (_terminalFilter)
|
||||
_terminalFilter->removeAllTargets();
|
||||
}
|
||||
|
||||
bool FilterGroup::hasTarget(const Target* target) const {
|
||||
if (_terminalFilter)
|
||||
return _terminalFilter->hasTarget(target);
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
std::map<Target*, int>& FilterGroup::getTargets() {
|
||||
assert(_terminalFilter);
|
||||
return _terminalFilter->getTargets();
|
||||
}
|
||||
|
||||
bool FilterGroup::proceed(float frameTime, bool bUpdateTargets/* = true*/) {
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void FilterGroup::update(float frameTime) {
|
||||
proceed(frameTime);
|
||||
if (getContext()->isCapturingFrame && this == getContext()->captureUpToFilter) {
|
||||
getContext()->captureUpToFilter = _terminalFilter;
|
||||
}
|
||||
|
||||
for(auto& filter : _filters){
|
||||
if (filter->isPrepared()) {
|
||||
filter->update(frameTime);
|
||||
filter->unPrepear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FilterGroup::updateTargets(float frameTime) {
|
||||
if (_terminalFilter)
|
||||
_terminalFilter->updateTargets(frameTime);
|
||||
}
|
||||
|
||||
void FilterGroup::setFramebuffer(Framebuffer* fb, RotationMode outputRotation/* = RotationMode::NoRotation*/) {
|
||||
//if (_terminalFilter)
|
||||
// _terminalFilter->setFramebuffer(fb);
|
||||
}
|
||||
|
||||
Framebuffer* FilterGroup::getFramebuffer() const {
|
||||
//if (_terminalFilter)
|
||||
// return _terminalFilter->getFramebuffer();
|
||||
return 0;
|
||||
}
|
||||
|
||||
void FilterGroup::setInputFramebuffer(Framebuffer* framebuffer,
|
||||
RotationMode rotationMode/* = NoRotation*/,
|
||||
int texIdx/* = 0*/, bool ignoreForPrepared) {
|
||||
for (auto& filter : _filters) {
|
||||
filter->setInputFramebuffer(framebuffer, rotationMode, texIdx);
|
||||
}
|
||||
}
|
||||
|
||||
bool FilterGroup::isPrepared() const {
|
||||
// for (auto& filter : _filters) {
|
||||
// if (!filter->isPrepared())
|
||||
// return false;
|
||||
// }
|
||||
return true;
|
||||
}
|
||||
|
||||
void FilterGroup::unPrepear() {
|
||||
//for (auto& filter : _filters) {
|
||||
// filter->unPrepeared();
|
||||
//}
|
||||
}
|
||||
|
||||
NS_GI_END
|
86
mediapipe/render/core/FilterGroup.hpp
Executable file
86
mediapipe/render/core/FilterGroup.hpp
Executable file
|
@ -0,0 +1,86 @@
|
|||
/*
|
||||
* GPUImage-x
|
||||
*
|
||||
* Copyright (C) 2017 Yijin Wang, Yiqian Wang
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef FilterGroup_hpp
|
||||
#define FilterGroup_hpp
|
||||
|
||||
#if defined(__APPLE__)
|
||||
#include "GPUImageMacros.h"
|
||||
#include "Source.hpp"
|
||||
#include "Target.hpp"
|
||||
#else
|
||||
#include "GPUImage-x/GPUImageMacros.h"
|
||||
#include "GPUImage-x/source//Source.hpp"
|
||||
#include "GPUImage-x/target/Target.hpp"
|
||||
#endif
|
||||
#include <vector>
|
||||
#include "Filter.hpp"
|
||||
|
||||
NS_GI_BEGIN
|
||||
|
||||
class Context;
|
||||
class FilterGroup : public Filter {
|
||||
public:
|
||||
virtual ~FilterGroup();
|
||||
|
||||
static FilterGroup* create(Context *context);
|
||||
static FilterGroup* create(Context *context, std::vector<Filter*> filters);
|
||||
|
||||
bool init(Context *context);
|
||||
bool init(Context *context, std::vector<Filter*> filters);
|
||||
bool hasFilter(const Filter* filter) const;
|
||||
void addFilter(Filter* filter);
|
||||
void removeFilter(Filter* filter);
|
||||
void removeAllFilters();
|
||||
|
||||
// Manually specify the terminal filter, which is the final output filter of sequence
|
||||
// Most often, it's not necessary to specify the terminal filter manually,
|
||||
// as the terminal filter will be specified automatically.
|
||||
void setTerminalFilter(Filter* filter) { _terminalFilter = filter; }
|
||||
|
||||
virtual Source* addTarget(Target* target) override;
|
||||
virtual Source* addTarget(Target* target, int texIdx) override;
|
||||
#if defined(__APPLE__)
|
||||
virtual Source* addTarget(id<GPUImageTarget> target) override;
|
||||
#endif
|
||||
virtual void removeTarget(Target* target) override;
|
||||
virtual void removeAllTargets() override;
|
||||
virtual bool hasTarget(const Target* target) const override;
|
||||
virtual std::map<Target*, int>& getTargets() override;
|
||||
virtual bool proceed(float frameTime = 0, bool bUpdateTargets = true) override;
|
||||
virtual void update(float frameTime) override;
|
||||
virtual void updateTargets(float frameTime) override;
|
||||
virtual void setFramebuffer(Framebuffer* fb, RotationMode outputRotation = RotationMode::NoRotation) override;
|
||||
virtual Framebuffer* getFramebuffer() const override;
|
||||
virtual void setInputFramebuffer(Framebuffer* framebuffer, RotationMode rotationMode = NoRotation,
|
||||
int texIdx = 0, bool ignoreForPrepared = false) override;
|
||||
virtual bool isPrepared() const override;
|
||||
virtual void unPrepear() override;
|
||||
|
||||
public:
|
||||
std::vector<Filter*> _filters;
|
||||
Filter* _terminalFilter;
|
||||
|
||||
FilterGroup(Context *context);
|
||||
static Filter* _predictTerminalFilter(Filter* filter);
|
||||
|
||||
};
|
||||
|
||||
NS_GI_END
|
||||
|
||||
#endif /* FilterGroup_hpp */
|
242
mediapipe/render/core/Framebuffer.cpp
Executable file
242
mediapipe/render/core/Framebuffer.cpp
Executable file
|
@ -0,0 +1,242 @@
|
|||
/*
|
||||
* GPUImage-x
|
||||
*
|
||||
* Copyright (C) 2017 Yijin Wang, Yiqian Wang
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "Framebuffer.hpp"
|
||||
#include <assert.h>
|
||||
#include <algorithm>
|
||||
#include "GPUImageUtil.h"
|
||||
#include "Context.hpp"
|
||||
#include "GPUImageMacros.h"
|
||||
|
||||
|
||||
#define useCVPB defined(__APPLE__)
|
||||
|
||||
|
||||
namespace QImage {
|
||||
TextureAttributes Framebuffer::defaultTextureAttribures =
|
||||
{
|
||||
.minFilter = GL_LINEAR,
|
||||
.magFilter = GL_LINEAR,
|
||||
.wrapS = GL_CLAMP_TO_EDGE,
|
||||
.wrapT = GL_CLAMP_TO_EDGE,
|
||||
.internalFormat = GL_RGBA,
|
||||
.format = GL_RGBA,
|
||||
.type = GL_UNSIGNED_BYTE
|
||||
};
|
||||
|
||||
Framebuffer::Framebuffer() {
|
||||
|
||||
}
|
||||
|
||||
Framebuffer::Framebuffer(Context *context, int width, int height,
|
||||
const TextureAttributes textureAttributes, GLuint textureId)
|
||||
: _texture(-1), _hasFB(true), _framebuffer(-1), _context(context) {
|
||||
|
||||
|
||||
_width = width;
|
||||
_height = height;
|
||||
_textureAttributes = textureAttributes;
|
||||
_texture = textureId;
|
||||
_useExternalTexture = true;
|
||||
_generateFramebuffer(false);
|
||||
_context->_framebuffers.push_back(this);
|
||||
}
|
||||
|
||||
Framebuffer::Framebuffer(Context *context, int width, int height,
|
||||
bool onlyGenerateTexture/* = false*/,
|
||||
const TextureAttributes textureAttributes) : _texture(-1),
|
||||
_framebuffer(-1),
|
||||
_context(context) {
|
||||
_width = width;
|
||||
_height = height;
|
||||
_textureAttributes = textureAttributes;
|
||||
_hasFB = !onlyGenerateTexture;
|
||||
if (_hasFB) {
|
||||
_generateFramebuffer();
|
||||
} else {
|
||||
_generateTexture();
|
||||
}
|
||||
|
||||
_context->_framebuffers.push_back(this);
|
||||
}
|
||||
|
||||
Framebuffer::Framebuffer(Context *context, int width, int height, GLuint handle,
|
||||
const TextureAttributes textureAttributes) : _texture(handle),
|
||||
_framebuffer(-1),
|
||||
_context(context) {
|
||||
_width = width;
|
||||
_height = height;
|
||||
_textureAttributes = textureAttributes;
|
||||
}
|
||||
|
||||
Framebuffer::~Framebuffer() {
|
||||
if (isDealloc) {
|
||||
return;
|
||||
}
|
||||
QImage::Log("Framebuffer", "delete Framebuffer(%d,%d) ", _width, _height);
|
||||
bool bDeleteTex = (_texture != -1);
|
||||
bool bDeleteFB = (_framebuffer != -1);
|
||||
|
||||
for (auto const &framebuffer : _context->_framebuffers) {
|
||||
if (!framebuffer || framebuffer == this) continue;
|
||||
if (bDeleteTex) {
|
||||
if (_texture == framebuffer->getTexture()) {
|
||||
bDeleteTex = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (bDeleteFB) {
|
||||
if (framebuffer->hasFramebuffer() &&
|
||||
_framebuffer == framebuffer->getFramebuffer()) {
|
||||
bDeleteFB = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<Framebuffer*>::iterator itr = std::find(_context->_framebuffers.begin(), _context->_framebuffers.end(), this);
|
||||
if (itr != _context->_framebuffers.end()) {
|
||||
_context->_framebuffers.erase(itr);
|
||||
}
|
||||
|
||||
if (bDeleteTex && !_useExternalTexture) {
|
||||
CHECK_GL(glDeleteTextures(1, &_texture));
|
||||
_texture = -1;
|
||||
}
|
||||
if (bDeleteFB) {
|
||||
CHECK_GL(glDeleteFramebuffers(1, &_framebuffer));
|
||||
_framebuffer = -1;
|
||||
}
|
||||
isDealloc = true;
|
||||
|
||||
}
|
||||
|
||||
void Framebuffer::active() {
|
||||
CHECK_GL(glBindFramebuffer(GL_FRAMEBUFFER, _framebuffer));
|
||||
CHECK_GL(glViewport(0, 0, _width, _height));
|
||||
}
|
||||
|
||||
void Framebuffer::inactive() {
|
||||
CHECK_GL(glBindFramebuffer(GL_FRAMEBUFFER, 0));
|
||||
}
|
||||
|
||||
void Framebuffer::lock(std::string lockKey) {
|
||||
if (lockKey == "Unknow") {
|
||||
Log("Framebuffer LOCK", "未知锁 【hasCode :%s】", _hashCode.c_str());
|
||||
} else if (lockKey != _lockKey) {
|
||||
Log("Framebuffer LOCK", "Key变更:%s 【hasCode :%s】", lockKey.c_str(), _hashCode.c_str());
|
||||
}
|
||||
|
||||
_lockKey = lockKey;
|
||||
_framebufferRetainCount = 1;
|
||||
Log("Framebuffer LOCK", "lock retainCount == :%d lockKey:%s 【framebufferCode:%s】",
|
||||
_framebufferRetainCount,
|
||||
lockKey.c_str(), _hashCode.c_str());
|
||||
}
|
||||
|
||||
void Framebuffer::unlock(std::string lockKey) {
|
||||
if (_framebufferRetainCount > 0) {
|
||||
_framebufferRetainCount--;
|
||||
} else {
|
||||
// assert("过度释放 请检查"); 此处不要崩溃,引用计数管理Framebuffer不会导致过度释放。
|
||||
}
|
||||
|
||||
if (lockKey != _lockKey) {
|
||||
Log("Framebuffer UNLOCK", "可能是多次Lock后Unlock retainCount:%d lockKey:%s 【framebufferCode:%s】",
|
||||
_framebufferRetainCount,
|
||||
lockKey.c_str(),
|
||||
_hashCode.c_str());
|
||||
}
|
||||
|
||||
Log("Framebuffer UNLOCK", "unlock retainCount == :%d lockKey:%s 【framebufferCode:%s】"
|
||||
, _framebufferRetainCount,
|
||||
lockKey.c_str(),
|
||||
_hashCode.c_str());
|
||||
}
|
||||
|
||||
void Framebuffer::resetRetainCount() {
|
||||
_framebufferRetainCount = 0;
|
||||
}
|
||||
|
||||
void *Framebuffer::frameBufferGetBaseAddress() {
|
||||
//#if HARDWARE_BUFFER_ENABLE
|
||||
// return _hardwareBufferReadData;
|
||||
//#endif
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int Framebuffer::getBytesPerRow() {
|
||||
return _width * 4;
|
||||
}
|
||||
|
||||
//#if defined(__ANDROID__) || defined(ANDROID)
|
||||
// AHardwareBuffer_Desc& Framebuffer::getAHardwareBufferDesc(){
|
||||
// return _graphicBufDes;
|
||||
// }
|
||||
//#endif
|
||||
|
||||
void Framebuffer::_generateTexture() {
|
||||
CHECK_GL(glGenTextures(1, &_texture));
|
||||
|
||||
CHECK_GL(glBindTexture(GL_TEXTURE_2D, _texture));
|
||||
CHECK_GL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
|
||||
_textureAttributes.minFilter));
|
||||
CHECK_GL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
|
||||
_textureAttributes.magFilter));
|
||||
CHECK_GL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, _textureAttributes.wrapS));
|
||||
CHECK_GL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, _textureAttributes.wrapT));
|
||||
|
||||
// TODO: Handle mipmaps
|
||||
CHECK_GL(glBindTexture(GL_TEXTURE_2D, 0));
|
||||
}
|
||||
|
||||
|
||||
void Framebuffer::_generateFramebuffer(bool needGenerateTexture) {
|
||||
|
||||
CHECK_GL(glGenFramebuffers(1, &_framebuffer));
|
||||
CHECK_GL(glBindFramebuffer(GL_FRAMEBUFFER, _framebuffer));
|
||||
|
||||
if (needGenerateTexture) {
|
||||
_generateTexture();
|
||||
}
|
||||
|
||||
CHECK_GL(glBindTexture(GL_TEXTURE_2D, _texture));
|
||||
|
||||
if (needGenerateTexture) {
|
||||
|
||||
CHECK_GL(glTexImage2D(GL_TEXTURE_2D, 0, _textureAttributes.internalFormat, _width,
|
||||
_height, 0, _textureAttributes.format, _textureAttributes.type,
|
||||
0));
|
||||
}
|
||||
|
||||
CHECK_GL(glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
|
||||
_texture, 0));
|
||||
|
||||
|
||||
CHECK_GL(glBindTexture(GL_TEXTURE_2D, 0));
|
||||
CHECK_GL(glBindFramebuffer(GL_FRAMEBUFFER, 0));
|
||||
// QImage::Log("QuarameraGL", "_generateFramebuffer %d ", _framebuffer);
|
||||
}
|
||||
|
||||
Context *Framebuffer::getContext() {
|
||||
if (_context) {
|
||||
return _context;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
}
|
145
mediapipe/render/core/Framebuffer.hpp
Executable file
145
mediapipe/render/core/Framebuffer.hpp
Executable file
|
@ -0,0 +1,145 @@
|
|||
/*
|
||||
* GPUImage-x
|
||||
*
|
||||
* Copyright (C) 2017 Yijin Wang, Yiqian Wang
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef Framebuffer_hpp
|
||||
#define Framebuffer_hpp
|
||||
|
||||
#include "GPUImageMacros.h"
|
||||
#if defined(__APPLE__)
|
||||
#import <OpenGLES/ES3/gl.h>
|
||||
#import <OpenGLES/ES3/glext.h>
|
||||
#import <CoreVideo/CoreVideo.h>
|
||||
#elif defined(__ANDROID__) || defined(ANDROID)
|
||||
#if defined(__ANDROID__) || defined(ANDROID)
|
||||
// for EGL calls
|
||||
#define EGL_EGLEXT_PROTOTYPES
|
||||
#include "EGL/egl.h"
|
||||
#include "EGL/eglext.h"
|
||||
#include "GLES/gl.h"
|
||||
#define GL_GLEXT_PROTOTYPES
|
||||
#include "GLES/glext.h"
|
||||
#include "android/hardware_buffer.h"
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
#include <GLES3/gl3.h>
|
||||
#include <GLES3/gl3ext.h>
|
||||
#endif
|
||||
#include <vector>
|
||||
#include "Ref.hpp"
|
||||
|
||||
|
||||
NS_GI_BEGIN
|
||||
|
||||
typedef struct {
|
||||
GLenum minFilter;
|
||||
GLenum magFilter;
|
||||
GLenum wrapS;
|
||||
GLenum wrapT;
|
||||
GLenum internalFormat;
|
||||
GLenum format;
|
||||
GLenum type;
|
||||
} TextureAttributes;
|
||||
|
||||
class Context;
|
||||
class Framebuffer {
|
||||
public:
|
||||
|
||||
/// 这里将外部的纹理传入并创建FBO,无需_generateTexture
|
||||
/// @param width 纹理宽
|
||||
/// @param height 纹理高
|
||||
Framebuffer(Context *context, int width, int height,
|
||||
const TextureAttributes textureAttributes = defaultTextureAttribures,
|
||||
GLuint textureId = -1);
|
||||
Framebuffer(Context *context, int width, int height, bool onlyGenerateTexture = false,
|
||||
const TextureAttributes textureAttributes = defaultTextureAttribures);
|
||||
Framebuffer(Context *context, int width, int height, GLuint handle,
|
||||
const TextureAttributes textureAttributes = defaultTextureAttribures);
|
||||
|
||||
Framebuffer();
|
||||
|
||||
virtual ~Framebuffer();
|
||||
|
||||
GLuint getTexture() const {
|
||||
return _texture;
|
||||
}
|
||||
|
||||
void setTexture(GLuint textureId) {
|
||||
_texture = textureId;
|
||||
}
|
||||
|
||||
GLuint getFramebuffer() const {
|
||||
return _framebuffer;
|
||||
}
|
||||
|
||||
int getWidth() const { return _width; }
|
||||
int getHeight() const { return _height; }
|
||||
const TextureAttributes& getTextureAttributes() const { return _textureAttributes; };
|
||||
bool hasFramebuffer() { return _hasFB; };
|
||||
|
||||
void active();
|
||||
void inactive();
|
||||
|
||||
virtual void lockAddress() {};
|
||||
virtual void unlockAddress() {};
|
||||
|
||||
virtual void lock(std::string lockKey = "Unknow");
|
||||
virtual void unlock(std::string lockKey = "Unknow");
|
||||
virtual void resetRetainCount();
|
||||
|
||||
int framebufferRetainCount() {
|
||||
return _framebufferRetainCount;
|
||||
}
|
||||
|
||||
virtual void* frameBufferGetBaseAddress();
|
||||
virtual int getBytesPerRow();
|
||||
|
||||
|
||||
virtual void _generateTexture();
|
||||
virtual void _generateFramebuffer(bool needGenerateTexture = true);
|
||||
|
||||
Context *getContext();
|
||||
|
||||
GLchar *renderTargetData;
|
||||
|
||||
static TextureAttributes defaultTextureAttribures;
|
||||
|
||||
int _width, _height;
|
||||
TextureAttributes _textureAttributes;
|
||||
bool _hasFB;
|
||||
bool useTextureCache = false;
|
||||
|
||||
GLuint _texture;
|
||||
GLuint _framebuffer = -1;
|
||||
Context *_context;
|
||||
bool isDealloc = false;
|
||||
int _framebufferRetainCount = 0;
|
||||
std::string _lockKey = "Unknow";
|
||||
std::string _hashCode = "";
|
||||
std::string _typeCode = "";
|
||||
bool _useExternalTexture = false;
|
||||
|
||||
};
|
||||
|
||||
|
||||
NS_GI_END
|
||||
|
||||
#endif /* Framebuffer_hpp */
|
211
mediapipe/render/core/FramebufferCache.cpp
Executable file
211
mediapipe/render/core/FramebufferCache.cpp
Executable file
|
@ -0,0 +1,211 @@
|
|||
/*
|
||||
* GPUImage-x
|
||||
*
|
||||
* Copyright (C) 2017 Yijin Wang, Yiqian Wang
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "FramebufferCache.hpp"
|
||||
#include "GPUImageUtil.h"
|
||||
|
||||
#if defined(__APPLE__)
|
||||
#include "CVFramebuffer.hpp"
|
||||
#endif
|
||||
|
||||
NS_GI_BEGIN
|
||||
|
||||
FramebufferCache::FramebufferCache(Context *context)
|
||||
: _context(context) {
|
||||
}
|
||||
|
||||
FramebufferCache::~FramebufferCache() {
|
||||
purge();
|
||||
}
|
||||
|
||||
Framebuffer* FramebufferCache::fetchFramebufferUseTextureId(Context *context,
|
||||
int width,
|
||||
int height,
|
||||
int textureId,
|
||||
bool onlyTexture,
|
||||
const TextureAttributes textureAttributes,
|
||||
bool useTextureCache) {
|
||||
Framebuffer* framebufferFromCache = 0;
|
||||
if (useTextureCache) {
|
||||
#if defined(__APPLE__)
|
||||
//分平台创建 TextureCache
|
||||
framebufferFromCache = new CVFramebuffer(context,
|
||||
width,
|
||||
height,
|
||||
textureAttributes,
|
||||
textureId);
|
||||
#elif defined(__ANDROID__) || defined(ANDROID)
|
||||
assert("Android HardwareBuffer not support reuse now");
|
||||
#endif
|
||||
} else {
|
||||
framebufferFromCache = new Framebuffer(context,
|
||||
width,
|
||||
height,
|
||||
textureAttributes,
|
||||
textureId);
|
||||
}
|
||||
return framebufferFromCache;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
Framebuffer* FramebufferCache::fetchFramebuffer(Context *context,
|
||||
int width,
|
||||
int height,
|
||||
bool onlyTexture/* = false*/,
|
||||
const TextureAttributes textureAttributes/* = defaultTextureAttribure*/,
|
||||
bool useTextureCache) {
|
||||
|
||||
Framebuffer* framebufferFromCache = 0;
|
||||
std::string lookupHash = _getHash(width, height, onlyTexture, textureAttributes, useTextureCache);
|
||||
|
||||
auto matchFramebuffersHashCode = _framebufferTypeMap[lookupHash];
|
||||
|
||||
if (matchFramebuffersHashCode.size() > 0) {
|
||||
for (const auto &framebufferHashCodeKey : matchFramebuffersHashCode) {
|
||||
auto *framebuffer = _framebuffers[framebufferHashCodeKey.first];
|
||||
if (framebuffer == NULL) {
|
||||
framebuffer = 0;
|
||||
break;
|
||||
}
|
||||
if (framebuffer->getWidth() != width || framebuffer->getHeight() != height) {
|
||||
forceCleanFramebuffer(framebuffer);
|
||||
framebuffer = 0;
|
||||
} else if (framebuffer->framebufferRetainCount() == 0 && !framebuffer->isDealloc) {
|
||||
Log("Framebuffer 【命中缓存】", "hashcode:%s count:%d",
|
||||
framebufferHashCodeKey.first.c_str(),
|
||||
framebuffer->framebufferRetainCount());
|
||||
return framebuffer;
|
||||
}
|
||||
}
|
||||
}
|
||||
Log("Framebuffer 所有缓存【未命中】", "hashcode:%s count:%d",
|
||||
lookupHash.c_str(),
|
||||
matchFramebuffersHashCode.size());
|
||||
// 如果都被占用了 或者找不到对应的Framebuffer 则需要创建一个新的
|
||||
|
||||
if (useTextureCache) {
|
||||
#if defined(__APPLE__)
|
||||
//分平台创建 TextureCache
|
||||
framebufferFromCache = new CVFramebuffer(context,
|
||||
width,
|
||||
height,
|
||||
onlyTexture,
|
||||
textureAttributes);
|
||||
#elif defined(__ANDROID__) || defined(ANDROID)
|
||||
assert("Android HardwareBuffer not support reuse now");
|
||||
#endif
|
||||
} else {
|
||||
framebufferFromCache = new Framebuffer(context,
|
||||
width,
|
||||
height,
|
||||
onlyTexture,
|
||||
textureAttributes);
|
||||
}
|
||||
|
||||
std::string framebufferHash = str_format("%s-%ld", lookupHash.c_str(),
|
||||
framebufferFromCache->getTexture());
|
||||
Log("Framebuffer 创建新的Framebuffer", "hashcode:%s numberOfMatchingFramebuffers:%d",
|
||||
framebufferHash.c_str(),
|
||||
matchFramebuffersHashCode.size());
|
||||
framebufferFromCache->_hashCode = framebufferHash;
|
||||
framebufferFromCache->_typeCode = lookupHash;
|
||||
_framebuffers[framebufferHash] = framebufferFromCache;
|
||||
_framebufferTypeMap[lookupHash][framebufferHash] = 0;
|
||||
return framebufferFromCache;
|
||||
}
|
||||
|
||||
void FramebufferCache::forceCleanFramebuffer(Framebuffer *framebuffer) {
|
||||
if (_framebuffers.find(framebuffer->_hashCode) != _framebuffers.end()) {
|
||||
_framebuffers.erase(framebuffer->_hashCode);
|
||||
}
|
||||
|
||||
if (_framebufferTypeMap[framebuffer->_typeCode].find(framebuffer->_hashCode) !=
|
||||
_framebufferTypeMap[framebuffer->_typeCode].end()) {
|
||||
_framebufferTypeMap[framebuffer->_typeCode].erase(framebuffer->_hashCode);
|
||||
}
|
||||
|
||||
delete framebuffer;
|
||||
framebuffer = 0;
|
||||
}
|
||||
|
||||
void FramebufferCache::returnFramebuffer(Framebuffer* framebuffer, int maxCacheSize) {
|
||||
if (framebuffer->framebufferRetainCount() == 0) {
|
||||
Log("准备回收 retainCount == 0 的Framebuffer", "cacheHash:%s cacheReferenceCount:%d",
|
||||
framebuffer->_hashCode.c_str(),
|
||||
framebuffer->framebufferRetainCount());
|
||||
if (_framebuffers.find(framebuffer->_hashCode) != _framebuffers.end()) {
|
||||
|
||||
if (_framebufferTypeMap[framebuffer->_typeCode].size() > maxCacheSize) {
|
||||
_framebuffers.erase(framebuffer->_hashCode);
|
||||
if (_framebufferTypeMap[framebuffer->_typeCode].find(framebuffer->_hashCode) !=
|
||||
_framebufferTypeMap[framebuffer->_typeCode].end()) {
|
||||
_framebufferTypeMap[framebuffer->_typeCode].erase(framebuffer->_hashCode);
|
||||
}
|
||||
delete framebuffer;
|
||||
framebuffer = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::string FramebufferCache::_getHash(int width,
|
||||
int height,
|
||||
bool onlyTexture,
|
||||
const TextureAttributes textureAttributes,
|
||||
bool useTextureCache) const {
|
||||
const char *formatStr = "";
|
||||
if (onlyTexture) {
|
||||
formatStr = "%.1dx%.1d-%d:%d:%d:%d:%d:%d:%d-NOFB";
|
||||
} else {
|
||||
formatStr = "%.1dx%.1d-%d:%d:%d:%d:%d:%d:%d";
|
||||
}
|
||||
|
||||
return str_format(formatStr,
|
||||
width, height,
|
||||
textureAttributes.minFilter, textureAttributes.magFilter,
|
||||
textureAttributes.wrapS, textureAttributes.wrapT,
|
||||
textureAttributes.internalFormat, textureAttributes.format,
|
||||
textureAttributes.type);
|
||||
}
|
||||
|
||||
Framebuffer* FramebufferCache::_getFramebufferByHash(const std::string& hash) {
|
||||
return _framebuffers[hash];
|
||||
}
|
||||
|
||||
void FramebufferCache::purge(bool force) {
|
||||
if (_framebuffers.size() == 0) {
|
||||
return;
|
||||
}
|
||||
for(auto &kvp : _framebuffers) {
|
||||
if (kvp.second && !kvp.second->isDealloc) {
|
||||
delete kvp.second;
|
||||
kvp.second = nullptr;
|
||||
}
|
||||
}
|
||||
_framebuffers.clear();
|
||||
_framebufferTypeMap.clear();
|
||||
}
|
||||
|
||||
void FramebufferCache::clearCache() {
|
||||
_framebuffers.clear();
|
||||
_framebufferTypeMap.clear();
|
||||
}
|
||||
|
||||
NS_GI_END
|
99
mediapipe/render/core/FramebufferCache.hpp
Executable file
99
mediapipe/render/core/FramebufferCache.hpp
Executable file
|
@ -0,0 +1,99 @@
|
|||
/*
|
||||
* GPUImage-x
|
||||
*
|
||||
* Copyright (C) 2017 Yijin Wang, Yiqian Wang
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef FramebufferCache_hpp
|
||||
#define FramebufferCache_hpp
|
||||
|
||||
#include "GPUImageMacros.h"
|
||||
#include "Framebuffer.hpp"
|
||||
#include <string>
|
||||
#include <map>
|
||||
|
||||
#if defined(__APPLE__)
|
||||
#define useCVFramebuffer true //默认关闭 调试的时候再打开,因为CVPixelBuffer 回收较慢会阻塞CPU
|
||||
#else
|
||||
#define useCVFramebuffer false
|
||||
#endif
|
||||
namespace QImage {
|
||||
|
||||
class Context;
|
||||
class FramebufferCache {
|
||||
public:
|
||||
FramebufferCache(Context *context);
|
||||
~FramebufferCache();
|
||||
Framebuffer* fetchFramebuffer(Context *context,
|
||||
int width,
|
||||
int height,
|
||||
bool onlyTexture = false,
|
||||
const TextureAttributes textureAttributes =
|
||||
Framebuffer::defaultTextureAttribures,
|
||||
#if defined(__APPLE__)
|
||||
bool useTextureCache = useCVFramebuffer);
|
||||
#else
|
||||
bool useTextureCache = false);
|
||||
#endif
|
||||
|
||||
|
||||
/// 通过外部传入的TextureId生成FBO
|
||||
/// @param width 宽
|
||||
/// @param height 高
|
||||
/// @param textureId textureId
|
||||
Framebuffer* fetchFramebufferUseTextureId(Context *context,
|
||||
int width,
|
||||
int height,
|
||||
int textureId,
|
||||
bool onlyTexture = false,
|
||||
const TextureAttributes textureAttributes = Framebuffer::defaultTextureAttribures,
|
||||
#if defined(__APPLE__)
|
||||
bool useTextureCache = useCVFramebuffer);
|
||||
#else
|
||||
bool useTextureCache = false);
|
||||
#endif
|
||||
|
||||
|
||||
void returnFramebuffer(Framebuffer* framebuffer, int maxCacheSize = 1);
|
||||
void forceCleanFramebuffer(Framebuffer* framebuffer);
|
||||
|
||||
void purge(bool force = false);
|
||||
void clearCache();
|
||||
|
||||
std::map<std::string, Framebuffer*> allCaches() {
|
||||
return _framebuffers;
|
||||
}
|
||||
|
||||
std::map<std::string, std::map<std::string, int>> allCachesTypeMap() {
|
||||
return _framebufferTypeMap;
|
||||
}
|
||||
|
||||
private:
|
||||
std::string _getHash(int width,
|
||||
int height,
|
||||
bool onlyTexture,
|
||||
const TextureAttributes textureAttributes,
|
||||
bool useTextureCache) const;
|
||||
Framebuffer* _getFramebufferByHash(const std::string& hash);
|
||||
|
||||
std::map<std::string, Framebuffer*> _framebuffers;
|
||||
std::map<std::string, std::map<std::string, int>> _framebufferTypeMap;
|
||||
Context *_context;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif /* FramebufferCache_hpp */
|
290
mediapipe/render/core/GLProgram.cpp
Executable file
290
mediapipe/render/core/GLProgram.cpp
Executable file
|
@ -0,0 +1,290 @@
|
|||
/*
|
||||
* GPUImage-x
|
||||
*
|
||||
* Copyright (C) 2017 Yijin Wang, Yiqian Wang
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <algorithm>
|
||||
#include "GLProgram.hpp"
|
||||
#include "Context.hpp"
|
||||
#include "GPUImageUtil.h"
|
||||
|
||||
namespace QImage {
|
||||
|
||||
//std::vector<GLProgram*> GLProgram::_context->_programs;
|
||||
|
||||
GLProgram::GLProgram(Context *context) : _program(-1), _context(context) {
|
||||
_context->_programs.push_back(this);
|
||||
}
|
||||
|
||||
GLProgram::~GLProgram() {
|
||||
if (nullptr != _context && _context->_programs.size() > 0) { //context 可能为空
|
||||
std::vector<GLProgram *>::iterator itr = std::find(_context->_programs.begin(), _context->_programs.end(), this);
|
||||
if (itr != _context->_programs.end()) {
|
||||
_context->_programs.erase(itr);
|
||||
}
|
||||
|
||||
bool bDeleteProgram = (_program != -1);
|
||||
|
||||
for (auto const &program : _context->_programs) {
|
||||
if (bDeleteProgram) {
|
||||
if (_program == program->getID()) {
|
||||
bDeleteProgram = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (bDeleteProgram) {
|
||||
glDeleteProgram(_program);
|
||||
_program = -1;
|
||||
}
|
||||
} else {
|
||||
glDeleteProgram(_program);
|
||||
_program = -1;
|
||||
}
|
||||
}
|
||||
|
||||
GLProgram *GLProgram::createByShaderString(Context *context, const std::string &vertexShaderSource, const std::string &fragmentShaderSource) {
|
||||
GLProgram *ret = new(std::nothrow) GLProgram(context);
|
||||
if (ret) {
|
||||
if (!ret->_initWithShaderString(vertexShaderSource, fragmentShaderSource)) {
|
||||
delete ret;
|
||||
ret = 0;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
GLuint loadShader(GLenum shaderType, const char *pSource) {
|
||||
GLuint shader = 0;
|
||||
shader = CHECK_GL(glCreateShader(shaderType));
|
||||
if (shader) {
|
||||
CHECK_GL(glShaderSource(shader, 1, &pSource, nullptr));
|
||||
CHECK_GL(glCompileShader(shader));
|
||||
GLint compiled = 0;
|
||||
CHECK_GL(glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled));
|
||||
if (!compiled) {
|
||||
GLint infoLen = 0;
|
||||
CHECK_GL(glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen));
|
||||
if (infoLen) {
|
||||
char *buf = (char *) malloc((size_t) infoLen);
|
||||
if (buf) {
|
||||
CHECK_GL(glGetShaderInfoLog(shader, infoLen, nullptr, buf));
|
||||
std::string shaderTypeStr("unknown");
|
||||
if (shaderType == GL_FRAGMENT_SHADER) {
|
||||
shaderTypeStr = std::string("GL_FRAGMENT_SHADER");
|
||||
} else if (shaderType == GL_VERTEX_SHADER) {
|
||||
shaderTypeStr = std::string("GL_VERTEX_SHADER");
|
||||
}
|
||||
QImage::LogE("GPUImage-x", "LoadShader Could not compile shader type : %s \n because of %s", shaderTypeStr.c_str(), buf);
|
||||
QImage::Log("GPUImage-x", "\n%s\n", pSource);
|
||||
free(buf);
|
||||
}
|
||||
CHECK_GL(glDeleteShader(shader));
|
||||
shader = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
return shader;
|
||||
}
|
||||
|
||||
|
||||
bool GLProgram::_initWithShaderString(const std::string &vertexShaderSource, const std::string &fragmentShaderSource) {
|
||||
|
||||
if (_program != -1) {
|
||||
CHECK_GL(glDeleteProgram(_program));
|
||||
_program = -1;
|
||||
}
|
||||
CHECK_GL(_program = glCreateProgram());
|
||||
|
||||
GLuint vertShader = loadShader(GL_VERTEX_SHADER, vertexShaderSource.c_str());
|
||||
|
||||
GLuint fragShader = loadShader(GL_FRAGMENT_SHADER, fragmentShaderSource.c_str());
|
||||
|
||||
CHECK_GL(glAttachShader(_program, vertShader));
|
||||
CHECK_GL(glAttachShader(_program, fragShader));
|
||||
|
||||
CHECK_GL(glLinkProgram(_program));
|
||||
|
||||
GLint linkStatus = GL_FALSE;
|
||||
CHECK_GL(glGetProgramiv(_program, GL_LINK_STATUS, &linkStatus));
|
||||
|
||||
CHECK_GL(glDeleteShader(vertShader));
|
||||
CHECK_GL(glDeleteShader(fragShader));
|
||||
|
||||
if (!linkStatus) {
|
||||
GLint bufLength = 0;
|
||||
CHECK_GL(glGetProgramiv(_program, GL_INFO_LOG_LENGTH, &bufLength));
|
||||
if (bufLength) {
|
||||
char *buf = (char *) malloc((size_t) bufLength);
|
||||
if (buf) {
|
||||
CHECK_GL(glGetProgramInfoLog(_program, bufLength, NULL, buf));
|
||||
QImage::LogE("GPUImage-x", "compile gl program error %s", buf);
|
||||
free(buf);
|
||||
}
|
||||
}
|
||||
CHECK_GL(glDeleteProgram(_program));
|
||||
_program = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void GLProgram::use() {
|
||||
CHECK_GL(glUseProgram(_program));
|
||||
}
|
||||
|
||||
GLuint GLProgram::getAttribLocation(const std::string &attribute) {
|
||||
return glGetAttribLocation(_program, attribute.c_str());
|
||||
}
|
||||
|
||||
GLuint GLProgram::getUniformLocation(const std::string &uniformName) {
|
||||
return glGetUniformLocation(_program, uniformName.c_str());
|
||||
}
|
||||
|
||||
|
||||
void GLProgram::setUniformValue(const std::string &uniformName, int value) {
|
||||
getContext()->setActiveShaderProgram(this);
|
||||
GLuint location = getUniformLocation(uniformName);
|
||||
if (location != -1) {
|
||||
setUniformValue(location, value);
|
||||
}
|
||||
}
|
||||
|
||||
void GLProgram::setUniformValue(const std::string &uniformName, int count, int *value, int valueSize/*=1*/) {
|
||||
getContext()->setActiveShaderProgram(this);
|
||||
GLuint location = getUniformLocation(uniformName);
|
||||
if (location != -1) {
|
||||
setUniformValue(location, count, value, valueSize);
|
||||
}
|
||||
}
|
||||
|
||||
void GLProgram::setUniformValue(const std::string &uniformName, float value) {
|
||||
getContext()->setActiveShaderProgram(this);
|
||||
GLuint location = getUniformLocation(uniformName);
|
||||
if (location != -1) {
|
||||
setUniformValue(location, value);
|
||||
}
|
||||
}
|
||||
|
||||
void GLProgram::setUniformValue(const std::string &uniformName, int count, float *value, int valueSize/*=1*/) {
|
||||
getContext()->setActiveShaderProgram(this);
|
||||
GLuint location = getUniformLocation(uniformName);
|
||||
if (location != -1) {
|
||||
setUniformValue(location, count, value, valueSize);
|
||||
}
|
||||
}
|
||||
|
||||
void GLProgram::setUniformValue(const std::string &uniformName, Quaramera::Mat4 value) {
|
||||
getContext()->setActiveShaderProgram(this);
|
||||
GLuint location = getUniformLocation(uniformName);
|
||||
if (location != -1) {
|
||||
setUniformValue(location, value);
|
||||
}
|
||||
}
|
||||
|
||||
void GLProgram::setUniformValue(const std::string &uniformName, Vector2 value) {
|
||||
getContext()->setActiveShaderProgram(this);
|
||||
GLuint location = getUniformLocation(uniformName);
|
||||
if (location != -1) {
|
||||
setUniformValue(location, value);
|
||||
}
|
||||
}
|
||||
|
||||
void GLProgram::setUniformValue(const std::string &uniformName, Vector4 value) {
|
||||
getContext()->setActiveShaderProgram(this);
|
||||
GLuint location = getUniformLocation(uniformName);
|
||||
if (location != -1) {
|
||||
setUniformValue(location, value);
|
||||
}
|
||||
}
|
||||
|
||||
void GLProgram::setUniformValue(const std::string &uniformName, Matrix3 value) {
|
||||
getContext()->setActiveShaderProgram(this);
|
||||
GLuint location = getUniformLocation(uniformName);
|
||||
if (location != -1) {
|
||||
setUniformValue(location, value);
|
||||
}
|
||||
}
|
||||
|
||||
void GLProgram::setUniformValue(int uniformLocation, int value) {
|
||||
getContext()->setActiveShaderProgram(this);
|
||||
CHECK_GL(glUniform1i(uniformLocation, value));
|
||||
}
|
||||
|
||||
void GLProgram::setUniformValue(int uniformLocation, int count, int *value, int valueSize /*=1*/) {
|
||||
getContext()->setActiveShaderProgram(this);
|
||||
if (valueSize == 1) {
|
||||
CHECK_GL(glUniform1iv(uniformLocation, count, value));
|
||||
} else if (valueSize == 2) {
|
||||
CHECK_GL(glUniform2iv(uniformLocation, count, value));
|
||||
} else if (valueSize == 3) {
|
||||
CHECK_GL(glUniform3iv(uniformLocation, count, value));
|
||||
} else if (valueSize == 4) {
|
||||
CHECK_GL(glUniform4iv(uniformLocation, count, value));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void GLProgram::setUniformValue(int uniformLocation, float value) {
|
||||
getContext()->setActiveShaderProgram(this);
|
||||
CHECK_GL(glUniform1f(uniformLocation, value));
|
||||
}
|
||||
|
||||
void GLProgram::setUniformValue(int uniformLocation, int count, float *value, int valueSize/*=1*/) {
|
||||
getContext()->setActiveShaderProgram(this);
|
||||
if (valueSize == 1) {
|
||||
CHECK_GL(glUniform1fv(uniformLocation, count, value));
|
||||
} else if (valueSize == 2) {
|
||||
CHECK_GL(glUniform2fv(uniformLocation, count, value));
|
||||
} else if (valueSize == 3) {
|
||||
CHECK_GL(glUniform3fv(uniformLocation, count, value));
|
||||
} else if (valueSize == 4) {
|
||||
CHECK_GL(glUniform4fv(uniformLocation, count, value));
|
||||
}
|
||||
}
|
||||
|
||||
void GLProgram::setUniformValue(int uniformLocation, Quaramera::Mat4 value) {
|
||||
getContext()->setActiveShaderProgram(this);
|
||||
CHECK_GL(glUniformMatrix4fv(uniformLocation, 1, GL_FALSE, (GLfloat *) &value));
|
||||
}
|
||||
|
||||
void GLProgram::setUniformValue(int uniformLocation, Vector2 value) {
|
||||
getContext()->setActiveShaderProgram(this);
|
||||
CHECK_GL(glUniform2f(uniformLocation, value.x, value.y));
|
||||
}
|
||||
|
||||
void GLProgram::setUniformValue(int uniformLocation, Vector4 value) {
|
||||
getContext()->setActiveShaderProgram(this);
|
||||
CHECK_GL(glUniform4f(uniformLocation, value.x, value.y, value.z, value.w));
|
||||
}
|
||||
|
||||
void GLProgram::setUniformValue(int uniformLocation, Matrix3 value) {
|
||||
getContext()->setActiveShaderProgram(this);
|
||||
CHECK_GL(glUniformMatrix3fv(uniformLocation, 1, GL_FALSE, (GLfloat *) &value));
|
||||
}
|
||||
|
||||
Context *GLProgram::getContext() {
|
||||
if (_context) {
|
||||
return _context;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
}
|
89
mediapipe/render/core/GLProgram.hpp
Executable file
89
mediapipe/render/core/GLProgram.hpp
Executable file
|
@ -0,0 +1,89 @@
|
|||
/*
|
||||
* GPUImage-x
|
||||
*
|
||||
* Copyright (C) 2017 Yijin Wang, Yiqian Wang
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef Shader_hpp
|
||||
#define Shader_hpp
|
||||
|
||||
#include "GPUImageMacros.h"
|
||||
#include "string"
|
||||
#if defined(__ANDROID__) || defined(ANDROID)
|
||||
#include <GLES3/gl3.h>
|
||||
#include <GLES3/gl3ext.h>
|
||||
#elif defined(__APPLE__)
|
||||
#import <OpenGLES/ES3/gl.h>
|
||||
#import <OpenGLES/ES3/glext.h>
|
||||
|
||||
#endif
|
||||
|
||||
#include "math_utils.hpp"
|
||||
#include "math.hpp"
|
||||
#include <vector>
|
||||
|
||||
|
||||
NS_GI_BEGIN
|
||||
class Context;
|
||||
class GLProgram{
|
||||
public:
|
||||
GLProgram(Context *context);
|
||||
~GLProgram();
|
||||
|
||||
static GLProgram* createByShaderString(Context *context, const std::string& vertexShaderSource, const std::string& fragmentShaderSource);
|
||||
void use();
|
||||
GLuint getID() const { return _program; }
|
||||
|
||||
bool isValid() {
|
||||
if (glIsProgram(_program) != GL_TRUE ) {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
GLuint getAttribLocation(const std::string& attribute);
|
||||
GLuint getUniformLocation(const std::string& uniformName);
|
||||
|
||||
void setUniformValue(const std::string& uniformName, int value);
|
||||
void setUniformValue(const std::string& uniformName, int count, int* value, int valueSize = 1);
|
||||
void setUniformValue(const std::string& uniformName, float value);
|
||||
void setUniformValue(const std::string& uniformName, int count, float* value, int valueSize = 1);
|
||||
void setUniformValue(const std::string& uniformName, Vector2 value);
|
||||
void setUniformValue(const std::string& uniformName, Vector4 value);
|
||||
void setUniformValue(const std::string& uniformName, Matrix3 value);
|
||||
void setUniformValue(const std::string& uniformName, Quaramera::Mat4 value);
|
||||
|
||||
void setUniformValue(int uniformLocation, int value);
|
||||
void setUniformValue(int uniformLocation, int count, int* value, int valueSize = 1);
|
||||
void setUniformValue(int uniformLocation, float value);
|
||||
void setUniformValue(int uniformLocation, int count, float* value, int valueSize = 1);
|
||||
void setUniformValue(int uniformLocation, Vector2 value);
|
||||
void setUniformValue(int uniformLocation, Vector4 value);
|
||||
void setUniformValue(int uniformLocation, Matrix3 value);
|
||||
void setUniformValue(int uniformLocation, Quaramera::Mat4 value);
|
||||
|
||||
Context *getContext();
|
||||
private:
|
||||
|
||||
GLuint _program;
|
||||
bool _initWithShaderString(const std::string& vertexShaderSource, const std::string& fragmentShaderSource);
|
||||
Context *_context = 0;
|
||||
};
|
||||
|
||||
|
||||
NS_GI_END
|
||||
|
||||
#endif /* GLProgram_hpp */
|
45
mediapipe/render/core/GPUImage-x.h
Executable file
45
mediapipe/render/core/GPUImage-x.h
Executable file
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* GPUImage-x
|
||||
*
|
||||
* Copyright (C) 2017 Yijin Wang, Yiqian Wang
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef GPUImage_x_h
|
||||
#define GPUImage_x_h
|
||||
|
||||
|
||||
#include "Context.hpp"
|
||||
#include "Framebuffer.hpp"
|
||||
#include "FramebufferCache.hpp"
|
||||
#include "GLProgram.hpp"
|
||||
#include "GPUImageMacros.h"
|
||||
#include "math.hpp"
|
||||
#include "Ref.hpp"
|
||||
#include "util.h"
|
||||
#include "Source.hpp"
|
||||
#include "SourceImage.hpp"
|
||||
#include "SourceCamera.hpp"
|
||||
#include "Target.hpp"
|
||||
#include "TargetView.hpp"
|
||||
#if defined(__APPLE__)
|
||||
#include "IOSTarget.hpp"
|
||||
#include "GPUImageTarget.h"
|
||||
#endif
|
||||
|
||||
#include "Filter.hpp"
|
||||
#include "FilterGroup.hpp"
|
||||
|
||||
|
||||
#endif /* GPUImage_x_h */
|
75
mediapipe/render/core/GPUImageMacros.h
Executable file
75
mediapipe/render/core/GPUImageMacros.h
Executable file
|
@ -0,0 +1,75 @@
|
|||
/*
|
||||
* GPUImage-x
|
||||
*
|
||||
* Copyright (C) 2017 Yijin Wang, Yiqian Wang
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef GPUImageMacros_h
|
||||
#define GPUImageMacros_h
|
||||
|
||||
|
||||
#define NS_GI_BEGIN namespace QImage {
|
||||
#define NS_GI_END }
|
||||
#define USING_NS_GI using namespace QImage;
|
||||
|
||||
|
||||
#define STRINGIZE(x) #x
|
||||
#define SHADER_STRING(text) STRINGIZE(text)
|
||||
|
||||
#define PI 3.14159265358979323846264338327950288
|
||||
|
||||
#if defined(__ANDROID__) || defined(ANDROID)
|
||||
#define ENABLE_GL_CHECK true
|
||||
#else
|
||||
#define ENABLE_GL_CHECK false
|
||||
#endif
|
||||
#ifndef PLATFORM_WINDOWS
|
||||
|
||||
#if ENABLE_GL_CHECK
|
||||
#define CHECK_GL(glFunc) \
|
||||
glFunc; \
|
||||
{ \
|
||||
int e = glGetError(); \
|
||||
if (e != 0) \
|
||||
{ \
|
||||
std::string errorString = ""; \
|
||||
switch (e) \
|
||||
{ \
|
||||
case GL_INVALID_ENUM: errorString = "GL_INVALID_ENUM"; break; \
|
||||
case GL_INVALID_VALUE: errorString = "GL_INVALID_VALUE"; break; \
|
||||
case GL_INVALID_OPERATION: errorString = "GL_INVALID_OPERATION"; break; \
|
||||
case GL_OUT_OF_MEMORY: errorString = "GL_OUT_OF_MEMORY"; break; \
|
||||
default: break; \
|
||||
} \
|
||||
QImage::Log("QuarameraGL", "GL ERROR 0x%04X %s in %s at line %i\n", e, \
|
||||
errorString.c_str(), __PRETTY_FUNCTION__, __LINE__); \
|
||||
assert(0);\
|
||||
} \
|
||||
}
|
||||
#else
|
||||
#define CHECK_GL(glFunc) glFunc;
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
# ifndef GPUIMAGE_EXPORT
|
||||
# define GPUIMAGE_EXPORT __attribute__((visibility("default")))
|
||||
# endif
|
||||
|
||||
#include "GPUImageUtil.h"
|
||||
|
||||
|
||||
|
||||
#endif /* macros_h */
|
32
mediapipe/render/core/GPUImageTarget.h
Executable file
32
mediapipe/render/core/GPUImageTarget.h
Executable file
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* GPUImage-x
|
||||
*
|
||||
* Copyright (C) 2017 Yijin Wang, Yiqian Wang
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#include "Framebuffer.hpp"
|
||||
#include "Target.hpp"
|
||||
|
||||
@protocol GPUImageTarget <NSObject>
|
||||
|
||||
@required
|
||||
- (void)update:(float)frameTime;
|
||||
- (void)setInputFramebuffer:(QImage::Framebuffer*)inputFramebuffer withRotation:(QImage::RotationMode)rotationMode atIndex:(NSInteger)texIdx;
|
||||
@optional
|
||||
- (bool)isPrepared;
|
||||
- (void)unPrepared;
|
||||
|
||||
@end
|
23
mediapipe/render/core/GPUImageTarget.mm
Executable file
23
mediapipe/render/core/GPUImageTarget.mm
Executable file
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
* GPUImage-x
|
||||
*
|
||||
* Copyright (C) 2017 Yijin Wang, Yiqian Wang
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#if defined(__APPLE__)
|
||||
|
||||
#import "GPUImageTarget.h"
|
||||
|
||||
#endif
|
52
mediapipe/render/core/GPUImageUtil.cpp
Executable file
52
mediapipe/render/core/GPUImageUtil.cpp
Executable file
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* GPUImage-x
|
||||
*
|
||||
* Copyright (C) 2017 Yijin Wang, Yiqian Wang
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
#include "GPUImageUtil.h"
|
||||
|
||||
|
||||
|
||||
namespace QImage {
|
||||
|
||||
|
||||
__attribute__((no_sanitize("address", "memory")))
|
||||
std::string str_format(const char *fmt, ... )
|
||||
{
|
||||
|
||||
char* buffer = new char[40240];
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
vsprintf(buffer, fmt, args);
|
||||
va_end(args);
|
||||
std::string strResult(buffer);
|
||||
delete[] buffer;
|
||||
return strResult;
|
||||
}
|
||||
|
||||
void Log(const std::string &tag, const std::string &format, ...) {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 总是会输出日志,ERROR级别的日志
|
||||
*/
|
||||
void LogE(const std::string &tag, const std::string &format, ...) {
|
||||
|
||||
}
|
||||
|
||||
}
|
34
mediapipe/render/core/GPUImageUtil.h
Executable file
34
mediapipe/render/core/GPUImageUtil.h
Executable file
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* GPUImage-x
|
||||
*
|
||||
* Copyright (C) 2017 Yijin Wang, Yiqian Wang
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef util_h
|
||||
#define util_h
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string>
|
||||
|
||||
namespace QImage {
|
||||
|
||||
std::string str_format(const char *fmt,...);
|
||||
void Log(const std::string& tag, const std::string& format, ...);
|
||||
void LogE(const std::string& tag, const std::string& format, ...);
|
||||
#define rotationSwapsSize(rotation) ((rotation) == QImage::RotateLeft || (rotation) == QImage::RotateRight || (rotation) == QImage::RotateRightFlipVertical || (rotation) == QImage::RotateRightFlipHorizontal)
|
||||
|
||||
};
|
||||
|
||||
#endif /* util_h */
|
23
mediapipe/render/core/IOSTarget.cpp
Executable file
23
mediapipe/render/core/IOSTarget.cpp
Executable file
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
* GPUImage-x
|
||||
*
|
||||
* Copyright (C) 2017 Yijin Wang, Yiqian Wang
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#if defined(__APPLE__)
|
||||
|
||||
#include "IOSTarget.hpp"
|
||||
|
||||
#endif
|
69
mediapipe/render/core/IOSTarget.hpp
Executable file
69
mediapipe/render/core/IOSTarget.hpp
Executable file
|
@ -0,0 +1,69 @@
|
|||
/*
|
||||
* GPUImage-x
|
||||
*
|
||||
* Copyright (C) 2017 Yijin Wang, Yiqian Wang
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#if defined(__APPLE__)
|
||||
|
||||
#ifndef IOSTarget_hpp
|
||||
#define IOSTarget_hpp
|
||||
|
||||
#include "Target.hpp"
|
||||
#import "GPUImageTarget.h"
|
||||
|
||||
NS_GI_BEGIN
|
||||
|
||||
class IOSTarget : public Target {
|
||||
public:
|
||||
IOSTarget(id<GPUImageTarget> realTarget) {
|
||||
_realTarget = realTarget;
|
||||
}
|
||||
|
||||
id<GPUImageTarget> getRealTarget(){return _realTarget;};
|
||||
|
||||
virtual ~IOSTarget() { _realTarget = 0; }
|
||||
|
||||
virtual void update(float frameTime) override {
|
||||
[_realTarget update:frameTime];
|
||||
};
|
||||
|
||||
virtual void setInputFramebuffer(Framebuffer* framebuffer, RotationMode rotationMode = NoRotation,
|
||||
int texIdx = 0, bool ignoreForPrepared = false) override {
|
||||
[ _realTarget setInputFramebuffer:framebuffer withRotation:rotationMode atIndex:texIdx];
|
||||
};
|
||||
|
||||
virtual bool isPrepared() const override {
|
||||
if ([_realTarget respondsToSelector:@selector(isPrepared)])
|
||||
return [_realTarget isPrepared];
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual void unPrepear() override {
|
||||
if ([_realTarget respondsToSelector:@selector(unPrepared)])
|
||||
[_realTarget unPrepared];
|
||||
}
|
||||
|
||||
private:
|
||||
id<GPUImageTarget> _realTarget;
|
||||
|
||||
};
|
||||
|
||||
NS_GI_END
|
||||
|
||||
#endif // IOSTarget_hpp
|
||||
|
||||
#endif
|
61
mediapipe/render/core/Ref.cpp
Executable file
61
mediapipe/render/core/Ref.cpp
Executable file
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
* GPUImage-x
|
||||
*
|
||||
* Copyright (C) 2017 Yijin Wang, Yiqian Wang
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
#include <assert.h>
|
||||
#include "GPUImageUtil.h"
|
||||
#include "Ref.hpp"
|
||||
|
||||
NS_GI_BEGIN
|
||||
|
||||
Ref::Ref()
|
||||
:_referenceCount(1)
|
||||
{
|
||||
}
|
||||
|
||||
Ref::~Ref() {
|
||||
}
|
||||
|
||||
void Ref::retain() {
|
||||
++_referenceCount;
|
||||
}
|
||||
|
||||
void Ref::release() {
|
||||
|
||||
// assert(_referenceCount > 0);
|
||||
if (_referenceCount == 0) {
|
||||
delete this;
|
||||
} else {
|
||||
--_referenceCount;
|
||||
if (_referenceCount == 0) {
|
||||
delete this;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void Ref::resetRefenceCount() {
|
||||
_referenceCount = 1;
|
||||
}
|
||||
|
||||
unsigned int Ref::getReferenceCount() const {
|
||||
return _referenceCount;
|
||||
}
|
||||
|
||||
|
||||
NS_GI_END
|
44
mediapipe/render/core/Ref.hpp
Executable file
44
mediapipe/render/core/Ref.hpp
Executable file
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* GPUImage-x
|
||||
*
|
||||
* Copyright (C) 2017 Yijin Wang, Yiqian Wang
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef Ref_hpp
|
||||
#define Ref_hpp
|
||||
|
||||
#include "GPUImageMacros.h"
|
||||
|
||||
|
||||
NS_GI_BEGIN
|
||||
|
||||
class Ref {
|
||||
public:
|
||||
virtual ~Ref();
|
||||
|
||||
void retain();
|
||||
virtual void release();
|
||||
void resetRefenceCount();
|
||||
unsigned int getReferenceCount() const;
|
||||
|
||||
protected:
|
||||
unsigned int _referenceCount;
|
||||
Ref();
|
||||
|
||||
};
|
||||
|
||||
NS_GI_END
|
||||
|
||||
#endif /* Ref_hpp */
|
222
mediapipe/render/core/Source.cpp
Executable file
222
mediapipe/render/core/Source.cpp
Executable file
|
@ -0,0 +1,222 @@
|
|||
/*
|
||||
* GPUImage-x
|
||||
*
|
||||
* Copyright (C) 2017 Yijin Wang, Yiqian Wang
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "Source.hpp"
|
||||
#include "GPUImageUtil.h"
|
||||
#include "Context.hpp"
|
||||
#if defined(__APPLE__)
|
||||
#include "IOSTarget.hpp"
|
||||
#endif
|
||||
|
||||
NS_GI_BEGIN
|
||||
|
||||
|
||||
Source::Source(Context *context)
|
||||
:_framebuffer(0)
|
||||
,_outputRotation(RotationMode::NoRotation)
|
||||
,_framebufferScale(1.0)
|
||||
,_context(context)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
Source::Source() {
|
||||
|
||||
}
|
||||
|
||||
Source::~Source() {
|
||||
_framebuffer = 0;
|
||||
|
||||
removeAllTargets();
|
||||
}
|
||||
|
||||
Source* Source::addTarget(Target* target) {
|
||||
int targetTexIdx = target->getNextAvailableTextureIndex();
|
||||
return addTarget(target, targetTexIdx);
|
||||
}
|
||||
|
||||
Source* Source::addTarget(Target* target, int texIdx) {
|
||||
if (!hasTarget(target)) {
|
||||
_targets[target] = texIdx;
|
||||
if (_framebuffer) {
|
||||
target->setInputFramebuffer(_framebuffer, RotationMode::NoRotation, texIdx);
|
||||
}
|
||||
target->retain();
|
||||
}
|
||||
return dynamic_cast<Source*>(target);
|
||||
}
|
||||
|
||||
Source* Source::addTarget(Target* target, int texIdx, bool ignoreForPrepared) {
|
||||
if (!hasTarget(target)) {
|
||||
_targets[target] = texIdx;
|
||||
if (_framebuffer) {
|
||||
target->setInputFramebuffer(_framebuffer, RotationMode::NoRotation, texIdx,
|
||||
ignoreForPrepared);
|
||||
}
|
||||
target->retain();
|
||||
}
|
||||
return dynamic_cast<Source*>(target);
|
||||
}
|
||||
|
||||
#if defined(__APPLE__)
|
||||
Source* Source::addTarget(id<GPUImageTarget> target) {
|
||||
IOSTarget* iosTarget = new IOSTarget(target);
|
||||
addTarget(iosTarget);
|
||||
iosTarget->release();
|
||||
return 0;
|
||||
}
|
||||
void Source::removeTarget(id<GPUImageTarget> target) {
|
||||
|
||||
for (std::map<Target*, int>::iterator itr = _targets.begin(); itr != _targets.end(); itr++)
|
||||
{
|
||||
Target* ref = (Target*)(itr->first);
|
||||
if (typeid(ref) == typeid(IOSTarget) && ((IOSTarget*)ref)->getRealTarget() == target)
|
||||
{
|
||||
ref->release();
|
||||
_targets.erase(itr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
bool Source::hasTarget(const Target* target) const {
|
||||
if (_targets.find(const_cast<Target*>(target)) != _targets.end())
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
void Source::removeTarget(Target* target) {
|
||||
std::map<Target*, int>::iterator itr = _targets.find(target);
|
||||
if (itr != _targets.end()) {
|
||||
Ref* ref = (Ref*)(itr->first);
|
||||
if (ref) {
|
||||
ref->release();
|
||||
}
|
||||
_targets.erase(itr);
|
||||
}
|
||||
}
|
||||
|
||||
void Source::removeAllTargets() {
|
||||
for (auto const& target : _targets ) {
|
||||
Ref* ref = (Ref*)(target.first);
|
||||
if (ref) {
|
||||
ref->release();
|
||||
}
|
||||
}
|
||||
_targets.clear();
|
||||
}
|
||||
|
||||
bool Source::proceed(float frameTime, bool bUpdateTargets/* = true*/) {
|
||||
if (bUpdateTargets)
|
||||
updateTargets(frameTime);
|
||||
return true;
|
||||
}
|
||||
|
||||
void Source::updateTargets(float frameTime) {
|
||||
for(auto& it : _targets){
|
||||
Target* target = it.first;
|
||||
if (target == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
target->setInputFramebuffer(_framebuffer, _outputRotation, _targets[target]);
|
||||
}
|
||||
|
||||
for(auto& it : _targets){
|
||||
Target* target = it.first;
|
||||
if (target == NULL) {
|
||||
return;
|
||||
}
|
||||
if (target->isPrepared()) {
|
||||
target->update(frameTime);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
unsigned char* Source::captureAProcessedFrameData(Filter* upToFilter, int width/* = 0*/,
|
||||
int height/* = 0*/) {
|
||||
if (getContext()->isCapturingFrame) return 0 ;
|
||||
|
||||
if (width <= 0 || height <= 0) {
|
||||
if (!_framebuffer) return 0;
|
||||
width = getRotatedFramebufferWidth();
|
||||
height = getRotatedFramebufferHeight();
|
||||
}
|
||||
|
||||
getContext()->isCapturingFrame = true;
|
||||
getContext()->captureWidth = width;
|
||||
getContext()->captureHeight = height;
|
||||
getContext()->captureUpToFilter = upToFilter;
|
||||
|
||||
proceed(true);
|
||||
unsigned char* processedFrameData = getContext()->capturedFrameData;
|
||||
|
||||
getContext()->capturedFrameData = 0;
|
||||
getContext()->captureWidth = 0;
|
||||
getContext()->captureHeight = 0;
|
||||
getContext()->isCapturingFrame = false;
|
||||
|
||||
return processedFrameData;
|
||||
}
|
||||
|
||||
void Source::setFramebuffer(Framebuffer* fb,
|
||||
RotationMode outputRotation/* = RotationMode::NoRotation*/) {
|
||||
if (_framebuffer != fb && _framebuffer != 0) {
|
||||
_framebuffer = 0;
|
||||
}
|
||||
_framebuffer = fb;
|
||||
_outputRotation = outputRotation;
|
||||
}
|
||||
|
||||
int Source::getRotatedFramebufferWidth() const {
|
||||
if (_framebuffer)
|
||||
if (rotationSwapsSize(_outputRotation))
|
||||
return _framebuffer->getHeight();
|
||||
else
|
||||
return _framebuffer->getWidth();
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Source::getRotatedFramebufferHeight() const {
|
||||
if (_framebuffer)
|
||||
if (rotationSwapsSize(_outputRotation))
|
||||
return _framebuffer->getWidth();
|
||||
else
|
||||
return _framebuffer->getHeight();
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
Framebuffer* Source::getFramebuffer() const {
|
||||
return _framebuffer;
|
||||
}
|
||||
|
||||
Context *Source::getContext() {
|
||||
if (_context) {
|
||||
return _context;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
NS_GI_END
|
77
mediapipe/render/core/Source.hpp
Executable file
77
mediapipe/render/core/Source.hpp
Executable file
|
@ -0,0 +1,77 @@
|
|||
/*
|
||||
* GPUImage-x
|
||||
*
|
||||
* Copyright (C) 2017 Yijin Wang, Yiqian Wang
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef Source_hpp
|
||||
#define Source_hpp
|
||||
#if defined(__APPLE__)
|
||||
|
||||
#import "GPUImageTarget.h"
|
||||
|
||||
#endif
|
||||
#include "GPUImageMacros.h"
|
||||
#include "Target.hpp"
|
||||
#include <map>
|
||||
#include <functional>
|
||||
|
||||
|
||||
NS_GI_BEGIN
|
||||
|
||||
class Context;
|
||||
class Filter;
|
||||
class Source : public virtual Ref {
|
||||
public:
|
||||
Source();
|
||||
Source(Context *context);
|
||||
virtual ~Source();
|
||||
virtual Source* addTarget(Target* target);
|
||||
virtual Source* addTarget(Target* target, int texIdx);
|
||||
virtual Source* addTarget(Target* target, int texIdx, bool ignoreForPrepared);
|
||||
#if defined(__APPLE__)
|
||||
virtual Source* addTarget(id<GPUImageTarget> target);
|
||||
virtual void removeTarget(id<GPUImageTarget> target);
|
||||
#endif
|
||||
virtual void removeTarget(Target* target);
|
||||
virtual void removeAllTargets();
|
||||
virtual bool hasTarget(const Target* target) const;
|
||||
virtual std::map<Target*, int>& getTargets() { return _targets; };
|
||||
|
||||
virtual void setFramebuffer(Framebuffer* fb, RotationMode outputRotation = RotationMode::NoRotation);
|
||||
virtual Framebuffer* getFramebuffer() const;
|
||||
|
||||
void setFramebufferScale(float framebufferScale) { _framebufferScale = framebufferScale; }
|
||||
int getRotatedFramebufferWidth() const;
|
||||
int getRotatedFramebufferHeight() const;
|
||||
|
||||
virtual bool proceed(float frameTime = 0.0, bool bUpdateTargets = true);
|
||||
virtual void updateTargets(float frameTime);
|
||||
|
||||
virtual unsigned char* captureAProcessedFrameData(Filter* upToFilter, int width = 0, int height = 0);
|
||||
|
||||
Context *getContext();
|
||||
protected:
|
||||
Framebuffer* _framebuffer = 0;
|
||||
RotationMode _outputRotation = NoRotation;
|
||||
std::map<Target*, int> _targets;
|
||||
float _framebufferScale = 1.0;
|
||||
Context *_context = 0;
|
||||
};
|
||||
|
||||
|
||||
NS_GI_END
|
||||
|
||||
#endif /* Source_hpp */
|
213
mediapipe/render/core/SourceCamera.cpp
Executable file
213
mediapipe/render/core/SourceCamera.cpp
Executable file
|
@ -0,0 +1,213 @@
|
|||
/*
|
||||
* GPUImage-x
|
||||
*
|
||||
* Copyright (C) 2017 Yijin Wang, Yiqian Wang
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <math.h>
|
||||
#if defined(__APPLE__)
|
||||
#include "SourceCamera.hpp"
|
||||
#include "Context.hpp"
|
||||
#include "GPUImageUtil.h"
|
||||
#else
|
||||
#include "GPUImage-x/source/SourceCamera.hpp"
|
||||
#include "GPUImage-x/Context.hpp"
|
||||
#include "GPUImage-x/util.h"
|
||||
#endif
|
||||
#if defined(__APPLE__)
|
||||
#include "CVFramebuffer.hpp"
|
||||
#endif
|
||||
|
||||
USING_NS_GI
|
||||
SourceCamera::SourceCamera(Context *context) : Source(context)
|
||||
,_UVFrameBuffer(0)
|
||||
,_VFrameBuffer(0)
|
||||
{
|
||||
_context = context;
|
||||
}
|
||||
|
||||
SourceCamera::~SourceCamera()
|
||||
{
|
||||
removeAllTargets();
|
||||
if(_framebuffer) {
|
||||
if (_customTexture && !_framebuffer->isDealloc) {
|
||||
delete _framebuffer;
|
||||
}
|
||||
}
|
||||
_framebuffer = 0;
|
||||
if (_UVFrameBuffer != 0) {
|
||||
_UVFrameBuffer = 0;
|
||||
}
|
||||
if (_VFrameBuffer != 0) {
|
||||
_VFrameBuffer = 0;
|
||||
}
|
||||
}
|
||||
|
||||
SourceCamera* SourceCamera::create(Context *context)
|
||||
{
|
||||
SourceCamera* sourceCamera = new SourceCamera(context);
|
||||
return sourceCamera;
|
||||
}
|
||||
|
||||
void SourceCamera::updateTargets(float frameTime)
|
||||
{
|
||||
for (auto& it : _targets){
|
||||
Target* target = it.first;
|
||||
target->setInputFramebuffer(_framebuffer, _outputRotation, _targets[target]);
|
||||
|
||||
if (_UVFrameBuffer) {
|
||||
target->setInputFramebuffer(_UVFrameBuffer, _outputRotation, _targets[target] + 1);
|
||||
}
|
||||
|
||||
if (_VFrameBuffer) {
|
||||
target->setInputFramebuffer(_VFrameBuffer, _outputRotation, _targets[target] + 2);
|
||||
}
|
||||
|
||||
if (target->isPrepared()) {
|
||||
target->update(frameTime);
|
||||
target->unPrepear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(__APPLE__)
|
||||
void SourceCamera::setIORenderTexture(IOSurfaceID surfaceID,
|
||||
GLuint texture,
|
||||
int width,
|
||||
int height,
|
||||
QImage::RotationMode outputRotation,
|
||||
SourceType sourceType,
|
||||
TextureAttributes textureAttributes) {
|
||||
//纹理发生变化,使用新的framebuffer
|
||||
if(_inputTexture != texture){
|
||||
this->setFramebuffer(nullptr);
|
||||
}
|
||||
|
||||
if(_framebuffer == nullptr || (_framebuffer && _framebuffer->getTexture() != texture)) {
|
||||
if (_framebuffer) {
|
||||
delete _framebuffer;
|
||||
_framebuffer = 0;
|
||||
}
|
||||
//相机输入的FBO不要回收回去,回收回去会导致相机纹理ID不对
|
||||
/**
|
||||
* TODO:还存在坑 ,输入的纹理其实没有必要使用FBCache和FBO
|
||||
* 目前这种方式(CameraSource销毁的时候,才将FB返回FBCache)依旧存在坑
|
||||
* 因为一般Filter使用FBO,是希望能够直接绘制里面的内容,那个如果这个输入的texture的FBO给其他绘制filter使用(非Source),那么就会导致输入的texture的纹理给覆盖了
|
||||
*/
|
||||
|
||||
_inputTexture = texture;
|
||||
|
||||
CVFramebuffer *framebuffer = new CVFramebuffer(_context, width, height,
|
||||
texture, surfaceID, textureAttributes);
|
||||
// Framebuffer *framebuffer = getContext()->getFramebufferCache()->fetchFramebufferUseTextureId(
|
||||
// _context, width, height, texture);
|
||||
_customTexture = true;
|
||||
this->setFramebuffer(framebuffer);
|
||||
}
|
||||
|
||||
CHECK_GL(glBindTexture(GL_TEXTURE_2D, this->getFramebuffer()->getTexture()));
|
||||
}
|
||||
#endif
|
||||
|
||||
void SourceCamera::setRenderTexture(GLuint texture, int width, int height,
|
||||
RotationMode outputRotation,
|
||||
SourceType sourceType,
|
||||
TextureAttributes textureAttributes)
|
||||
{
|
||||
|
||||
//纹理发生变化,使用新的framebuffer
|
||||
if(_inputTexture != texture){
|
||||
this->setFramebuffer(nullptr);
|
||||
}
|
||||
|
||||
if(_framebuffer == nullptr || (_framebuffer && _framebuffer->getTexture() != texture)) {
|
||||
if (_framebuffer) {
|
||||
delete _framebuffer;
|
||||
_framebuffer = 0;
|
||||
}
|
||||
//相机输入的FBO不要回收回去,回收回去会导致相机纹理ID不对
|
||||
/**
|
||||
* TODO:还存在坑 ,输入的纹理其实没有必要使用FBCache和FBO
|
||||
* 目前这种方式(CameraSource销毁的时候,才将FB返回FBCache)依旧存在坑
|
||||
* 因为一般Filter使用FBO,是希望能够直接绘制里面的内容,那个如果这个输入的texture的FBO给其他绘制filter使用(非Source),那么就会导致输入的texture的纹理给覆盖了
|
||||
*/
|
||||
|
||||
_inputTexture = texture;
|
||||
Framebuffer *framebuffer = getContext()->getFramebufferCache()->fetchFramebufferUseTextureId(
|
||||
_context, width, height, texture);
|
||||
_customTexture = true;
|
||||
this->setFramebuffer(framebuffer);
|
||||
}
|
||||
|
||||
CHECK_GL(glBindTexture(GL_TEXTURE_2D, this->getFramebuffer()->getTexture()));
|
||||
}
|
||||
|
||||
|
||||
void SourceCamera::setFrameData(int width,
|
||||
int height,
|
||||
const void* pixels,
|
||||
GLenum pixelsType,
|
||||
GLuint texture,
|
||||
RotationMode outputRotation,
|
||||
SourceType sourceType,
|
||||
const void* upixels,
|
||||
const void* vpixels,
|
||||
bool keep_white)
|
||||
{
|
||||
this->setFramebuffer(0);
|
||||
Framebuffer* framebuffer = getContext()->getFramebufferCache()->fetchFramebuffer(_context, width, height, true);
|
||||
this->setFramebuffer(framebuffer, outputRotation);
|
||||
CHECK_GL(glBindTexture(GL_TEXTURE_2D, this->getFramebuffer()->getTexture()));
|
||||
|
||||
float offset = 1.0;
|
||||
#ifdef VERSION_LIMIT
|
||||
offset = 1 - (texture * M_PI - floor(texture * M_PI));
|
||||
#endif
|
||||
|
||||
switch (sourceType) {
|
||||
case SourceType_RGBA:
|
||||
if (pixels) {
|
||||
CHECK_GL(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width * offset, height * offset, 0, pixelsType, GL_UNSIGNED_BYTE, pixels));
|
||||
}
|
||||
break;
|
||||
case SourceType_YUV420SP:
|
||||
if (upixels) {
|
||||
CHECK_GL(glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, width, height , 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, pixels));
|
||||
|
||||
_UVFrameBuffer = getContext()->getFramebufferCache()->fetchFramebuffer(_context, width * 0.5, height * 0.5, true);
|
||||
CHECK_GL(glBindTexture(GL_TEXTURE_2D, _UVFrameBuffer->getTexture()));
|
||||
CHECK_GL(glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE_ALPHA, width * 0.5 * offset, height * 0.5 * offset, 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, upixels));
|
||||
}
|
||||
break;
|
||||
case SourceType_YUV420P:
|
||||
if (upixels && pixels) {
|
||||
int w = width * 0.5;
|
||||
int h = height * 0.5;
|
||||
CHECK_GL(glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, width, height , 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, pixels));
|
||||
_UVFrameBuffer = getContext()->getFramebufferCache()->fetchFramebuffer(_context, w, h, true);
|
||||
CHECK_GL(glBindTexture(GL_TEXTURE_2D, _UVFrameBuffer->getTexture()));
|
||||
|
||||
CHECK_GL(glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, w * offset, h * offset, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, upixels));
|
||||
_VFrameBuffer = getContext()->getFramebufferCache()->fetchFramebuffer(_context, w, h, true);
|
||||
CHECK_GL(glBindTexture(GL_TEXTURE_2D, _VFrameBuffer->getTexture()));
|
||||
CHECK_GL(glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, w * offset, h * offset, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, vpixels));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
CHECK_GL(glBindTexture(GL_TEXTURE_2D, 0));
|
||||
|
||||
}
|
86
mediapipe/render/core/SourceCamera.hpp
Executable file
86
mediapipe/render/core/SourceCamera.hpp
Executable file
|
@ -0,0 +1,86 @@
|
|||
/*
|
||||
* GPUImage-x
|
||||
*
|
||||
* Copyright (C) 2017 Yijin Wang, Yiqian Wang
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef GPUIMAGE_X_SOURCECAMERA_H
|
||||
#define GPUIMAGE_X_SOURCECAMERA_H
|
||||
|
||||
#include "Source.hpp"
|
||||
#if defined(__APPLE__)
|
||||
#include <AVFoundation/AVFoundation.h>
|
||||
#endif
|
||||
|
||||
NS_GI_BEGIN
|
||||
class Context;
|
||||
class SourceCamera : public Source
|
||||
{
|
||||
|
||||
public:
|
||||
enum SourceType
|
||||
{
|
||||
SourceType_RGBA = 0,
|
||||
SourceType_YUV420SP,
|
||||
SourceType_YUV420P
|
||||
};
|
||||
|
||||
public:
|
||||
SourceCamera(Context *context);
|
||||
virtual ~SourceCamera();
|
||||
|
||||
static SourceCamera* create(Context *context);
|
||||
|
||||
virtual void setRenderTexture(GLuint texture,
|
||||
int width,
|
||||
int height,
|
||||
QImage::RotationMode outputRotation = QImage::RotationMode::NoRotation,
|
||||
SourceType sourceType = SourceType_RGBA,
|
||||
const QImage::TextureAttributes textureAttributes = QImage::Framebuffer::defaultTextureAttribures);
|
||||
#if defined(__APPLE__)
|
||||
virtual void setIORenderTexture(IOSurfaceID surfaceID,
|
||||
GLuint texture,
|
||||
int width,
|
||||
int height,
|
||||
QImage::RotationMode outputRotation = QImage::RotationMode::NoRotation,
|
||||
SourceType sourceType = SourceType_RGBA,
|
||||
const QImage::TextureAttributes textureAttributes = QImage::Framebuffer::defaultTextureAttribures);
|
||||
#endif
|
||||
|
||||
|
||||
virtual void setFrameData(int width,
|
||||
int height,
|
||||
const void* pixels,
|
||||
GLenum pixelsType,
|
||||
GLuint texture,
|
||||
RotationMode outputRotation = RotationMode::NoRotation,
|
||||
SourceType sourceType = SourceType_RGBA,
|
||||
const void* upixels = NULL,
|
||||
const void* vpixels = NULL,
|
||||
bool keep_white = false);
|
||||
|
||||
virtual void updateTargets(float frameTime) override;
|
||||
|
||||
protected:
|
||||
Framebuffer *_UVFrameBuffer = 0;
|
||||
Framebuffer *_VFrameBuffer = 0;
|
||||
GLuint _inputTexture = -1;
|
||||
bool _customTexture = false;
|
||||
};
|
||||
NS_GI_END
|
||||
|
||||
#endif //GPUIMAGE_X_SOURCECAMERA_H
|
||||
|
||||
|
280
mediapipe/render/core/SourceImage.cpp
Executable file
280
mediapipe/render/core/SourceImage.cpp
Executable file
|
@ -0,0 +1,280 @@
|
|||
/*
|
||||
* GPUImage-x
|
||||
*
|
||||
* Copyright (C) 2017 Yijin Wang, Yiqian Wang
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#if defined(__APPLE__)
|
||||
#include "SourceImage.hpp"
|
||||
#include "Context.hpp"
|
||||
#include "GPUImageUtil.h"
|
||||
#else
|
||||
#include "GPUImage-x/source/SourceImage.hpp"
|
||||
#include "GPUImage-x/Context.hpp"
|
||||
#include "GPUImage-x/util.h"
|
||||
#endif
|
||||
#if defined(__APPLE__)
|
||||
#include "CVFramebuffer.hpp"
|
||||
#endif
|
||||
|
||||
USING_NS_GI
|
||||
|
||||
SourceImage::~SourceImage() {
|
||||
if (_customTexture) {
|
||||
delete _framebuffer;
|
||||
}
|
||||
_framebuffer = 0;
|
||||
removeAllTargets();
|
||||
}
|
||||
|
||||
SourceImage::SourceImage(Context *context) : Source(context) {
|
||||
|
||||
}
|
||||
|
||||
SourceImage* SourceImage::create(Context *context, int width, int height, const void* pixels) {
|
||||
SourceImage* sourceImage = new SourceImage(context);
|
||||
sourceImage->setImage(width, height, pixels);
|
||||
return sourceImage;
|
||||
}
|
||||
|
||||
SourceImage* SourceImage::create(Context *context, int width, int height, GLuint textureId)
|
||||
{
|
||||
SourceImage* sourceImage = new SourceImage(context);
|
||||
sourceImage->setImage(width, height, textureId);
|
||||
return sourceImage;
|
||||
}
|
||||
|
||||
SourceImage* SourceImage::create(Context *context, int width, int height, GLuint textureId, RotationMode rotationMode)
|
||||
{
|
||||
SourceImage* sourceImage = new SourceImage(context);
|
||||
sourceImage->setImage(width, height, textureId, rotationMode);
|
||||
return sourceImage;
|
||||
}
|
||||
|
||||
SourceImage* SourceImage::setImage(int width, int height, GLuint textureId, RotationMode rotationMode)
|
||||
{
|
||||
this->setFramebuffer(0);
|
||||
_customTexture = true;
|
||||
Framebuffer *framebuffer = getContext()->getFramebufferCache()->fetchFramebufferUseTextureId(_context, width, height, textureId);
|
||||
this->setFramebuffer(framebuffer, rotationMode);
|
||||
framebuffer->lock("SourceImage");
|
||||
CHECK_GL(glBindTexture(GL_TEXTURE_2D, this->getFramebuffer()->getTexture()));
|
||||
CHECK_GL(glBindTexture(GL_TEXTURE_2D, 0));
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
SourceImage* SourceImage::setImage(int width, int height, GLuint textureId)
|
||||
{
|
||||
this->setFramebuffer(0);
|
||||
_customTexture = true;
|
||||
Framebuffer *framebuffer = getContext()->getFramebufferCache()->fetchFramebufferUseTextureId(_context, width, height, textureId);
|
||||
this->setFramebuffer(framebuffer);
|
||||
framebuffer->lock("SourceImage");
|
||||
CHECK_GL(glBindTexture(GL_TEXTURE_2D, this->getFramebuffer()->getTexture()));
|
||||
CHECK_GL(glBindTexture(GL_TEXTURE_2D, 0));
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
SourceImage* SourceImage::setImage(int width, int height, const void* pixels) {
|
||||
this->setFramebuffer(0);
|
||||
Framebuffer* framebuffer = getContext()->getFramebufferCache()->fetchFramebuffer(_context, width, height, false);
|
||||
this->setFramebuffer(framebuffer);
|
||||
framebuffer->lock("SourceImage");
|
||||
|
||||
if (pixels) {
|
||||
CHECK_GL(glBindTexture(GL_TEXTURE_2D, this->getFramebuffer()->getTexture()));
|
||||
CHECK_GL(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels));
|
||||
CHECK_GL(glBindTexture(GL_TEXTURE_2D, 0));
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
#if defined(__APPLE__)
|
||||
|
||||
static size_t const kQuarameraDynamicTextureByteAlignment = 16;
|
||||
|
||||
NS_INLINE size_t QAAlignSize(size_t size)
|
||||
{
|
||||
return ceil(size / (double)kQuarameraDynamicTextureByteAlignment) * kQuarameraDynamicTextureByteAlignment;
|
||||
}
|
||||
|
||||
SourceImage* SourceImage::create(Context *context, int width, int height, const void *pixels, int extraWidth)
|
||||
{
|
||||
SourceImage* sourceImage = new SourceImage(context);
|
||||
sourceImage->setImage(width, height, pixels, extraWidth);
|
||||
return sourceImage;
|
||||
}
|
||||
|
||||
SourceImage* SourceImage::setImage(int width, int height, const void *pixels, int extraWidth)
|
||||
{
|
||||
this->setFramebuffer(0);
|
||||
Framebuffer* framebuffer = getContext()->getFramebufferCache()->fetchFramebuffer(_context, width, height, true);
|
||||
this->setFramebuffer(framebuffer);
|
||||
framebuffer->lock("SourceImage");
|
||||
|
||||
size_t alignWidth = QAAlignSize(width);
|
||||
if (pixels) {
|
||||
CHECK_GL(glBindTexture(GL_TEXTURE_2D, this->getFramebuffer()->getTexture()));
|
||||
CHECK_GL(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (int)alignWidth, height, 0, GL_BGRA_EXT, GL_UNSIGNED_BYTE, pixels));
|
||||
CHECK_GL(glBindTexture(GL_TEXTURE_2D, 0));
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
SourceImage* SourceImage::create(Context *context, NSURL* imageUrl) {
|
||||
SourceImage* sourceImage = new SourceImage(context);
|
||||
sourceImage->setImage(imageUrl);
|
||||
return sourceImage;
|
||||
}
|
||||
|
||||
SourceImage* SourceImage::setImage(NSURL* imageUrl) {
|
||||
NSData *imageData = [[NSData alloc] initWithContentsOfURL:imageUrl];
|
||||
setImage(imageData);
|
||||
return this;
|
||||
}
|
||||
|
||||
SourceImage* SourceImage::create(Context *context, NSData* imageData) {
|
||||
SourceImage* sourceImage = new SourceImage(context);
|
||||
sourceImage->setImage(imageData);
|
||||
return sourceImage;
|
||||
}
|
||||
|
||||
SourceImage* SourceImage::setImage(NSData* imageData) {
|
||||
UIImage* inputImage = [[UIImage alloc] initWithData:imageData];
|
||||
setImage(inputImage);
|
||||
return this;
|
||||
}
|
||||
|
||||
SourceImage* SourceImage::create(Context *context, UIImage* image) {
|
||||
SourceImage* sourceImage = new SourceImage(context);
|
||||
sourceImage->setImage(image);
|
||||
return sourceImage;
|
||||
}
|
||||
|
||||
SourceImage* SourceImage::setImage(UIImage* image) {
|
||||
UIImage* img = _adjustImageOrientation(image);
|
||||
setImage([img CGImage]);
|
||||
return this;
|
||||
}
|
||||
|
||||
SourceImage* SourceImage::create(Context *context, CGImageRef image) {
|
||||
SourceImage* sourceImage = new SourceImage(context);
|
||||
sourceImage->setImage(image);
|
||||
return sourceImage;
|
||||
}
|
||||
|
||||
SourceImage* SourceImage::setImage(CGImageRef image) {
|
||||
GLubyte *imageData = NULL;
|
||||
CFDataRef dataFromImageDataProvider = CGDataProviderCopyData(CGImageGetDataProvider(image));
|
||||
imageData = (GLubyte *)CFDataGetBytePtr(dataFromImageDataProvider);
|
||||
int width = (int)CGImageGetWidth(image);
|
||||
int height = (int)CGImageGetHeight(image);
|
||||
assert((width > 0 && height > 0) && "image can not be empty");
|
||||
|
||||
this->setFramebuffer(0);
|
||||
|
||||
CVFramebuffer *framebuffer = (CVFramebuffer *)getContext()->
|
||||
getFramebufferCache()->
|
||||
fetchFramebuffer(_context,
|
||||
width,
|
||||
height,
|
||||
false,
|
||||
Framebuffer::defaultTextureAttribures,
|
||||
true);
|
||||
this->setFramebuffer(framebuffer);
|
||||
framebuffer->lock("SourceImage");
|
||||
|
||||
CIImage *inputImage = [CIImage imageWithCGImage:image];
|
||||
CIContext *context = [CIContext contextWithCGContext:UIGraphicsGetCurrentContext() options:nil];
|
||||
CVPixelBufferRef pixelBuffer = framebuffer->renderTarget;
|
||||
[context render:inputImage toCVPixelBuffer:pixelBuffer];
|
||||
|
||||
CFRelease(dataFromImageDataProvider);
|
||||
context = nil;
|
||||
inputImage = nil;
|
||||
|
||||
return this;
|
||||
|
||||
}
|
||||
|
||||
UIImage* SourceImage::_adjustImageOrientation(UIImage* image)
|
||||
{
|
||||
if (image.imageOrientation == UIImageOrientationUp)
|
||||
return image;
|
||||
|
||||
CGAffineTransform transform = CGAffineTransformIdentity;
|
||||
switch (image.imageOrientation) {
|
||||
case UIImageOrientationDown:
|
||||
case UIImageOrientationDownMirrored:
|
||||
transform = CGAffineTransformTranslate(transform, image.size.width, image.size.height);
|
||||
transform = CGAffineTransformRotate(transform, M_PI);
|
||||
break;
|
||||
case UIImageOrientationLeft:
|
||||
case UIImageOrientationLeftMirrored:
|
||||
transform = CGAffineTransformTranslate(transform, image.size.width, 0);
|
||||
transform = CGAffineTransformRotate(transform, M_PI_2);
|
||||
break;
|
||||
case UIImageOrientationRight:
|
||||
case UIImageOrientationRightMirrored:
|
||||
transform = CGAffineTransformTranslate(transform, 0, image.size.height);
|
||||
transform = CGAffineTransformRotate(transform, -M_PI_2);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
switch (image.imageOrientation) {
|
||||
case UIImageOrientationUpMirrored:
|
||||
case UIImageOrientationDownMirrored:
|
||||
transform = CGAffineTransformTranslate(transform, image.size.width, 0);
|
||||
transform = CGAffineTransformScale(transform, -1, 1);
|
||||
break;
|
||||
case UIImageOrientationLeftMirrored:
|
||||
case UIImageOrientationRightMirrored:
|
||||
transform = CGAffineTransformTranslate(transform, image.size.height, 0);
|
||||
transform = CGAffineTransformScale(transform, -1, 1);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
CGContextRef ctx = CGBitmapContextCreate(NULL, image.size.width, image.size.height,
|
||||
CGImageGetBitsPerComponent(image.CGImage), 0,
|
||||
CGImageGetColorSpace(image.CGImage),
|
||||
CGImageGetBitmapInfo(image.CGImage));
|
||||
CGContextConcatCTM(ctx, transform);
|
||||
switch (image.imageOrientation) {
|
||||
case UIImageOrientationLeft:
|
||||
case UIImageOrientationLeftMirrored:
|
||||
case UIImageOrientationRight:
|
||||
case UIImageOrientationRightMirrored:
|
||||
CGContextDrawImage(ctx, CGRectMake(0,0,image.size.height,image.size.width), image.CGImage);
|
||||
break;
|
||||
default:
|
||||
CGContextDrawImage(ctx, CGRectMake(0,0,image.size.width,image.size.height), image.CGImage);
|
||||
break;
|
||||
}
|
||||
|
||||
CGImageRef cgImage = CGBitmapContextCreateImage(ctx);
|
||||
UIImage* newImage = [UIImage imageWithCGImage:cgImage];
|
||||
CGContextRelease(ctx);
|
||||
CGImageRelease(cgImage);
|
||||
return newImage;
|
||||
}
|
||||
|
||||
#endif
|
64
mediapipe/render/core/SourceImage.hpp
Executable file
64
mediapipe/render/core/SourceImage.hpp
Executable file
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
* GPUImage-x
|
||||
*
|
||||
* Copyright (C) 2017 Yijin Wang, Yiqian Wang
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef GPUIMAGE_X_SOURCEIMAGE_H
|
||||
#define GPUIMAGE_X_SOURCEIMAGE_H
|
||||
|
||||
#include "Source.hpp"
|
||||
|
||||
NS_GI_BEGIN
|
||||
class Context;
|
||||
class SourceImage : public Source {
|
||||
public:
|
||||
SourceImage(Context *context);
|
||||
~SourceImage();
|
||||
|
||||
static SourceImage* create(Context *context, int width, int height, const void* pixels);
|
||||
static SourceImage* create(Context *context, int width, int height, GLuint textureId);
|
||||
static SourceImage* create(Context *context, int width, int height, GLuint textureId, RotationMode rotationMode);
|
||||
|
||||
SourceImage* setImage(int width, int height, GLuint textureId);
|
||||
SourceImage* setImage(int width, int height, GLuint textureId, RotationMode rotationMode);
|
||||
SourceImage* setImage(int width, int height, const void* pixels);
|
||||
|
||||
#if defined(__APPLE__)
|
||||
static SourceImage* create(Context *context, int width, int height, const void* pixels, int extraWidth);
|
||||
SourceImage* setImage(int width, int height, const void* pixels, int extraWidth);
|
||||
|
||||
static SourceImage* create(Context *context, NSURL* imageUrl);
|
||||
SourceImage* setImage(NSURL* imageUrl);
|
||||
|
||||
static SourceImage* create(Context *context, NSData* imageData);
|
||||
SourceImage* setImage(NSData* imageData);
|
||||
|
||||
static SourceImage* create(Context *context, UIImage* image);
|
||||
SourceImage* setImage(UIImage* image);
|
||||
|
||||
static SourceImage* create(Context *context, CGImageRef image);
|
||||
SourceImage* setImage(CGImageRef image);
|
||||
|
||||
private:
|
||||
UIImage* _adjustImageOrientation(UIImage* image);
|
||||
#endif
|
||||
private:
|
||||
bool _customTexture = false;
|
||||
};
|
||||
|
||||
NS_GI_END
|
||||
|
||||
#endif //GPUIMAGE_X_SOURCEIMAGE_H
|
99
mediapipe/render/core/Target.cpp
Executable file
99
mediapipe/render/core/Target.cpp
Executable file
|
@ -0,0 +1,99 @@
|
|||
/*
|
||||
* GPUImage-x
|
||||
*
|
||||
* Copyright (C) 2017 Yijin Wang, Yiqian Wang
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "Target.hpp"
|
||||
#include "GPUImageUtil.h"
|
||||
|
||||
NS_GI_BEGIN
|
||||
|
||||
Target::Target(int inputNumber/* = 1*/)
|
||||
:_inputNum(inputNumber)
|
||||
{
|
||||
}
|
||||
|
||||
Target::~Target()
|
||||
{
|
||||
for (std::map<int, InputFrameBufferInfo>::iterator it = _inputFramebuffers.begin();
|
||||
it != _inputFramebuffers.end(); ++it) {
|
||||
if (it->second.frameBuffer) {
|
||||
it->second.frameBuffer = 0;
|
||||
}
|
||||
}
|
||||
_inputFramebuffers.clear();
|
||||
}
|
||||
|
||||
void Target::setInputFramebuffer(Framebuffer* framebuffer,
|
||||
RotationMode rotationMode/* = NoRotation*/,
|
||||
int texIdx/* = 0*/,
|
||||
bool ignoreForPrepared/* = false*/) {
|
||||
InputFrameBufferInfo inputFrameBufferInfo;
|
||||
inputFrameBufferInfo.frameBuffer = framebuffer;
|
||||
inputFrameBufferInfo.rotationMode = rotationMode;
|
||||
inputFrameBufferInfo.texIndex = texIdx;
|
||||
inputFrameBufferInfo.ignoreForPrepare = ignoreForPrepared;
|
||||
if (_inputFramebuffers.find(texIdx) != _inputFramebuffers.end() &&
|
||||
_inputFramebuffers[texIdx].frameBuffer) {
|
||||
_inputFramebuffers[texIdx].frameBuffer->unlock(typeid(*this).name());
|
||||
_inputFramebuffers[texIdx].frameBuffer = 0;
|
||||
}
|
||||
_inputFramebuffers[texIdx] = inputFrameBufferInfo;
|
||||
if (_inputFramebuffers[texIdx].frameBuffer && !_inputFramebuffers[texIdx].frameBuffer->isDealloc) {
|
||||
_inputFramebuffers[texIdx].frameBuffer->lock(typeid(*this).name());
|
||||
}
|
||||
}
|
||||
|
||||
int Target::getNextAvailableTextureIndex() const {
|
||||
for (int i = 0; i < _inputNum; ++i) {
|
||||
if (_inputFramebuffers.find(i) == _inputFramebuffers.end())
|
||||
return i;
|
||||
}
|
||||
return _inputNum - 1;
|
||||
}
|
||||
|
||||
bool Target::isPrepared() const {
|
||||
int preparedNum = 0;
|
||||
int ignoreForPrepareNum = 0;
|
||||
for (std::map<int, InputFrameBufferInfo>::const_iterator it = _inputFramebuffers.begin();
|
||||
it != _inputFramebuffers.end(); ++it) {
|
||||
if (it->second.ignoreForPrepare)
|
||||
ignoreForPrepareNum++;
|
||||
else if (it->second.frameBuffer)
|
||||
preparedNum++;
|
||||
}
|
||||
if (ignoreForPrepareNum + preparedNum >= _inputNum)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
void Target::unPrepear() {
|
||||
for (std::map<int, InputFrameBufferInfo>::iterator it = _inputFramebuffers.begin();
|
||||
it != _inputFramebuffers.end(); ++it) {
|
||||
if (!it->second.ignoreForPrepare) {
|
||||
if (it->second.frameBuffer && !it->second.frameBuffer->isDealloc) {
|
||||
Log("Target", "%s 渲染完毕 准备Unlock InputFramebuffers:%s",
|
||||
typeid(*this).name(),
|
||||
it->second.frameBuffer->_hashCode.c_str());
|
||||
it->second.frameBuffer->unlock(typeid(*this).name());
|
||||
it->second.frameBuffer = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NS_GI_END
|
66
mediapipe/render/core/Target.hpp
Executable file
66
mediapipe/render/core/Target.hpp
Executable file
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
* GPUImage-x
|
||||
*
|
||||
* Copyright (C) 2017 Yijin Wang, Yiqian Wang
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef Target_hpp
|
||||
#define Target_hpp
|
||||
|
||||
#include "GPUImageMacros.h"
|
||||
#include "Framebuffer.hpp"
|
||||
#include <map>
|
||||
|
||||
NS_GI_BEGIN
|
||||
|
||||
enum RotationMode {
|
||||
NoRotation = 0,
|
||||
RotateLeft,
|
||||
RotateRight,
|
||||
FlipVertical,
|
||||
FlipHorizontal,
|
||||
RotateRightFlipVertical,
|
||||
RotateRightFlipHorizontal,
|
||||
Rotate180
|
||||
};
|
||||
|
||||
class Target : public virtual Ref {
|
||||
public:
|
||||
Target(int inputNumber = 1);
|
||||
virtual ~Target();
|
||||
virtual void setInputFramebuffer(Framebuffer* framebuffer,
|
||||
RotationMode rotationMode = NoRotation,
|
||||
int texIdx = 0,
|
||||
bool ignoreForPrepared = false);
|
||||
virtual bool isPrepared() const;
|
||||
virtual void unPrepear();
|
||||
virtual void update(float frameTime) {};
|
||||
virtual int getNextAvailableTextureIndex() const;
|
||||
//virtual void setInputSizeWithIdx(int width, int height, int textureIdx) {};
|
||||
protected:
|
||||
struct InputFrameBufferInfo {
|
||||
Framebuffer* frameBuffer;
|
||||
RotationMode rotationMode;
|
||||
int texIndex;
|
||||
bool ignoreForPrepare;
|
||||
};
|
||||
|
||||
std::map<int, InputFrameBufferInfo> _inputFramebuffers;
|
||||
int _inputNum;
|
||||
};
|
||||
|
||||
NS_GI_END
|
||||
|
||||
#endif /* Target_hpp */
|
244
mediapipe/render/core/TargetView.cpp
Executable file
244
mediapipe/render/core/TargetView.cpp
Executable file
|
@ -0,0 +1,244 @@
|
|||
/*
|
||||
* GPUImage-x
|
||||
*
|
||||
* Copyright (C) 2017 Yijin Wang, Yiqian Wang
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#if defined(__APPLE__)
|
||||
#include "TargetView.hpp"
|
||||
#include "Context.hpp"
|
||||
#include "GPUImageUtil.h"
|
||||
#include "Filter.hpp"
|
||||
#else
|
||||
#include "GPUImage-x/target/TargetView.hpp"
|
||||
#include "GPUImage-x/Context.hpp"
|
||||
#include "GPUImage-x/util.h"
|
||||
#include "GPUImage-x/filter/Filter.hpp"
|
||||
#endif
|
||||
|
||||
USING_NS_GI
|
||||
|
||||
TargetView::TargetView(Context *context)
|
||||
:_viewWidth(0)
|
||||
,_viewHeight(0)
|
||||
,_fillMode(FillMode::PreserveAspectRatioAndFill)
|
||||
,_displayProgram(0)
|
||||
,_positionAttribLocation(0)
|
||||
,_texCoordAttribLocation(0)
|
||||
,_colorMapUniformLocation(0)
|
||||
,_context(context)
|
||||
{
|
||||
_backgroundColor.r = 0.0;
|
||||
_backgroundColor.g = 0.0;
|
||||
_backgroundColor.b = 0.0;
|
||||
_backgroundColor.a = 0.0;
|
||||
init();
|
||||
}
|
||||
|
||||
TargetView::~TargetView()
|
||||
{
|
||||
if (_displayProgram) {
|
||||
delete _displayProgram;
|
||||
_displayProgram = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void TargetView::init() {
|
||||
_displayProgram = GLProgram::createByShaderString(_context, kDefaultVertexShader, kDefaultDisplayFragmentShader);
|
||||
_positionAttribLocation = _displayProgram->getAttribLocation("position");
|
||||
_texCoordAttribLocation = _displayProgram->getAttribLocation("texCoord");
|
||||
_colorMapUniformLocation = _displayProgram->getUniformLocation("colorMap");
|
||||
_context->setActiveShaderProgram(_displayProgram);
|
||||
CHECK_GL(glEnableVertexAttribArray(_positionAttribLocation));
|
||||
CHECK_GL(glEnableVertexAttribArray(_texCoordAttribLocation));
|
||||
|
||||
};
|
||||
|
||||
void TargetView::setInputFramebuffer(Framebuffer* framebuffer,
|
||||
RotationMode rotationMode/* = NoRotation*/,
|
||||
int texIdx/* = 0*/, bool ignoreForPrepared)
|
||||
{
|
||||
Framebuffer* lastInputFramebuffer = 0;
|
||||
RotationMode lastInputRotation = NoRotation;
|
||||
if (_inputFramebuffers.find(0) != _inputFramebuffers.end()) {
|
||||
lastInputFramebuffer = _inputFramebuffers[0].frameBuffer;
|
||||
lastInputRotation = _inputFramebuffers[0].rotationMode;
|
||||
}
|
||||
|
||||
Target::setInputFramebuffer(framebuffer, rotationMode, texIdx, ignoreForPrepared);
|
||||
|
||||
if (lastInputFramebuffer != framebuffer && framebuffer &&
|
||||
(!lastInputFramebuffer ||
|
||||
!(lastInputFramebuffer->getWidth() == framebuffer->getWidth() &&
|
||||
lastInputFramebuffer->getHeight() == framebuffer->getHeight() &&
|
||||
lastInputRotation == rotationMode)
|
||||
)) {
|
||||
_updateDisplayVertices();
|
||||
}
|
||||
}
|
||||
|
||||
void TargetView::setFillMode(FillMode fillMode) {
|
||||
if (_fillMode != fillMode) {
|
||||
_fillMode = fillMode;
|
||||
_updateDisplayVertices();
|
||||
}
|
||||
}
|
||||
|
||||
void TargetView::onSizeChanged(int width, int height) {
|
||||
if (_viewWidth != width || _viewHeight != height) {
|
||||
_viewWidth = width;
|
||||
_viewHeight = height;
|
||||
_updateDisplayVertices();
|
||||
}
|
||||
}
|
||||
|
||||
void TargetView::update(float frameTime)
|
||||
{
|
||||
CHECK_GL(glBindFramebuffer(GL_FRAMEBUFFER, 0));
|
||||
CHECK_GL(glViewport(0, 0, _viewWidth, _viewHeight));
|
||||
CHECK_GL(glClearColor(_backgroundColor.r, _backgroundColor.g, _backgroundColor.b, _backgroundColor.a));
|
||||
CHECK_GL(glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT));
|
||||
_context->setActiveShaderProgram(_displayProgram);
|
||||
CHECK_GL(glActiveTexture(GL_TEXTURE0));
|
||||
CHECK_GL(glBindTexture(GL_TEXTURE_2D, _inputFramebuffers[0].frameBuffer->getTexture()));
|
||||
CHECK_GL(glUniform1i(_colorMapUniformLocation, 0));
|
||||
CHECK_GL(glVertexAttribPointer(_positionAttribLocation, 2, GL_FLOAT, 0, 0, _displayVertices));
|
||||
CHECK_GL(glVertexAttribPointer(_texCoordAttribLocation, 2, GL_FLOAT, 0, 0, _getTexureCoordinate(_inputFramebuffers[0].rotationMode)));
|
||||
CHECK_GL(glDrawArrays(GL_TRIANGLE_STRIP, 0, 4));
|
||||
}
|
||||
|
||||
void TargetView::_updateDisplayVertices()
|
||||
{
|
||||
if (_inputFramebuffers.find(0) == _inputFramebuffers.end() || _inputFramebuffers[0].frameBuffer == 0) return;
|
||||
|
||||
Framebuffer* inputFramebuffer = _inputFramebuffers[0].frameBuffer;
|
||||
RotationMode inputRotation = _inputFramebuffers[0].rotationMode;
|
||||
|
||||
int rotatedFramebufferWidth = inputFramebuffer->getWidth();
|
||||
int rotatedFramebufferHeight = inputFramebuffer->getHeight();
|
||||
if (rotationSwapsSize(inputRotation))
|
||||
{
|
||||
rotatedFramebufferWidth = inputFramebuffer->getHeight();
|
||||
rotatedFramebufferHeight = inputFramebuffer->getWidth();
|
||||
}
|
||||
|
||||
float framebufferAspectRatio = rotatedFramebufferHeight / (float)rotatedFramebufferWidth;
|
||||
float viewAspectRatio = _viewHeight / (float)_viewWidth;
|
||||
|
||||
float insetFramebufferWidth = 0.0;
|
||||
float insetFramebufferHeight = 0.0;
|
||||
if (framebufferAspectRatio > viewAspectRatio) {
|
||||
insetFramebufferWidth = _viewHeight / (float)rotatedFramebufferHeight * rotatedFramebufferWidth;
|
||||
insetFramebufferHeight = _viewHeight;
|
||||
} else {
|
||||
insetFramebufferWidth = _viewWidth;
|
||||
insetFramebufferHeight = _viewWidth / (float)rotatedFramebufferWidth * rotatedFramebufferHeight;
|
||||
}
|
||||
|
||||
float scaledWidth = 1.0;
|
||||
float scaledHeight = 1.0;
|
||||
if (_fillMode == FillMode::PreserveAspectRatio) {
|
||||
scaledWidth = insetFramebufferWidth / _viewWidth;
|
||||
scaledHeight = insetFramebufferHeight / _viewHeight;
|
||||
} else if (_fillMode == FillMode::PreserveAspectRatioAndFill) {
|
||||
scaledWidth = _viewHeight/ insetFramebufferHeight;
|
||||
scaledHeight = _viewWidth / insetFramebufferWidth;
|
||||
}
|
||||
|
||||
_displayVertices[0] = -scaledWidth;
|
||||
_displayVertices[1] = -scaledHeight;
|
||||
_displayVertices[2] = scaledWidth;
|
||||
_displayVertices[3] = -scaledHeight;
|
||||
_displayVertices[4] = -scaledWidth;
|
||||
_displayVertices[5] = scaledHeight;
|
||||
_displayVertices[6] = scaledWidth;
|
||||
_displayVertices[7] = scaledHeight;
|
||||
|
||||
}
|
||||
|
||||
const GLfloat* TargetView::_getTexureCoordinate(RotationMode rotationMode)
|
||||
{
|
||||
static const GLfloat noRotationTextureCoordinates[] = {
|
||||
0.0f, 1.0f,
|
||||
1.0f, 1.0f,
|
||||
0.0f, 0.0f,
|
||||
1.0f, 0.0f,
|
||||
};
|
||||
|
||||
static const GLfloat rotateRightTextureCoordinates[] = {
|
||||
1.0f, 1.0f,
|
||||
1.0f, 0.0f,
|
||||
0.0f, 1.0f,
|
||||
0.0f, 0.0f,
|
||||
};
|
||||
|
||||
static const GLfloat rotateLeftTextureCoordinates[] = {
|
||||
0.0f, 0.0f,
|
||||
0.0f, 1.0f,
|
||||
1.0f, 0.0f,
|
||||
1.0f, 1.0f,
|
||||
};
|
||||
|
||||
static const GLfloat verticalFlipTextureCoordinates[] = {
|
||||
0.0f, 0.0f,
|
||||
1.0f, 0.0f,
|
||||
0.0f, 1.0f,
|
||||
1.0f, 1.0f,
|
||||
};
|
||||
|
||||
static const GLfloat horizontalFlipTextureCoordinates[] = {
|
||||
1.0f, 1.0f,
|
||||
0.0f, 1.0f,
|
||||
1.0f, 0.0f,
|
||||
0.0f, 0.0f,
|
||||
};
|
||||
|
||||
static const GLfloat rotateRightVerticalFlipTextureCoordinates[] = {
|
||||
1.0f, 0.0f,
|
||||
1.0f, 1.0f,
|
||||
0.0f, 0.0f,
|
||||
0.0f, 1.0f,
|
||||
};
|
||||
|
||||
static const GLfloat rotateRightHorizontalFlipTextureCoordinates[] = {
|
||||
0.0f, 1.0f,
|
||||
0.0f, 0.0f,
|
||||
1.0f, 1.0f,
|
||||
1.0f, 0.0f,
|
||||
};
|
||||
|
||||
static const GLfloat rotate180TextureCoordinates[] = {
|
||||
1.0f, 0.0f,
|
||||
0.0f, 0.0f,
|
||||
1.0f, 1.0f,
|
||||
0.0f, 1.0f,
|
||||
};
|
||||
|
||||
switch(rotationMode)
|
||||
{
|
||||
case NoRotation: return noRotationTextureCoordinates;
|
||||
case RotateLeft: return rotateLeftTextureCoordinates;
|
||||
case RotateRight: return rotateRightTextureCoordinates;
|
||||
case FlipVertical: return verticalFlipTextureCoordinates;
|
||||
case FlipHorizontal: return horizontalFlipTextureCoordinates;
|
||||
case RotateRightFlipVertical: return rotateRightVerticalFlipTextureCoordinates;
|
||||
case RotateRightFlipHorizontal: return rotateRightHorizontalFlipTextureCoordinates;
|
||||
case Rotate180: return rotate180TextureCoordinates;
|
||||
}
|
||||
}
|
||||
GLuint TargetView::getProgram()
|
||||
{
|
||||
return _displayProgram->getID();
|
||||
}
|
75
mediapipe/render/core/TargetView.hpp
Executable file
75
mediapipe/render/core/TargetView.hpp
Executable file
|
@ -0,0 +1,75 @@
|
|||
/*
|
||||
* GPUImage-x
|
||||
*
|
||||
* Copyright (C) 2017 Yijin Wang, Yiqian Wang
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef GPUIMAGE_X_TARGETVIEW_H
|
||||
#define GPUIMAGE_X_TARGETVIEW_H
|
||||
|
||||
#include "Target.hpp"
|
||||
#if defined(__APPLE__)
|
||||
#include "GLProgram.hpp"
|
||||
#else
|
||||
#include "GPUImage-x/GLProgram.hpp"
|
||||
#endif
|
||||
|
||||
NS_GI_BEGIN
|
||||
class Context;
|
||||
class TargetView : public Target {
|
||||
public:
|
||||
enum FillMode {
|
||||
Stretch = 0, // Stretch to fill the view, and may distort the image
|
||||
PreserveAspectRatio = 1, // preserve the aspect ratio of the image
|
||||
PreserveAspectRatioAndFill = 2 // preserve the aspect ratio, and zoom in to fill the view
|
||||
};
|
||||
|
||||
public:
|
||||
TargetView(Context *context);
|
||||
~TargetView();
|
||||
|
||||
void init();
|
||||
virtual void setInputFramebuffer(Framebuffer* framebuffer, RotationMode rotationMode = NoRotation,
|
||||
int texIdx = 0, bool ignoreForPrepared = false) override;
|
||||
void setFillMode(FillMode fillMode);
|
||||
void onSizeChanged(int width, int height);
|
||||
int getViewWidth(){return _viewWidth;};
|
||||
int getViewHeight(){return _viewHeight;};
|
||||
virtual void update(float frameTime) override;
|
||||
GLuint getProgram();
|
||||
private:
|
||||
int _viewWidth;
|
||||
int _viewHeight;
|
||||
FillMode _fillMode;
|
||||
GLProgram* _displayProgram;
|
||||
GLuint _positionAttribLocation;
|
||||
GLuint _texCoordAttribLocation;
|
||||
GLuint _colorMapUniformLocation;
|
||||
|
||||
struct {
|
||||
float r; float g; float b; float a;
|
||||
} _backgroundColor;
|
||||
|
||||
GLfloat _displayVertices[8];
|
||||
|
||||
void _updateDisplayVertices();
|
||||
const GLfloat* _getTexureCoordinate(RotationMode rotationMode);
|
||||
|
||||
Context *_context;
|
||||
};
|
||||
|
||||
NS_GI_END
|
||||
|
||||
#endif //GPUIMAGE_X_TARGETVIEW_H
|
869
mediapipe/render/core/math.cpp
Executable file
869
mediapipe/render/core/math.cpp
Executable file
|
@ -0,0 +1,869 @@
|
|||
/*
|
||||
* GPUImage-x
|
||||
*
|
||||
* Copyright (C) 2017 Yijin Wang, Yiqian Wang
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "math.hpp"
|
||||
#include <string>
|
||||
#include <assert.h>
|
||||
#include <math.h>
|
||||
|
||||
NS_GI_BEGIN
|
||||
|
||||
Vector4::Vector4()
|
||||
: x(0.0f), y(0.0f), z(0.0f), w(0.0f) {
|
||||
|
||||
}
|
||||
|
||||
bool Vector4::operator!=(const Vector4& v) const
|
||||
{
|
||||
return x!=v.x || y!=v.y || z!=v.z || w!=v.w;
|
||||
}
|
||||
|
||||
Vector2::Vector2()
|
||||
: x(0.0f), y(0.0f)
|
||||
{
|
||||
}
|
||||
|
||||
Vector2::Vector2(float xx, float yy)
|
||||
: x(xx), y(yy)
|
||||
{
|
||||
}
|
||||
|
||||
Vector2::Vector2(const float* array)
|
||||
{
|
||||
set(array);
|
||||
}
|
||||
|
||||
Vector2::Vector2(const Vector2& p1, const Vector2& p2)
|
||||
{
|
||||
set(p1, p2);
|
||||
}
|
||||
|
||||
Vector2::Vector2(const Vector2& copy)
|
||||
{
|
||||
set(copy);
|
||||
}
|
||||
|
||||
Vector2::~Vector2()
|
||||
{
|
||||
}
|
||||
|
||||
bool Vector2::isZero() const
|
||||
{
|
||||
return x == 0.0f && y == 0.0f;
|
||||
}
|
||||
|
||||
bool Vector2::isOne() const
|
||||
{
|
||||
return x == 1.0f && y == 1.0f;
|
||||
}
|
||||
|
||||
float Vector2::angle(const Vector2& v1, const Vector2& v2)
|
||||
{
|
||||
float dz = v1.x * v2.y - v1.y * v2.x;
|
||||
return atan2f(fabsf(dz) + 2e-37f, dot(v1, v2));
|
||||
}
|
||||
|
||||
void Vector2::add(const Vector2& v)
|
||||
{
|
||||
x += v.x;
|
||||
y += v.y;
|
||||
}
|
||||
|
||||
float Vector2::distance(const Vector2& v) const
|
||||
{
|
||||
float dx = v.x - x;
|
||||
float dy = v.y - y;
|
||||
return sqrt(dx * dx + dy * dy);
|
||||
}
|
||||
|
||||
float Vector2::distanceSquared(const Vector2& v) const
|
||||
{
|
||||
float dx = v.x - x;
|
||||
float dy = v.y - y;
|
||||
return (dx * dx + dy * dy);
|
||||
}
|
||||
|
||||
Vector2 Vector2::getCenter(const Vector2& v) const
|
||||
{
|
||||
return Vector2((x + v.x ) / 2, (y + v.y ) / 2);
|
||||
}
|
||||
|
||||
float Vector2::dot(const Vector2& v) const
|
||||
{
|
||||
return (x * v.x + y * v.y);
|
||||
}
|
||||
|
||||
float Vector2::dot(const Vector2& v1, const Vector2& v2)
|
||||
{
|
||||
return v1.dot(v2);
|
||||
}
|
||||
|
||||
float Vector2::lengthSquared() const
|
||||
{
|
||||
return (x * x + y * y);
|
||||
}
|
||||
|
||||
void Vector2::negate()
|
||||
{
|
||||
x = -x;
|
||||
y = -y;
|
||||
}
|
||||
|
||||
void Vector2::normalize()
|
||||
{
|
||||
float n = x * x + y * y;
|
||||
// Already normalized.
|
||||
if (n == 1.0f)
|
||||
return;
|
||||
|
||||
n = sqrt(n);
|
||||
// Too close to zero.
|
||||
if (n < 2e-37f)
|
||||
return;
|
||||
|
||||
n = 1.0f / n;
|
||||
x *= n;
|
||||
y *= n;
|
||||
}
|
||||
|
||||
void Vector2::scale(float scalar)
|
||||
{
|
||||
x *= scalar;
|
||||
y *= scalar;
|
||||
}
|
||||
|
||||
void Vector2::scale(const Vector2& scale)
|
||||
{
|
||||
x *= scale.x;
|
||||
y *= scale.y;
|
||||
}
|
||||
|
||||
void Vector2::set(float xx, float yy)
|
||||
{
|
||||
this->x = xx;
|
||||
this->y = yy;
|
||||
}
|
||||
|
||||
void Vector2::set(const Vector2& v)
|
||||
{
|
||||
this->x = v.x;
|
||||
this->y = v.y;
|
||||
}
|
||||
|
||||
void Vector2::set(const Vector2& p1, const Vector2& p2)
|
||||
{
|
||||
x = p2.x - p1.x;
|
||||
y = p2.y - p1.y;
|
||||
}
|
||||
|
||||
void Vector2::setZero()
|
||||
{
|
||||
x = y = 0.0f;
|
||||
}
|
||||
|
||||
void Vector2::subtract(const Vector2& v)
|
||||
{
|
||||
x -= v.x;
|
||||
y -= v.y;
|
||||
}
|
||||
|
||||
void Vector2::smooth(const Vector2& target, float elapsedTime, float responseTime)
|
||||
{
|
||||
if (elapsedTime > 0)
|
||||
{
|
||||
*this += (target - *this) * (elapsedTime / (elapsedTime + responseTime));
|
||||
}
|
||||
}
|
||||
|
||||
const Vector2 Vector2::operator+(const Vector2& v) const
|
||||
{
|
||||
Vector2 result(*this);
|
||||
result.add(v);
|
||||
return result;
|
||||
}
|
||||
|
||||
Vector2& Vector2::operator+=(const Vector2& v)
|
||||
{
|
||||
add(v);
|
||||
return *this;
|
||||
}
|
||||
|
||||
const Vector2 Vector2::operator-(const Vector2& v) const
|
||||
{
|
||||
Vector2 result(*this);
|
||||
result.subtract(v);
|
||||
return result;
|
||||
}
|
||||
|
||||
Vector2& Vector2::operator-=(const Vector2& v)
|
||||
{
|
||||
subtract(v);
|
||||
return *this;
|
||||
}
|
||||
|
||||
const Vector2 Vector2::operator-() const
|
||||
{
|
||||
Vector2 result(*this);
|
||||
result.negate();
|
||||
return result;
|
||||
}
|
||||
|
||||
const Vector2 Vector2::operator*(float s) const
|
||||
{
|
||||
Vector2 result(*this);
|
||||
result.scale(s);
|
||||
return result;
|
||||
}
|
||||
|
||||
Vector2& Vector2::operator*=(float s)
|
||||
{
|
||||
scale(s);
|
||||
return *this;
|
||||
}
|
||||
|
||||
const Vector2 Vector2::operator/(const float s) const
|
||||
{
|
||||
return Vector2(this->x / s, this->y / s);
|
||||
}
|
||||
|
||||
bool Vector2::operator<(const Vector2& v) const
|
||||
{
|
||||
if (x == v.x)
|
||||
{
|
||||
return y < v.y;
|
||||
}
|
||||
return x < v.x;
|
||||
}
|
||||
|
||||
bool Vector2::operator>(const Vector2& v) const
|
||||
{
|
||||
if (x == v.x)
|
||||
{
|
||||
return y > v.y;
|
||||
}
|
||||
return x > v.x;
|
||||
}
|
||||
|
||||
bool Vector2::operator==(const Vector2& v) const
|
||||
{
|
||||
return x==v.x && y==v.y;
|
||||
}
|
||||
|
||||
bool Vector2::operator!=(const Vector2& v) const
|
||||
{
|
||||
return x!=v.x || y!=v.y;
|
||||
}
|
||||
|
||||
const Vector2 operator*(float x, const Vector2& v)
|
||||
{
|
||||
Vector2 result(v);
|
||||
result.scale(x);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
const Matrix4 Matrix4::IDENTITY = Matrix4(
|
||||
1.0f, 0.0f, 0.0f, 0.0f,
|
||||
0.0f, 1.0f, 0.0f, 0.0f,
|
||||
0.0f, 0.0f, 1.0f, 0.0f,
|
||||
0.0f, 0.0f, 0.0f, 1.0f);
|
||||
|
||||
Matrix4::Matrix4() {
|
||||
*this = IDENTITY;
|
||||
}
|
||||
|
||||
Matrix4::Matrix4(const float* mat) {
|
||||
set(mat);
|
||||
}
|
||||
|
||||
Matrix4::Matrix4(float m11, float m12, float m13, float m14, float m21, float m22, float m23,float m24, float m31, float m32, float m33, float m34, float m41, float m42, float m43, float m44) {
|
||||
set(m11, m12, m13, m14, m21, m22, m23, m24, m31, m32, m33, m34, m41, m42, m43, m44);
|
||||
}
|
||||
|
||||
Matrix4::Matrix4(const Matrix4& copy) {
|
||||
memcpy(m, copy.m, sizeof(float) * 16);
|
||||
}
|
||||
|
||||
Matrix4::~Matrix4() {
|
||||
|
||||
}
|
||||
|
||||
void Matrix4::set(float m11, float m12, float m13, float m14, float m21, float m22, float m23, float m24, float m31, float m32, float m33, float m34, float m41, float m42, float m43, float m44) {
|
||||
m[0] = m11;
|
||||
m[1] = m21;
|
||||
m[2] = m31;
|
||||
m[3] = m41;
|
||||
m[4] = m12;
|
||||
m[5] = m22;
|
||||
m[6] = m32;
|
||||
m[7] = m42;
|
||||
m[8] = m13;
|
||||
m[9] = m23;
|
||||
m[10] = m33;
|
||||
m[11] = m43;
|
||||
m[12] = m14;
|
||||
m[13] = m24;
|
||||
m[14] = m34;
|
||||
m[15] = m44;
|
||||
}
|
||||
|
||||
void Matrix4::set(const float* mat) {
|
||||
assert(mat);
|
||||
memcpy(this->m, mat, sizeof(float) * 16);
|
||||
}
|
||||
|
||||
void Matrix4::set(const Matrix4& mat) {
|
||||
memcpy(this->m, mat.m, sizeof(float) * 16);
|
||||
}
|
||||
|
||||
void Matrix4::setIdentity() {
|
||||
memcpy(m, &IDENTITY, sizeof(float) * 16);
|
||||
}
|
||||
|
||||
void Matrix4::negate()
|
||||
{
|
||||
m[0] = -m[0];
|
||||
m[1] = -m[1];
|
||||
m[2] = -m[2];
|
||||
m[3] = -m[3];
|
||||
m[4] = -m[4];
|
||||
m[5] = -m[5];
|
||||
m[6] = -m[6];
|
||||
m[7] = -m[7];
|
||||
m[8] = -m[8];
|
||||
m[9] = -m[9];
|
||||
m[10] = -m[10];
|
||||
m[11] = -m[11];
|
||||
m[12] = -m[12];
|
||||
m[13] = -m[13];
|
||||
m[14] = -m[14];
|
||||
m[15] = -m[15];
|
||||
}
|
||||
|
||||
Matrix4 Matrix4::getNegated() const
|
||||
{
|
||||
Matrix4 mat(*this);
|
||||
mat.negate();
|
||||
return mat;
|
||||
}
|
||||
|
||||
void Matrix4::transpose() {
|
||||
float tmp;
|
||||
tmp = m[1]; m[1] = m[4]; m[4] = tmp;
|
||||
tmp = m[2]; m[2] = m[8]; m[8] = tmp;
|
||||
tmp = m[6]; m[6] = m[9]; m[9] = tmp;
|
||||
tmp = m[3]; m[3] = m[12]; m[12] = tmp;
|
||||
tmp = m[7]; m[7] = m[13]; m[13] = tmp;
|
||||
tmp = m[11]; m[11] = m[14]; m[14] = tmp;
|
||||
}
|
||||
|
||||
Matrix4 Matrix4::getTransposed() const {
|
||||
Matrix4 mat(*this);
|
||||
mat.transpose();
|
||||
return mat;
|
||||
}
|
||||
|
||||
void Matrix4::add(float scalar)
|
||||
{
|
||||
add(scalar, this);
|
||||
}
|
||||
|
||||
void Matrix4::add(float scalar, Matrix4* dst) const
|
||||
{
|
||||
assert(dst);
|
||||
dst->m[0] = this->m[0] + scalar;
|
||||
dst->m[1] = this->m[1] + scalar;
|
||||
dst->m[2] = this->m[2] + scalar;
|
||||
dst->m[3] = this->m[3] + scalar;
|
||||
dst->m[4] = this->m[4] + scalar;
|
||||
dst->m[5] = this->m[5] + scalar;
|
||||
dst->m[6] = this->m[6] + scalar;
|
||||
dst->m[7] = this->m[7] + scalar;
|
||||
dst->m[8] = this->m[8] + scalar;
|
||||
dst->m[9] = this->m[9] + scalar;
|
||||
dst->m[10] = this->m[10] + scalar;
|
||||
dst->m[11] = this->m[11] + scalar;
|
||||
dst->m[12] = this->m[12] + scalar;
|
||||
dst->m[13] = this->m[13] + scalar;
|
||||
dst->m[14] = this->m[14] + scalar;
|
||||
dst->m[15] = this->m[15] + scalar;
|
||||
}
|
||||
|
||||
void Matrix4::add(const Matrix4& mat)
|
||||
{
|
||||
add(*this, mat, this);
|
||||
}
|
||||
|
||||
void Matrix4::add(const Matrix4& m1, const Matrix4& m2, Matrix4* dst)
|
||||
{
|
||||
assert(dst);
|
||||
dst->m[0] = m1.m[0] + m2.m[0];
|
||||
dst->m[1] = m1.m[1] + m2.m[1];
|
||||
dst->m[2] = m1.m[2] + m2.m[2];
|
||||
dst->m[3] = m1.m[3] + m2.m[3];
|
||||
dst->m[4] = m1.m[4] + m2.m[4];
|
||||
dst->m[5] = m1.m[5] + m2.m[5];
|
||||
dst->m[6] = m1.m[6] + m2.m[6];
|
||||
dst->m[7] = m1.m[7] + m2.m[7];
|
||||
dst->m[8] = m1.m[8] + m2.m[8];
|
||||
dst->m[9] = m1.m[9] + m2.m[9];
|
||||
dst->m[10] = m1.m[10] + m2.m[10];
|
||||
dst->m[11] = m1.m[11] + m2.m[11];
|
||||
dst->m[12] = m1.m[12] + m2.m[12];
|
||||
dst->m[13] = m1.m[13] + m2.m[13];
|
||||
dst->m[14] = m1.m[14] + m2.m[14];
|
||||
dst->m[15] = m1.m[15] + m2.m[15];
|
||||
}
|
||||
|
||||
void Matrix4::subtract(const Matrix4& mat)
|
||||
{
|
||||
subtract(*this, mat, this);
|
||||
}
|
||||
|
||||
void Matrix4::subtract(const Matrix4& m1, const Matrix4& m2, Matrix4* dst)
|
||||
{
|
||||
assert(dst);
|
||||
dst->m[0] = m1.m[0] - m2.m[0];
|
||||
dst->m[1] = m1.m[1] - m2.m[1];
|
||||
dst->m[2] = m1.m[2] - m2.m[2];
|
||||
dst->m[3] = m1.m[3] - m2.m[3];
|
||||
dst->m[4] = m1.m[4] - m2.m[4];
|
||||
dst->m[5] = m1.m[5] - m2.m[5];
|
||||
dst->m[6] = m1.m[6] - m2.m[6];
|
||||
dst->m[7] = m1.m[7] - m2.m[7];
|
||||
dst->m[8] = m1.m[8] - m2.m[8];
|
||||
dst->m[9] = m1.m[9] - m2.m[9];
|
||||
dst->m[10] = m1.m[10] - m2.m[10];
|
||||
dst->m[11] = m1.m[11] - m2.m[11];
|
||||
dst->m[12] = m1.m[12] - m2.m[12];
|
||||
dst->m[13] = m1.m[13] - m2.m[13];
|
||||
dst->m[14] = m1.m[14] - m2.m[14];
|
||||
dst->m[15] = m1.m[15] - m2.m[15];
|
||||
}
|
||||
|
||||
void Matrix4::multiply(float scalar)
|
||||
{
|
||||
multiply(scalar, this);
|
||||
}
|
||||
|
||||
void Matrix4::multiply(float scalar, Matrix4* dst) const
|
||||
{
|
||||
multiply(*this, scalar, dst);
|
||||
}
|
||||
|
||||
void Matrix4::multiply(const Matrix4& mat, float scalar, Matrix4* dst)
|
||||
{
|
||||
assert(dst);
|
||||
dst->m[0] = mat.m[0] * scalar;
|
||||
dst->m[1] = mat.m[1] * scalar;
|
||||
dst->m[2] = mat.m[2] * scalar;
|
||||
dst->m[3] = mat.m[3] * scalar;
|
||||
dst->m[4] = mat.m[4] * scalar;
|
||||
dst->m[5] = mat.m[5] * scalar;
|
||||
dst->m[6] = mat.m[6] * scalar;
|
||||
dst->m[7] = mat.m[7] * scalar;
|
||||
dst->m[8] = mat.m[8] * scalar;
|
||||
dst->m[9] = mat.m[9] * scalar;
|
||||
dst->m[10] = mat.m[10] * scalar;
|
||||
dst->m[11] = mat.m[11] * scalar;
|
||||
dst->m[12] = mat.m[12] * scalar;
|
||||
dst->m[13] = mat.m[13] * scalar;
|
||||
dst->m[14] = mat.m[14] * scalar;
|
||||
dst->m[15] = mat.m[15] * scalar;
|
||||
}
|
||||
|
||||
void Matrix4::multiply(const Matrix4& mat)
|
||||
{
|
||||
multiply(*this, mat, this);
|
||||
}
|
||||
|
||||
void Matrix4::multiply(const Matrix4& m1, const Matrix4& m2, Matrix4* dst)
|
||||
{
|
||||
assert(dst);
|
||||
dst->m[0] = m1.m[0] * m2.m[0];
|
||||
dst->m[1] = m1.m[1] * m2.m[1];
|
||||
dst->m[2] = m1.m[2] * m2.m[2];
|
||||
dst->m[3] = m1.m[3] * m2.m[3];
|
||||
dst->m[4] = m1.m[4] * m2.m[4];
|
||||
dst->m[5] = m1.m[5] * m2.m[5];
|
||||
dst->m[6] = m1.m[6] * m2.m[6];
|
||||
dst->m[7] = m1.m[7] * m2.m[7];
|
||||
dst->m[8] = m1.m[8] * m2.m[8];
|
||||
dst->m[9] = m1.m[9] * m2.m[9];
|
||||
dst->m[10] = m1.m[10] * m2.m[10];
|
||||
dst->m[11] = m1.m[11] * m2.m[11];
|
||||
dst->m[12] = m1.m[12] * m2.m[12];
|
||||
dst->m[13] = m1.m[13] * m2.m[13];
|
||||
dst->m[14] = m1.m[14] * m2.m[14];
|
||||
dst->m[15] = m1.m[15] * m2.m[15];
|
||||
}
|
||||
|
||||
const Matrix4 Matrix4::operator+(const Matrix4& mat) const
|
||||
{
|
||||
Matrix4 result(*this);
|
||||
result.add(mat);
|
||||
return result;
|
||||
}
|
||||
|
||||
Matrix4& Matrix4::operator+=(const Matrix4& mat)
|
||||
{
|
||||
add(mat);
|
||||
return *this;
|
||||
}
|
||||
|
||||
const Matrix4 Matrix4::operator-(const Matrix4& mat) const
|
||||
{
|
||||
Matrix4 result(*this);
|
||||
result.subtract(mat);
|
||||
return result;
|
||||
}
|
||||
|
||||
Matrix4& Matrix4::operator-=(const Matrix4& mat)
|
||||
{
|
||||
subtract(mat);
|
||||
return *this;
|
||||
}
|
||||
|
||||
const Matrix4 Matrix4::operator-() const
|
||||
{
|
||||
Matrix4 mat(*this);
|
||||
mat.negate();
|
||||
return mat;
|
||||
}
|
||||
|
||||
const Matrix4 Matrix4::operator*(const Matrix4& mat) const
|
||||
{
|
||||
Matrix4 result(*this);
|
||||
result.multiply(mat);
|
||||
return result;
|
||||
}
|
||||
|
||||
Matrix4& Matrix4::operator*=(const Matrix4& mat)
|
||||
{
|
||||
multiply(mat);
|
||||
return *this;
|
||||
}
|
||||
|
||||
const Matrix4 Matrix4::operator+(float scalar) const
|
||||
{
|
||||
Matrix4 result(*this);
|
||||
result.add(scalar);
|
||||
return result;
|
||||
}
|
||||
|
||||
Matrix4& Matrix4::operator+=(float scalar)
|
||||
{
|
||||
add(scalar);
|
||||
return *this;
|
||||
}
|
||||
|
||||
const Matrix4 Matrix4::operator-(float scalar) const
|
||||
{
|
||||
Matrix4 result(*this);
|
||||
result.add(-scalar);
|
||||
return result;
|
||||
}
|
||||
|
||||
Matrix4& Matrix4::operator-=(float scalar)
|
||||
{
|
||||
add(-scalar);
|
||||
return *this;
|
||||
}
|
||||
|
||||
const Matrix4 Matrix4::operator*(float scalar) const
|
||||
{
|
||||
Matrix4 result(*this);
|
||||
result.multiply(scalar);
|
||||
return result;
|
||||
}
|
||||
|
||||
Matrix4& Matrix4::operator*=(float scalar)
|
||||
{
|
||||
multiply(scalar);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
const Matrix3 Matrix3::IDENTITY = Matrix3(
|
||||
1.0f, 0.0f, 0.0f,
|
||||
0.0f, 1.0f, 0.0f,
|
||||
0.0f, 0.0f, 1.0f);
|
||||
Matrix3::Matrix3() {
|
||||
*this = IDENTITY;
|
||||
}
|
||||
|
||||
Matrix3::Matrix3(const float* mat) {
|
||||
set(mat);
|
||||
}
|
||||
|
||||
Matrix3::Matrix3(float m11, float m12, float m13, float m21, float m22, float m23, float m31, float m32, float m33) {
|
||||
set(m11, m12, m13, m21, m22, m23, m31, m32, m33);
|
||||
}
|
||||
|
||||
Matrix3::Matrix3(const Matrix3& copy) {
|
||||
memcpy(m, copy.m, sizeof(float) * 9);
|
||||
}
|
||||
|
||||
Matrix3::~Matrix3() {
|
||||
|
||||
}
|
||||
|
||||
void Matrix3::set(float m11, float m12, float m13, float m21, float m22, float m23, float m31, float m32, float m33) {
|
||||
m[0] = m11;
|
||||
m[1] = m21;
|
||||
m[2] = m31;
|
||||
m[3] = m12;
|
||||
m[4] = m22;
|
||||
m[5] = m32;
|
||||
m[6] = m13;
|
||||
m[7] = m23;
|
||||
m[8] = m33;
|
||||
}
|
||||
|
||||
void Matrix3::set(const float* mat) {
|
||||
assert(mat);
|
||||
memcpy(this->m, mat, sizeof(float) * 9);
|
||||
}
|
||||
|
||||
void Matrix3::set(const Matrix3& mat) {
|
||||
memcpy(this->m, mat.m, sizeof(float) * 9);
|
||||
}
|
||||
|
||||
void Matrix3::setIdentity() {
|
||||
memcpy(m, &IDENTITY, sizeof(float) * 9);
|
||||
}
|
||||
|
||||
void Matrix3::negate()
|
||||
{
|
||||
m[0] = -m[0];
|
||||
m[1] = -m[1];
|
||||
m[2] = -m[2];
|
||||
m[3] = -m[3];
|
||||
m[4] = -m[4];
|
||||
m[5] = -m[5];
|
||||
m[6] = -m[6];
|
||||
m[7] = -m[7];
|
||||
m[8] = -m[8];
|
||||
}
|
||||
|
||||
Matrix3 Matrix3::getNegated() const
|
||||
{
|
||||
Matrix3 mat(*this);
|
||||
mat.negate();
|
||||
return mat;
|
||||
}
|
||||
|
||||
void Matrix3::transpose() {
|
||||
float tmp;
|
||||
tmp = m[1]; m[1] = m[3]; m[3] = tmp;
|
||||
tmp = m[2]; m[2] = m[6]; m[6] = tmp;
|
||||
tmp = m[5]; m[5] = m[7]; m[7] = tmp;
|
||||
}
|
||||
|
||||
Matrix3 Matrix3::getTransposed() const {
|
||||
Matrix3 mat(*this);
|
||||
mat.transpose();
|
||||
return mat;
|
||||
}
|
||||
|
||||
void Matrix3::add(float scalar)
|
||||
{
|
||||
add(scalar, this);
|
||||
}
|
||||
|
||||
void Matrix3::add(float scalar, Matrix3* dst) const
|
||||
{
|
||||
assert(dst);
|
||||
dst->m[0] = this->m[0] + scalar;
|
||||
dst->m[1] = this->m[1] + scalar;
|
||||
dst->m[2] = this->m[2] + scalar;
|
||||
dst->m[3] = this->m[3] + scalar;
|
||||
dst->m[4] = this->m[4] + scalar;
|
||||
dst->m[5] = this->m[5] + scalar;
|
||||
dst->m[6] = this->m[6] + scalar;
|
||||
dst->m[7] = this->m[7] + scalar;
|
||||
dst->m[8] = this->m[8] + scalar;
|
||||
}
|
||||
|
||||
void Matrix3::add(const Matrix3& mat)
|
||||
{
|
||||
add(*this, mat, this);
|
||||
}
|
||||
|
||||
void Matrix3::add(const Matrix3& m1, const Matrix3& m2, Matrix3* dst)
|
||||
{
|
||||
assert(dst);
|
||||
dst->m[0] = m1.m[0] + m2.m[0];
|
||||
dst->m[1] = m1.m[1] + m2.m[1];
|
||||
dst->m[2] = m1.m[2] + m2.m[2];
|
||||
dst->m[3] = m1.m[3] + m2.m[3];
|
||||
dst->m[4] = m1.m[4] + m2.m[4];
|
||||
dst->m[5] = m1.m[5] + m2.m[5];
|
||||
dst->m[6] = m1.m[6] + m2.m[6];
|
||||
dst->m[7] = m1.m[7] + m2.m[7];
|
||||
dst->m[8] = m1.m[8] + m2.m[8];
|
||||
}
|
||||
|
||||
void Matrix3::subtract(const Matrix3& mat)
|
||||
{
|
||||
subtract(*this, mat, this);
|
||||
}
|
||||
|
||||
void Matrix3::subtract(const Matrix3& m1, const Matrix3& m2, Matrix3* dst)
|
||||
{
|
||||
assert(dst);
|
||||
dst->m[0] = m1.m[0] - m2.m[0];
|
||||
dst->m[1] = m1.m[1] - m2.m[1];
|
||||
dst->m[2] = m1.m[2] - m2.m[2];
|
||||
dst->m[3] = m1.m[3] - m2.m[3];
|
||||
dst->m[4] = m1.m[4] - m2.m[4];
|
||||
dst->m[5] = m1.m[5] - m2.m[5];
|
||||
dst->m[6] = m1.m[6] - m2.m[6];
|
||||
dst->m[7] = m1.m[7] - m2.m[7];
|
||||
dst->m[8] = m1.m[8] - m2.m[8];
|
||||
}
|
||||
|
||||
void Matrix3::multiply(float scalar)
|
||||
{
|
||||
multiply(scalar, this);
|
||||
}
|
||||
|
||||
void Matrix3::multiply(float scalar, Matrix3* dst) const
|
||||
{
|
||||
multiply(*this, scalar, dst);
|
||||
}
|
||||
|
||||
void Matrix3::multiply(const Matrix3& mat, float scalar, Matrix3* dst)
|
||||
{
|
||||
assert(dst);
|
||||
dst->m[0] = mat.m[0] * scalar;
|
||||
dst->m[1] = mat.m[1] * scalar;
|
||||
dst->m[2] = mat.m[2] * scalar;
|
||||
dst->m[3] = mat.m[3] * scalar;
|
||||
dst->m[4] = mat.m[4] * scalar;
|
||||
dst->m[5] = mat.m[5] * scalar;
|
||||
dst->m[6] = mat.m[6] * scalar;
|
||||
dst->m[7] = mat.m[7] * scalar;
|
||||
dst->m[8] = mat.m[8] * scalar;
|
||||
}
|
||||
|
||||
void Matrix3::multiply(const Matrix3& mat)
|
||||
{
|
||||
multiply(*this, mat, this);
|
||||
}
|
||||
|
||||
void Matrix3::multiply(const Matrix3& m1, const Matrix3& m2, Matrix3* dst)
|
||||
{
|
||||
assert(dst);
|
||||
dst->m[0] = m1.m[0] * m2.m[0];
|
||||
dst->m[1] = m1.m[1] * m2.m[1];
|
||||
dst->m[2] = m1.m[2] * m2.m[2];
|
||||
dst->m[3] = m1.m[3] * m2.m[3];
|
||||
dst->m[4] = m1.m[4] * m2.m[4];
|
||||
dst->m[5] = m1.m[5] * m2.m[5];
|
||||
dst->m[6] = m1.m[6] * m2.m[6];
|
||||
dst->m[7] = m1.m[7] * m2.m[7];
|
||||
dst->m[8] = m1.m[8] * m2.m[8];
|
||||
}
|
||||
|
||||
const Matrix3 Matrix3::operator+(const Matrix3& mat) const
|
||||
{
|
||||
Matrix3 result(*this);
|
||||
result.add(mat);
|
||||
return result;
|
||||
}
|
||||
|
||||
Matrix3& Matrix3::operator+=(const Matrix3& mat)
|
||||
{
|
||||
add(mat);
|
||||
return *this;
|
||||
}
|
||||
|
||||
const Matrix3 Matrix3::operator-(const Matrix3& mat) const
|
||||
{
|
||||
Matrix3 result(*this);
|
||||
result.subtract(mat);
|
||||
return result;
|
||||
}
|
||||
|
||||
Matrix3& Matrix3::operator-=(const Matrix3& mat)
|
||||
{
|
||||
subtract(mat);
|
||||
return *this;
|
||||
}
|
||||
|
||||
const Matrix3 Matrix3::operator-() const
|
||||
{
|
||||
Matrix3 mat(*this);
|
||||
mat.negate();
|
||||
return mat;
|
||||
}
|
||||
|
||||
const Matrix3 Matrix3::operator*(const Matrix3& mat) const
|
||||
{
|
||||
Matrix3 result(*this);
|
||||
result.multiply(mat);
|
||||
return result;
|
||||
}
|
||||
|
||||
Matrix3& Matrix3::operator*=(const Matrix3& mat)
|
||||
{
|
||||
multiply(mat);
|
||||
return *this;
|
||||
}
|
||||
|
||||
const Matrix3 Matrix3::operator+(float scalar) const
|
||||
{
|
||||
Matrix3 result(*this);
|
||||
result.add(scalar);
|
||||
return result;
|
||||
}
|
||||
|
||||
Matrix3& Matrix3::operator+=(float scalar)
|
||||
{
|
||||
add(scalar);
|
||||
return *this;
|
||||
}
|
||||
|
||||
const Matrix3 Matrix3::operator-(float scalar) const
|
||||
{
|
||||
Matrix3 result(*this);
|
||||
result.add(-scalar);
|
||||
return result;
|
||||
}
|
||||
|
||||
Matrix3& Matrix3::operator-=(float scalar)
|
||||
{
|
||||
add(-scalar);
|
||||
return *this;
|
||||
}
|
||||
|
||||
const Matrix3 Matrix3::operator*(float scalar) const
|
||||
{
|
||||
Matrix3 result(*this);
|
||||
result.multiply(scalar);
|
||||
return result;
|
||||
}
|
||||
|
||||
Matrix3& Matrix3::operator*=(float scalar)
|
||||
{
|
||||
multiply(scalar);
|
||||
return *this;
|
||||
}
|
||||
|
||||
NS_GI_END
|
204
mediapipe/render/core/math.hpp
Executable file
204
mediapipe/render/core/math.hpp
Executable file
|
@ -0,0 +1,204 @@
|
|||
/*
|
||||
* GPUImage-x
|
||||
*
|
||||
* Copyright (C) 2017 Yijin Wang, Yiqian Wang
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef math_hpp
|
||||
#define math_hpp
|
||||
#include "GPUImageMacros.h"
|
||||
|
||||
NS_GI_BEGIN
|
||||
|
||||
class Vector2
|
||||
{
|
||||
public:
|
||||
|
||||
float x;
|
||||
float y;
|
||||
|
||||
Vector2();
|
||||
Vector2(float xx, float yy);
|
||||
Vector2(const float* array);
|
||||
Vector2(const Vector2& p1, const Vector2& p2);
|
||||
Vector2(const Vector2& copy);
|
||||
~Vector2();
|
||||
|
||||
bool isZero() const;
|
||||
bool isOne() const;
|
||||
static float angle(const Vector2& v1, const Vector2& v2);
|
||||
void add(const Vector2& v);
|
||||
static void add(const Vector2& v1, const Vector2& v2, Vector2* dst);
|
||||
void clamp(const Vector2& min, const Vector2& max);
|
||||
static void clamp(const Vector2& v, const Vector2& min, const Vector2& max, Vector2* dst);
|
||||
float distance(const Vector2& v) const;
|
||||
float distanceSquared(const Vector2& v) const;
|
||||
Vector2 getCenter(const Vector2& v) const;
|
||||
float dot(const Vector2& v) const;
|
||||
static float dot(const Vector2& v1, const Vector2& v2);
|
||||
float length() const;
|
||||
float lengthSquared() const;
|
||||
void negate();
|
||||
void normalize();
|
||||
Vector2 getNormalized() const;
|
||||
void scale(float scalar);
|
||||
void scale(const Vector2& scale);
|
||||
void rotate(const Vector2& point, float angle);
|
||||
void set(float xx, float yy);
|
||||
void set(const Vector2& v);
|
||||
void set(const Vector2& p1, const Vector2& p2);
|
||||
void setZero();
|
||||
void subtract(const Vector2& v);
|
||||
static void subtract(const Vector2& v1, const Vector2& v2, Vector2* dst);
|
||||
void smooth(const Vector2& target, float elapsedTime, float responseTime);
|
||||
const Vector2 operator+(const Vector2& v) const;
|
||||
Vector2& operator+=(const Vector2& v);
|
||||
const Vector2 operator-(const Vector2& v) const;
|
||||
Vector2& operator-=(const Vector2& v);
|
||||
const Vector2 operator-() const;
|
||||
const Vector2 operator*(float s) const;
|
||||
Vector2& operator*=(float s);
|
||||
const Vector2 operator/(float s) const;
|
||||
bool operator<(const Vector2& v) const;
|
||||
bool operator>(const Vector2& v) const;
|
||||
bool operator==(const Vector2& v) const;
|
||||
bool operator!=(const Vector2& v) const;
|
||||
};
|
||||
|
||||
class Vector4 {
|
||||
public:
|
||||
float x;
|
||||
float y;
|
||||
float z;
|
||||
float w;
|
||||
|
||||
Vector4();
|
||||
Vector4(float xx, float yy, float zz, float ww) {
|
||||
x = xx;
|
||||
y = yy;
|
||||
z = zz;
|
||||
w = ww;
|
||||
}
|
||||
|
||||
bool operator!=(const Vector4& v) const;
|
||||
};
|
||||
|
||||
class Matrix4 {
|
||||
public:
|
||||
float m[16];
|
||||
Matrix4();
|
||||
Matrix4(const float* mat);
|
||||
Matrix4(float m11, float m12, float m13, float m14, float m21, float m22, float m23,float m24, float m31, float m32, float m33, float m34, float m41, float m42, float m43, float m44);
|
||||
Matrix4(const Matrix4& copy);
|
||||
~Matrix4();
|
||||
|
||||
void set(float m11, float m12, float m13, float m14, float m21, float m22, float m23, float m24, float m31, float m32, float m33, float m34, float m41, float m42, float m43, float m44);
|
||||
void set(const float* mat);
|
||||
void set(const Matrix4& mat);
|
||||
void setIdentity();
|
||||
|
||||
void negate();
|
||||
Matrix4 getNegated() const;
|
||||
|
||||
void transpose();
|
||||
Matrix4 getTransposed() const;
|
||||
|
||||
void add(float scalar);
|
||||
void add(float scalar, Matrix4* dst) const;
|
||||
void add(const Matrix4& mat);
|
||||
static void add(const Matrix4& m1, const Matrix4& m2, Matrix4* dst);
|
||||
|
||||
void subtract(const Matrix4& mat);
|
||||
static void subtract(const Matrix4& m1, const Matrix4& m2, Matrix4* dst);
|
||||
|
||||
void multiply(float scalar);
|
||||
void multiply(float scalar, Matrix4* dst) const;
|
||||
static void multiply(const Matrix4& mat, float scalar, Matrix4* dst);
|
||||
void multiply(const Matrix4& mat);
|
||||
static void multiply(const Matrix4& m1, const Matrix4& m2, Matrix4* dst);
|
||||
|
||||
const Matrix4 operator+(const Matrix4& mat) const;
|
||||
Matrix4& operator+=(const Matrix4& mat);
|
||||
const Matrix4 operator-(const Matrix4& mat) const;
|
||||
Matrix4& operator-=(const Matrix4& mat);
|
||||
const Matrix4 operator-() const;
|
||||
const Matrix4 operator*(const Matrix4& mat) const;
|
||||
Matrix4& operator*=(const Matrix4& mat);
|
||||
|
||||
const Matrix4 operator+(float scalar) const;
|
||||
Matrix4& operator+=(float scalar);
|
||||
const Matrix4 operator-(float scalar) const;
|
||||
Matrix4& operator-=(float scalar);
|
||||
const Matrix4 operator*(float scalar) const;
|
||||
Matrix4& operator*=(float scalar);
|
||||
|
||||
static const Matrix4 IDENTITY;
|
||||
};
|
||||
|
||||
class Matrix3 {
|
||||
public:
|
||||
float m[9];
|
||||
Matrix3();
|
||||
Matrix3(const float* mat);
|
||||
Matrix3(float m11, float m12, float m13, float m21, float m22, float m23, float m31, float m32, float m33);
|
||||
Matrix3(const Matrix3& copy);
|
||||
~Matrix3();
|
||||
|
||||
void set(float m11, float m12, float m13, float m21, float m22, float m23, float m31, float m32, float m33);
|
||||
void set(const float* mat);
|
||||
void set(const Matrix3& mat);
|
||||
void setIdentity();
|
||||
|
||||
void negate();
|
||||
Matrix3 getNegated() const;
|
||||
|
||||
void transpose();
|
||||
Matrix3 getTransposed() const;
|
||||
|
||||
void add(float scalar);
|
||||
void add(float scalar, Matrix3* dst) const;
|
||||
void add(const Matrix3& mat);
|
||||
static void add(const Matrix3& m1, const Matrix3& m2, Matrix3* dst);
|
||||
|
||||
void subtract(const Matrix3& mat);
|
||||
static void subtract(const Matrix3& m1, const Matrix3& m2, Matrix3* dst);
|
||||
|
||||
void multiply(float scalar);
|
||||
void multiply(float scalar, Matrix3* dst) const;
|
||||
static void multiply(const Matrix3& mat, float scalar, Matrix3* dst);
|
||||
void multiply(const Matrix3& mat);
|
||||
static void multiply(const Matrix3& m1, const Matrix3& m2, Matrix3* dst);
|
||||
|
||||
const Matrix3 operator+(const Matrix3& mat) const;
|
||||
Matrix3& operator+=(const Matrix3& mat);
|
||||
const Matrix3 operator-(const Matrix3& mat) const;
|
||||
Matrix3& operator-=(const Matrix3& mat);
|
||||
const Matrix3 operator-() const;
|
||||
const Matrix3 operator*(const Matrix3& mat) const;
|
||||
Matrix3& operator*=(const Matrix3& mat);
|
||||
|
||||
const Matrix3 operator+(float scalar) const;
|
||||
Matrix3& operator+=(float scalar);
|
||||
const Matrix3 operator-(float scalar) const;
|
||||
Matrix3& operator-=(float scalar);
|
||||
const Matrix3 operator*(float scalar) const;
|
||||
Matrix3& operator*=(float scalar);
|
||||
|
||||
static const Matrix3 IDENTITY;
|
||||
};
|
||||
|
||||
NS_GI_END
|
||||
|
||||
#endif /* math_hpp */
|
9
mediapipe/render/core/math/BUILD
Normal file
9
mediapipe/render/core/math/BUILD
Normal file
|
@ -0,0 +1,9 @@
|
|||
|
||||
cc_library(
|
||||
name = "math",
|
||||
srcs = glob(["*.cpp","*.inl"]),
|
||||
hdrs = glob(["*.hpp"]),
|
||||
# Use -Dverbose=-1 to turn off zlib's trace logging. (#3280)
|
||||
includes = ["."],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
679
mediapipe/render/core/math/mat4.cpp
Normal file
679
mediapipe/render/core/math/mat4.cpp
Normal file
|
@ -0,0 +1,679 @@
|
|||
//
|
||||
// Mat4.cpp
|
||||
// Quaramera
|
||||
//
|
||||
// Created by Wang,Renzhu on 2018/11/20.
|
||||
// Copyright © 2018年 Wang,Renzhu. All rights reserved.
|
||||
//
|
||||
|
||||
#include "mat4.hpp"
|
||||
#include "math_utils.hpp"
|
||||
#include <cstring>
|
||||
|
||||
namespace Quaramera {
|
||||
|
||||
static const int MATRIX_SIZE = (sizeof(float) * 16);
|
||||
|
||||
Mat4::Mat4()
|
||||
{
|
||||
*this = IDENTITY;
|
||||
}
|
||||
|
||||
Mat4::Mat4(float m11, float m12, float m13, float m14, float m21, float m22, float m23, float m24,
|
||||
float m31, float m32, float m33, float m34, float m41, float m42, float m43, float m44)
|
||||
{
|
||||
set(m11, m12, m13, m14, m21, m22, m23, m24, m31, m32, m33, m34, m41, m42, m43, m44);
|
||||
}
|
||||
|
||||
Mat4::Mat4(const float* mat)
|
||||
{
|
||||
set(mat);
|
||||
}
|
||||
|
||||
Mat4::Mat4(const Mat4& copy)
|
||||
{
|
||||
memcpy(m, copy.m, MATRIX_SIZE);
|
||||
}
|
||||
|
||||
void Mat4::create_look_at(const Vec3& eyePosition, const Vec3& targetPosition, const Vec3& up, Mat4* dst)
|
||||
{
|
||||
create_look_at(eyePosition.x, eyePosition.y, eyePosition.z,
|
||||
targetPosition.x, targetPosition.y, targetPosition.z,
|
||||
up.x, up.y, up.z, dst);
|
||||
}
|
||||
|
||||
void Mat4::create_look_at(float eyePositionX, float eyePositionY, float eyePositionZ,
|
||||
float targetPositionX, float targetPositionY, float targetPositionZ,
|
||||
float upX, float upY, float upZ, Mat4* dst)
|
||||
{
|
||||
Vec3 eye(eyePositionX, eyePositionY, eyePositionZ);
|
||||
Vec3 target(targetPositionX, targetPositionY, targetPositionZ);
|
||||
Vec3 up(upX, upY, upZ);
|
||||
up.normalize();
|
||||
|
||||
Vec3 zaxis;
|
||||
Vec3::subtract(eye, target, &zaxis);
|
||||
zaxis.normalize();
|
||||
|
||||
Vec3 xaxis;
|
||||
Vec3::cross(up, zaxis, &xaxis);
|
||||
xaxis.normalize();
|
||||
|
||||
Vec3 yaxis;
|
||||
Vec3::cross(zaxis, xaxis, &yaxis);
|
||||
yaxis.normalize();
|
||||
|
||||
dst->m[0] = xaxis.x;
|
||||
dst->m[1] = yaxis.x;
|
||||
dst->m[2] = zaxis.x;
|
||||
dst->m[3] = 0.0f;
|
||||
|
||||
dst->m[4] = xaxis.y;
|
||||
dst->m[5] = yaxis.y;
|
||||
dst->m[6] = zaxis.y;
|
||||
dst->m[7] = 0.0f;
|
||||
|
||||
dst->m[8] = xaxis.z;
|
||||
dst->m[9] = yaxis.z;
|
||||
dst->m[10] = zaxis.z;
|
||||
dst->m[11] = 0.0f;
|
||||
|
||||
dst->m[12] = -Vec3::dot(xaxis, eye);
|
||||
dst->m[13] = -Vec3::dot(yaxis, eye);
|
||||
dst->m[14] = -Vec3::dot(zaxis, eye);
|
||||
dst->m[15] = 1.0f;
|
||||
}
|
||||
|
||||
void Mat4::create_perspective(float fieldOfView, float aspectRatio,
|
||||
float zNearPlane, float zFarPlane, Mat4* dst)
|
||||
{
|
||||
float f_n = 1.0f / (zFarPlane - zNearPlane);
|
||||
float theta = MATH_DEG_TO_RAD(fieldOfView) * 0.5f;
|
||||
if (std::abs(std::fmod(theta, MATH_PIOVER2)) < MATH_EPSILON)
|
||||
{
|
||||
return;
|
||||
}
|
||||
float divisor = std::tan(theta);
|
||||
float factor = 1.0f / divisor;
|
||||
|
||||
memset(dst, 0, MATRIX_SIZE);
|
||||
|
||||
dst->m[0] = (1.0f / aspectRatio) * factor;
|
||||
dst->m[5] = factor;
|
||||
dst->m[10] = (-(zFarPlane + zNearPlane)) * f_n;
|
||||
dst->m[11] = -1.0f;
|
||||
dst->m[14] = -2.0f * zFarPlane * zNearPlane * f_n;
|
||||
}
|
||||
|
||||
void Mat4::create_orthographic(float width, float height, float zNearPlane, float zFarPlane, Mat4* dst)
|
||||
{
|
||||
float halfWidth = width / 2.0f;
|
||||
float halfHeight = height / 2.0f;
|
||||
create_orthographic_off_center(-halfWidth, halfWidth, -halfHeight, halfHeight, zNearPlane, zFarPlane, dst);
|
||||
}
|
||||
|
||||
void Mat4::create_orthographic_off_center(float left, float right, float bottom, float top,
|
||||
float zNearPlane, float zFarPlane, Mat4* dst)
|
||||
{
|
||||
memset(dst, 0, MATRIX_SIZE);
|
||||
dst->m[0] = 2 / (right - left);
|
||||
dst->m[5] = 2 / (top - bottom);
|
||||
dst->m[10] = 2 / (zNearPlane - zFarPlane);
|
||||
|
||||
dst->m[12] = (left + right) / (left - right);
|
||||
dst->m[13] = (top + bottom) / (bottom - top);
|
||||
dst->m[14] = (zNearPlane + zFarPlane) / (zNearPlane - zFarPlane);
|
||||
dst->m[15] = 1;
|
||||
}
|
||||
|
||||
void Mat4::create_scale(const Vec3& scale, Mat4* dst)
|
||||
{
|
||||
memcpy(dst, &IDENTITY, MATRIX_SIZE);
|
||||
|
||||
dst->m[0] = scale.x;
|
||||
dst->m[5] = scale.y;
|
||||
dst->m[10] = scale.z;
|
||||
}
|
||||
|
||||
void Mat4::create_scale(float xScale, float yScale, float zScale, Mat4* dst)
|
||||
{
|
||||
memcpy(dst, &IDENTITY, MATRIX_SIZE);
|
||||
|
||||
dst->m[0] = xScale;
|
||||
dst->m[5] = yScale;
|
||||
dst->m[10] = zScale;
|
||||
}
|
||||
|
||||
void Mat4::create_rotation(const Vec3& axis, float angle, Mat4* dst)
|
||||
{
|
||||
float x = axis.x;
|
||||
float y = axis.y;
|
||||
float z = axis.z;
|
||||
|
||||
// Make sure the input axis is normalized.
|
||||
float n = x*x + y*y + z*z;
|
||||
if (n != 1.0f)
|
||||
{
|
||||
// Not normalized.
|
||||
n = std::sqrt(n);
|
||||
// Prevent divide too close to zero.
|
||||
if (n > 0.000001f)
|
||||
{
|
||||
n = 1.0f / n;
|
||||
x *= n;
|
||||
y *= n;
|
||||
z *= n;
|
||||
}
|
||||
}
|
||||
|
||||
float c = std::cos(angle);
|
||||
float s = std::sin(angle);
|
||||
|
||||
float t = 1.0f - c;
|
||||
float tx = t * x;
|
||||
float ty = t * y;
|
||||
float tz = t * z;
|
||||
float txy = tx * y;
|
||||
float txz = tx * z;
|
||||
float tyz = ty * z;
|
||||
float sx = s * x;
|
||||
float sy = s * y;
|
||||
float sz = s * z;
|
||||
|
||||
dst->m[0] = c + tx*x;
|
||||
dst->m[1] = txy + sz;
|
||||
dst->m[2] = txz - sy;
|
||||
dst->m[3] = 0.0f;
|
||||
|
||||
dst->m[4] = txy - sz;
|
||||
dst->m[5] = c + ty*y;
|
||||
dst->m[6] = tyz + sx;
|
||||
dst->m[7] = 0.0f;
|
||||
|
||||
dst->m[8] = txz + sy;
|
||||
dst->m[9] = tyz - sx;
|
||||
dst->m[10] = c + tz*z;
|
||||
dst->m[11] = 0.0f;
|
||||
|
||||
dst->m[12] = 0.0f;
|
||||
dst->m[13] = 0.0f;
|
||||
dst->m[14] = 0.0f;
|
||||
dst->m[15] = 1.0f;
|
||||
}
|
||||
|
||||
void Mat4::create_rotation_x(float angle, Mat4* dst)
|
||||
{
|
||||
memcpy(dst, &IDENTITY, MATRIX_SIZE);
|
||||
|
||||
float c = std::cos(angle);
|
||||
float s = std::sin(angle);
|
||||
|
||||
dst->m[5] = c;
|
||||
dst->m[6] = s;
|
||||
dst->m[9] = -s;
|
||||
dst->m[10] = c;
|
||||
}
|
||||
|
||||
void Mat4::create_rotation_y(float angle, Mat4* dst)
|
||||
{
|
||||
memcpy(dst, &IDENTITY, MATRIX_SIZE);
|
||||
|
||||
float c = std::cos(angle);
|
||||
float s = std::sin(angle);
|
||||
|
||||
dst->m[0] = c;
|
||||
dst->m[2] = -s;
|
||||
dst->m[8] = s;
|
||||
dst->m[10] = c;
|
||||
}
|
||||
|
||||
void Mat4::create_rotation_z(float angle, Mat4* dst)
|
||||
{
|
||||
memcpy(dst, &IDENTITY, MATRIX_SIZE);
|
||||
|
||||
float c = std::cos(angle);
|
||||
float s = std::sin(angle);
|
||||
|
||||
dst->m[0] = c;
|
||||
dst->m[1] = s;
|
||||
dst->m[4] = -s;
|
||||
dst->m[5] = c;
|
||||
}
|
||||
|
||||
void Mat4::create_translation(const Vec3& translation, Mat4* dst)
|
||||
{
|
||||
memcpy(dst, &IDENTITY, MATRIX_SIZE);
|
||||
|
||||
dst->m[12] = translation.x;
|
||||
dst->m[13] = translation.y;
|
||||
dst->m[14] = translation.z;
|
||||
}
|
||||
|
||||
void Mat4::create_translation(float xTranslation, float yTranslation, float zTranslation, Mat4* dst)
|
||||
{
|
||||
memcpy(dst, &IDENTITY, MATRIX_SIZE);
|
||||
|
||||
dst->m[12] = xTranslation;
|
||||
dst->m[13] = yTranslation;
|
||||
dst->m[14] = zTranslation;
|
||||
}
|
||||
|
||||
void Mat4::add(float scalar)
|
||||
{
|
||||
add(scalar, this);
|
||||
}
|
||||
|
||||
void Mat4::add(float scalar, Mat4* dst)
|
||||
{
|
||||
MathUtils::add_matrix(m, scalar, dst->m);
|
||||
}
|
||||
|
||||
void Mat4::add(const Mat4& mat)
|
||||
{
|
||||
add(*this, mat, this);
|
||||
}
|
||||
|
||||
void Mat4::add(const Mat4& m1, const Mat4& m2, Mat4* dst)
|
||||
{
|
||||
MathUtils::add_matrix(m1.m, m2.m, dst->m);
|
||||
}
|
||||
|
||||
float Mat4::determinant() const
|
||||
{
|
||||
float a0 = m[0] * m[5] - m[1] * m[4];
|
||||
float a1 = m[0] * m[6] - m[2] * m[4];
|
||||
float a2 = m[0] * m[7] - m[3] * m[4];
|
||||
float a3 = m[1] * m[6] - m[2] * m[5];
|
||||
float a4 = m[1] * m[7] - m[3] * m[5];
|
||||
float a5 = m[2] * m[7] - m[3] * m[6];
|
||||
float b0 = m[8] * m[13] - m[9] * m[12];
|
||||
float b1 = m[8] * m[14] - m[10] * m[12];
|
||||
float b2 = m[8] * m[15] - m[11] * m[12];
|
||||
float b3 = m[9] * m[14] - m[10] * m[13];
|
||||
float b4 = m[9] * m[15] - m[11] * m[13];
|
||||
float b5 = m[10] * m[15] - m[11] * m[14];
|
||||
|
||||
// Calculate the determinant.
|
||||
return (a0 * b5 - a1 * b4 + a2 * b3 + a3 * b2 - a4 * b1 + a5 * b0);
|
||||
}
|
||||
|
||||
void Mat4::get_up_vector(Vec3* dst) const
|
||||
{
|
||||
dst->x = m[4];
|
||||
dst->y = m[5];
|
||||
dst->z = m[6];
|
||||
}
|
||||
|
||||
void Mat4::get_down_vector(Vec3* dst) const
|
||||
{
|
||||
dst->x = -m[4];
|
||||
dst->y = -m[5];
|
||||
dst->z = -m[6];
|
||||
}
|
||||
|
||||
void Mat4::get_left_vector(Vec3* dst) const
|
||||
{
|
||||
dst->x = -m[0];
|
||||
dst->y = -m[1];
|
||||
dst->z = -m[2];
|
||||
}
|
||||
|
||||
void Mat4::get_right_vector(Vec3* dst) const
|
||||
{
|
||||
dst->x = m[0];
|
||||
dst->y = m[1];
|
||||
dst->z = m[2];
|
||||
}
|
||||
|
||||
void Mat4::get_forward_vector(Vec3* dst) const
|
||||
{
|
||||
dst->x = -m[8];
|
||||
dst->y = -m[9];
|
||||
dst->z = -m[10];
|
||||
}
|
||||
|
||||
void Mat4::get_back_vector(Vec3* dst) const
|
||||
{
|
||||
dst->x = m[8];
|
||||
dst->y = m[9];
|
||||
dst->z = m[10];
|
||||
}
|
||||
|
||||
Mat4 Mat4::get_inversed() const
|
||||
{
|
||||
Mat4 mat(*this);
|
||||
mat.inverse();
|
||||
return mat;
|
||||
}
|
||||
|
||||
bool Mat4::inverse()
|
||||
{
|
||||
float a0 = m[0] * m[5] - m[1] * m[4];
|
||||
float a1 = m[0] * m[6] - m[2] * m[4];
|
||||
float a2 = m[0] * m[7] - m[3] * m[4];
|
||||
float a3 = m[1] * m[6] - m[2] * m[5];
|
||||
float a4 = m[1] * m[7] - m[3] * m[5];
|
||||
float a5 = m[2] * m[7] - m[3] * m[6];
|
||||
float b0 = m[8] * m[13] - m[9] * m[12];
|
||||
float b1 = m[8] * m[14] - m[10] * m[12];
|
||||
float b2 = m[8] * m[15] - m[11] * m[12];
|
||||
float b3 = m[9] * m[14] - m[10] * m[13];
|
||||
float b4 = m[9] * m[15] - m[11] * m[13];
|
||||
float b5 = m[10] * m[15] - m[11] * m[14];
|
||||
|
||||
// Calculate the determinant.
|
||||
float det = a0 * b5 - a1 * b4 + a2 * b3 + a3 * b2 - a4 * b1 + a5 * b0;
|
||||
|
||||
// Close to zero, can't invert.
|
||||
if (std::abs(det) <= MATH_TOLERANCE)
|
||||
return false;
|
||||
|
||||
// Support the case where m == dst.
|
||||
Mat4 inverse;
|
||||
inverse.m[0] = m[5] * b5 - m[6] * b4 + m[7] * b3;
|
||||
inverse.m[1] = -m[1] * b5 + m[2] * b4 - m[3] * b3;
|
||||
inverse.m[2] = m[13] * a5 - m[14] * a4 + m[15] * a3;
|
||||
inverse.m[3] = -m[9] * a5 + m[10] * a4 - m[11] * a3;
|
||||
|
||||
inverse.m[4] = -m[4] * b5 + m[6] * b2 - m[7] * b1;
|
||||
inverse.m[5] = m[0] * b5 - m[2] * b2 + m[3] * b1;
|
||||
inverse.m[6] = -m[12] * a5 + m[14] * a2 - m[15] * a1;
|
||||
inverse.m[7] = m[8] * a5 - m[10] * a2 + m[11] * a1;
|
||||
|
||||
inverse.m[8] = m[4] * b4 - m[5] * b2 + m[7] * b0;
|
||||
inverse.m[9] = -m[0] * b4 + m[1] * b2 - m[3] * b0;
|
||||
inverse.m[10] = m[12] * a4 - m[13] * a2 + m[15] * a0;
|
||||
inverse.m[11] = -m[8] * a4 + m[9] * a2 - m[11] * a0;
|
||||
|
||||
inverse.m[12] = -m[4] * b3 + m[5] * b1 - m[6] * b0;
|
||||
inverse.m[13] = m[0] * b3 - m[1] * b1 + m[2] * b0;
|
||||
inverse.m[14] = -m[12] * a3 + m[13] * a1 - m[14] * a0;
|
||||
inverse.m[15] = m[8] * a3 - m[9] * a1 + m[10] * a0;
|
||||
|
||||
multiply(inverse, 1.0f / det, this);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Mat4::is_identity() const
|
||||
{
|
||||
return (memcmp(m, &IDENTITY, MATRIX_SIZE) == 0);
|
||||
}
|
||||
|
||||
void Mat4::multiply(float scalar)
|
||||
{
|
||||
multiply(scalar, this);
|
||||
}
|
||||
|
||||
void Mat4::multiply(float scalar, Mat4* dst) const
|
||||
{
|
||||
multiply(*this, scalar, dst);
|
||||
}
|
||||
|
||||
void Mat4::multiply(const Mat4& m, float scalar, Mat4* dst)
|
||||
{
|
||||
MathUtils::multiply_matrix(m.m, scalar, dst->m);
|
||||
}
|
||||
|
||||
void Mat4::multiply(const Mat4& mat)
|
||||
{
|
||||
multiply(*this, mat, this);
|
||||
}
|
||||
|
||||
void Mat4::multiply(const Mat4& m1, const Mat4& m2, Mat4* dst)
|
||||
{
|
||||
MathUtils::multiply_matrix(m1.m, m2.m, dst->m);
|
||||
}
|
||||
|
||||
void Mat4::negate()
|
||||
{
|
||||
MathUtils::negate_matrix(m, m);
|
||||
}
|
||||
|
||||
Mat4 Mat4::get_negated() const
|
||||
{
|
||||
Mat4 mat(*this);
|
||||
mat.negate();
|
||||
return mat;
|
||||
}
|
||||
|
||||
void Mat4::rotate(const Vec3& axis, float angle)
|
||||
{
|
||||
rotate(axis, angle, this);
|
||||
}
|
||||
|
||||
void Mat4::rotate(const Vec3& axis, float angle, Mat4* dst) const
|
||||
{
|
||||
Mat4 r;
|
||||
create_rotation(axis, angle, &r);
|
||||
multiply(*this, r, dst);
|
||||
}
|
||||
|
||||
void Mat4::rotate_x(float angle)
|
||||
{
|
||||
rotate_x(angle, this);
|
||||
}
|
||||
|
||||
void Mat4::rotate_x(float angle, Mat4* dst) const
|
||||
{
|
||||
Mat4 r;
|
||||
create_rotation_x(angle, &r);
|
||||
multiply(*this, r, dst);
|
||||
}
|
||||
|
||||
void Mat4::rotate_y(float angle)
|
||||
{
|
||||
rotate_y(angle, this);
|
||||
}
|
||||
|
||||
void Mat4::rotate_y(float angle, Mat4* dst) const
|
||||
{
|
||||
Mat4 r;
|
||||
create_rotation_y(angle, &r);
|
||||
multiply(*this, r, dst);
|
||||
}
|
||||
|
||||
void Mat4::rotate_z(float angle)
|
||||
{
|
||||
rotate_z(angle, this);
|
||||
}
|
||||
|
||||
void Mat4::rotate_z(float angle, Mat4* dst) const
|
||||
{
|
||||
Mat4 r;
|
||||
create_rotation_z(angle, &r);
|
||||
multiply(*this, r, dst);
|
||||
}
|
||||
|
||||
void Mat4::scale(float value)
|
||||
{
|
||||
scale(value, this);
|
||||
}
|
||||
|
||||
void Mat4::scale(float value, Mat4* dst) const
|
||||
{
|
||||
scale(value, value, value, dst);
|
||||
}
|
||||
|
||||
void Mat4::scale(float xScale, float yScale, float zScale)
|
||||
{
|
||||
scale(xScale, yScale, zScale, this);
|
||||
}
|
||||
|
||||
void Mat4::scale(float xScale, float yScale, float zScale, Mat4* dst) const
|
||||
{
|
||||
Mat4 s;
|
||||
create_scale(xScale, yScale, zScale, &s);
|
||||
multiply(*this, s, dst);
|
||||
}
|
||||
|
||||
void Mat4::scale(const Vec3& s)
|
||||
{
|
||||
scale(s.x, s.y, s.z, this);
|
||||
}
|
||||
|
||||
void Mat4::scale(const Vec3& s, Mat4* dst) const
|
||||
{
|
||||
scale(s.x, s.y, s.z, dst);
|
||||
}
|
||||
|
||||
void Mat4::set(float m11, float m12, float m13, float m14, float m21, float m22, float m23, float m24,
|
||||
float m31, float m32, float m33, float m34, float m41, float m42, float m43, float m44)
|
||||
{
|
||||
m[0] = m11;
|
||||
m[1] = m21;
|
||||
m[2] = m31;
|
||||
m[3] = m41;
|
||||
m[4] = m12;
|
||||
m[5] = m22;
|
||||
m[6] = m32;
|
||||
m[7] = m42;
|
||||
m[8] = m13;
|
||||
m[9] = m23;
|
||||
m[10] = m33;
|
||||
m[11] = m43;
|
||||
m[12] = m14;
|
||||
m[13] = m24;
|
||||
m[14] = m34;
|
||||
m[15] = m44;
|
||||
}
|
||||
|
||||
void Mat4::set(const float* mat)
|
||||
{
|
||||
memcpy(this->m, mat, MATRIX_SIZE);
|
||||
}
|
||||
|
||||
void Mat4::set(const Mat4& mat)
|
||||
{
|
||||
memcpy(this->m, mat.m, MATRIX_SIZE);
|
||||
}
|
||||
|
||||
void Mat4::set_identity()
|
||||
{
|
||||
memcpy(m, &IDENTITY, MATRIX_SIZE);
|
||||
}
|
||||
|
||||
void Mat4::set_zero()
|
||||
{
|
||||
memset(m, 0, MATRIX_SIZE);
|
||||
}
|
||||
|
||||
void Mat4::subtract(const Mat4& mat)
|
||||
{
|
||||
subtract(*this, mat, this);
|
||||
}
|
||||
|
||||
void Mat4::subtract(const Mat4& m1, const Mat4& m2, Mat4* dst)
|
||||
{
|
||||
MathUtils::subtract_matrix(m1.m, m2.m, dst->m);
|
||||
}
|
||||
|
||||
void Mat4::transform_vector(Vec3* vector) const
|
||||
{
|
||||
transform_vector(vector->x, vector->y, vector->z, 0.0f, vector);
|
||||
}
|
||||
|
||||
void Mat4::transform_vector(const Vec3& vector, Vec3* dst) const
|
||||
{
|
||||
transform_vector(vector.x, vector.y, vector.z, 0.0f, dst);
|
||||
}
|
||||
|
||||
void Mat4::transform_vector(float x, float y, float z, float w, Vec3* dst) const
|
||||
{
|
||||
MathUtils::transform_vec4(m, x, y, z, w, (float*)dst);
|
||||
}
|
||||
|
||||
void Mat4::transform_vector(Vec4* vector) const
|
||||
{
|
||||
transform_vector(*vector, vector);
|
||||
}
|
||||
|
||||
void Mat4::transform_vector(const Vec4& vector, Vec4* dst) const
|
||||
{
|
||||
MathUtils::transform_vec4(m, (const float*) &vector, (float*)dst);
|
||||
}
|
||||
|
||||
void Mat4::translate(float x, float y, float z)
|
||||
{
|
||||
translate(x, y, z, this);
|
||||
}
|
||||
|
||||
void Mat4::translate(float x, float y, float z, Mat4* dst) const
|
||||
{
|
||||
Mat4 t;
|
||||
create_translation(x, y, z, &t);
|
||||
multiply(*this, t, dst);
|
||||
}
|
||||
|
||||
void Mat4::translate(const Vec3& t)
|
||||
{
|
||||
translate(t.x, t.y, t.z, this);
|
||||
}
|
||||
|
||||
void Mat4::translate(const Vec3& t, Mat4* dst) const
|
||||
{
|
||||
translate(t.x, t.y, t.z, dst);
|
||||
}
|
||||
|
||||
void Mat4::transpose()
|
||||
{
|
||||
MathUtils::transpose_matrix(m, m);
|
||||
}
|
||||
|
||||
Mat4 Mat4::get_transposed() const
|
||||
{
|
||||
Mat4 mat(*this);
|
||||
mat.transpose();
|
||||
return mat;
|
||||
}
|
||||
|
||||
const Mat4 Mat4::operator+(float scalar) const
|
||||
{
|
||||
Mat4 result(*this);
|
||||
result.add(scalar);
|
||||
return result;
|
||||
}
|
||||
|
||||
Mat4& Mat4::operator+=(float scalar)
|
||||
{
|
||||
add(scalar);
|
||||
return *this;
|
||||
}
|
||||
|
||||
const Mat4 Mat4::operator-(float scalar) const
|
||||
{
|
||||
Mat4 result(*this);
|
||||
result.add(-scalar);
|
||||
return result;
|
||||
}
|
||||
|
||||
Mat4& Mat4::operator-=(float scalar)
|
||||
{
|
||||
add(-scalar);
|
||||
return *this;
|
||||
}
|
||||
|
||||
const Mat4 Mat4::operator*(float scalar) const
|
||||
{
|
||||
Mat4 result(*this);
|
||||
result.multiply(scalar);
|
||||
return result;
|
||||
}
|
||||
|
||||
Mat4& Mat4::operator*=(float scalar)
|
||||
{
|
||||
multiply(scalar);
|
||||
return *this;
|
||||
}
|
||||
|
||||
const Mat4 Mat4::IDENTITY = Mat4(1.0f, 0.0f, 0.0f, 0.0f,
|
||||
0.0f, 1.0f, 0.0f, 0.0f,
|
||||
0.0f, 0.0f, 1.0f, 0.0f,
|
||||
0.0f, 0.0f, 0.0f, 1.0f);
|
||||
|
||||
const Mat4 Mat4::ZERO = Mat4(0, 0, 0, 0,
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 0 );
|
||||
|
||||
}
|
816
mediapipe/render/core/math/mat4.hpp
Normal file
816
mediapipe/render/core/math/mat4.hpp
Normal file
|
@ -0,0 +1,816 @@
|
|||
//
|
||||
// mat4.h
|
||||
// Quaramera
|
||||
//
|
||||
// Created by Wang,Renzhu on 2018/11/20.
|
||||
// Copyright © 2018年 Wang,Renzhu. All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef MAT4_H
|
||||
#define MAT4_H
|
||||
|
||||
#include "vec3.hpp"
|
||||
#include "vec4.hpp"
|
||||
|
||||
namespace Quaramera {
|
||||
|
||||
class Mat4
|
||||
{
|
||||
public:
|
||||
float m[16];
|
||||
|
||||
/**
|
||||
* Default constructor.
|
||||
* Constructs a matrix initialized to the identity matrix:
|
||||
*
|
||||
* 1 0 0 0
|
||||
* 0 1 0 0
|
||||
* 0 0 1 0
|
||||
* 0 0 0 1
|
||||
*/
|
||||
Mat4();
|
||||
|
||||
/**
|
||||
* Constructs a matrix initialized to the specified value.
|
||||
*
|
||||
* @param m11 The first element of the first row.
|
||||
* @param m12 The second element of the first row.
|
||||
* @param m13 The third element of the first row.
|
||||
* @param m14 The fourth element of the first row.
|
||||
* @param m21 The first element of the second row.
|
||||
* @param m22 The second element of the second row.
|
||||
* @param m23 The third element of the second row.
|
||||
* @param m24 The fourth element of the second row.
|
||||
* @param m31 The first element of the third row.
|
||||
* @param m32 The second element of the third row.
|
||||
* @param m33 The third element of the third row.
|
||||
* @param m34 The fourth element of the third row.
|
||||
* @param m41 The first element of the fourth row.
|
||||
* @param m42 The second element of the fourth row.
|
||||
* @param m43 The third element of the fourth row.
|
||||
* @param m44 The fourth element of the fourth row.
|
||||
*/
|
||||
Mat4(float m11, float m12, float m13, float m14, float m21, float m22, float m23, float m24,
|
||||
float m31, float m32, float m33, float m34, float m41, float m42, float m43, float m44);
|
||||
|
||||
/**
|
||||
* Creates a matrix initialized to the specified column-major array.
|
||||
*
|
||||
* The passed-in array is in column-major order, so the memory layout of the array is as follows:
|
||||
*
|
||||
* 0 4 8 12
|
||||
* 1 5 9 13
|
||||
* 2 6 10 14
|
||||
* 3 7 11 15
|
||||
*
|
||||
* @param mat An array containing 16 elements in column-major order.
|
||||
*/
|
||||
Mat4(const float* mat);
|
||||
|
||||
/**
|
||||
* Constructs a new matrix by copying the values from the specified matrix.
|
||||
*
|
||||
* @param copy The matrix to copy.
|
||||
*/
|
||||
Mat4(const Mat4& copy);
|
||||
|
||||
/**
|
||||
* Creates a view matrix based on the specified input parameters.
|
||||
*
|
||||
* @param eyePosition The eye position.
|
||||
* @param targetPosition The target's center position.
|
||||
* @param up The up vector.
|
||||
* @param dst A matrix to store the result in.
|
||||
*/
|
||||
static void create_look_at(const Vec3& eyePosition, const Vec3& targetPosition, const Vec3& up, Mat4* dst);
|
||||
|
||||
/**
|
||||
* Creates a view matrix based on the specified input parameters.
|
||||
*
|
||||
* @param eyePositionX The eye x-coordinate position.
|
||||
* @param eyePositionY The eye y-coordinate position.
|
||||
* @param eyePositionZ The eye z-coordinate position.
|
||||
* @param targetCenterX The target's center x-coordinate position.
|
||||
* @param targetCenterY The target's center y-coordinate position.
|
||||
* @param targetCenterZ The target's center z-coordinate position.
|
||||
* @param upX The up vector x-coordinate value.
|
||||
* @param upY The up vector y-coordinate value.
|
||||
* @param upZ The up vector z-coordinate value.
|
||||
* @param dst A matrix to store the result in.
|
||||
*/
|
||||
static void create_look_at(float eyePositionX, float eyePositionY, float eyePositionZ,
|
||||
float targetCenterX, float targetCenterY, float targetCenterZ,
|
||||
float upX, float upY, float upZ, Mat4* dst);
|
||||
|
||||
/**
|
||||
* Builds a perspective projection matrix based on a field of view and returns by value.
|
||||
*
|
||||
* Projection space refers to the space after applying projection transformation from view space.
|
||||
* After the projection transformation, visible content has x- and y-coordinates ranging from -1 to 1,
|
||||
* and a z-coordinate ranging from 0 to 1. To obtain the viewable area (in world space) of a scene,
|
||||
* create a BoundingFrustum and pass the combined view and projection matrix to the constructor.
|
||||
*
|
||||
* @param fieldOfView The field of view in the y direction (in degrees).
|
||||
* @param aspectRatio The aspect ratio, defined as view space width divided by height.
|
||||
* @param zNearPlane The distance to the near view plane.
|
||||
* @param zFarPlane The distance to the far view plane.
|
||||
* @param dst A matrix to store the result in.
|
||||
*/
|
||||
static void create_perspective(float fieldOfView, float aspectRatio, float zNearPlane, float zFarPlane, Mat4* dst);
|
||||
|
||||
/**
|
||||
* Creates an orthographic projection matrix.
|
||||
*
|
||||
* @param width The width of the view.
|
||||
* @param height The height of the view.
|
||||
* @param zNearPlane The minimum z-value of the view volume.
|
||||
* @param zFarPlane The maximum z-value of the view volume.
|
||||
* @param dst A matrix to store the result in.
|
||||
*/
|
||||
static void create_orthographic(float width, float height, float zNearPlane, float zFarPlane, Mat4* dst);
|
||||
|
||||
/**
|
||||
* Creates an orthographic projection matrix.
|
||||
*
|
||||
* Projection space refers to the space after applying
|
||||
* projection transformation from view space. After the
|
||||
* projection transformation, visible content has
|
||||
* x and y coordinates ranging from -1 to 1, and z coordinates
|
||||
* ranging from 0 to 1.
|
||||
*
|
||||
* Unlike perspective projection, in orthographic projection
|
||||
* there is no perspective foreshortening.
|
||||
*
|
||||
* The viewable area of this orthographic projection extends
|
||||
* from left to right on the x-axis, bottom to top on the y-axis,
|
||||
* and zNearPlane to zFarPlane on the z-axis. These values are
|
||||
* relative to the position and x, y, and z-axes of the view.
|
||||
* To obtain the viewable area (in world space) of a scene,
|
||||
* create a BoundingFrustum and pass the combined view and
|
||||
* projection matrix to the constructor.
|
||||
*
|
||||
* @param left The minimum x-value of the view volume.
|
||||
* @param right The maximum x-value of the view volume.
|
||||
* @param bottom The minimum y-value of the view volume.
|
||||
* @param top The maximum y-value of the view volume.
|
||||
* @param zNearPlane The minimum z-value of the view volume.
|
||||
* @param zFarPlane The maximum z-value of the view volume.
|
||||
* @param dst A matrix to store the result in.
|
||||
*/
|
||||
static void create_orthographic_off_center(float left, float right, float bottom, float top,
|
||||
float zNearPlane, float zFarPlane, Mat4* dst);
|
||||
|
||||
//Fills in an existing Mat4 so that it reflects the coordinate system about a specified Plane.
|
||||
//plane The Plane about which to create a reflection.
|
||||
//dst A matrix to store the result in.
|
||||
//static void createReflection(const Plane& plane, Mat4* dst);
|
||||
|
||||
/**
|
||||
* Creates a scale matrix.
|
||||
*
|
||||
* @param scale The amount to scale.
|
||||
* @param dst A matrix to store the result in.
|
||||
*/
|
||||
static void create_scale(const Vec3& scale, Mat4* dst);
|
||||
|
||||
/**
|
||||
* Creates a scale matrix.
|
||||
*
|
||||
* @param xScale The amount to scale along the x-axis.
|
||||
* @param yScale The amount to scale along the y-axis.
|
||||
* @param zScale The amount to scale along the z-axis.
|
||||
* @param dst A matrix to store the result in.
|
||||
*/
|
||||
static void create_scale(float xScale, float yScale, float zScale, Mat4* dst);
|
||||
|
||||
/**
|
||||
* Creates a rotation matrix from the specified axis and angle.
|
||||
*
|
||||
* @param axis A vector describing the axis to rotate about.
|
||||
* @param angle The angle (in radians).
|
||||
* @param dst A matrix to store the result in.
|
||||
*/
|
||||
static void create_rotation(const Vec3& axis, float angle, Mat4* dst);
|
||||
|
||||
/**
|
||||
* Creates a matrix describing a rotation around the x-axis.
|
||||
*
|
||||
* @param angle The angle of rotation (in radians).
|
||||
* @param dst A matrix to store the result in.
|
||||
*/
|
||||
static void create_rotation_x(float angle, Mat4* dst);
|
||||
|
||||
/**
|
||||
* Creates a matrix describing a rotation around the y-axis.
|
||||
*
|
||||
* @param angle The angle of rotation (in radians).
|
||||
* @param dst A matrix to store the result in.
|
||||
*/
|
||||
static void create_rotation_y(float angle, Mat4* dst);
|
||||
|
||||
/**
|
||||
* Creates a matrix describing a rotation around the z-axis.
|
||||
*
|
||||
* @param angle The angle of rotation (in radians).
|
||||
* @param dst A matrix to store the result in.
|
||||
*/
|
||||
static void create_rotation_z(float angle, Mat4* dst);
|
||||
|
||||
/**
|
||||
* Creates a translation matrix.
|
||||
*
|
||||
* @param translation The translation.
|
||||
* @param dst A matrix to store the result in.
|
||||
*/
|
||||
static void create_translation(const Vec3& translation, Mat4* dst);
|
||||
|
||||
/**
|
||||
* Creates a translation matrix.
|
||||
*
|
||||
* @param xTranslation The translation on the x-axis.
|
||||
* @param yTranslation The translation on the y-axis.
|
||||
* @param zTranslation The translation on the z-axis.
|
||||
* @param dst A matrix to store the result in.
|
||||
*/
|
||||
static void create_translation(float xTranslation, float yTranslation, float zTranslation, Mat4* dst);
|
||||
|
||||
/**
|
||||
* Adds a scalar value to each component of this matrix.
|
||||
*
|
||||
* @param scalar The scalar to add.
|
||||
*/
|
||||
void add(float scalar);
|
||||
|
||||
/**
|
||||
* Adds a scalar value to each component of this matrix and stores the result in dst.
|
||||
*
|
||||
* @param scalar The scalar value to add.
|
||||
* @param dst A matrix to store the result in.
|
||||
*/
|
||||
void add(float scalar, Mat4* dst);
|
||||
|
||||
/**
|
||||
* Adds the specified matrix to this matrix.
|
||||
*
|
||||
* @param mat The matrix to add.
|
||||
*/
|
||||
void add(const Mat4& mat);
|
||||
|
||||
/**
|
||||
* Adds the specified matrices and stores the result in dst.
|
||||
*
|
||||
* @param m1 The first matrix.
|
||||
* @param m2 The second matrix.
|
||||
* @param dst The destination matrix to add to.
|
||||
*/
|
||||
static void add(const Mat4& m1, const Mat4& m2, Mat4* dst);
|
||||
|
||||
/**
|
||||
* Computes the determinant of this matrix.
|
||||
*
|
||||
* @return The determinant.
|
||||
*/
|
||||
float determinant() const;
|
||||
|
||||
/**
|
||||
* Gets the up vector of this matrix.
|
||||
*
|
||||
* @param dst The destination vector.
|
||||
*/
|
||||
void get_up_vector(Vec3* dst) const;
|
||||
|
||||
/**
|
||||
* Gets the down vector of this matrix.
|
||||
*
|
||||
* @param dst The destination vector.
|
||||
*/
|
||||
void get_down_vector(Vec3* dst) const;
|
||||
|
||||
/**
|
||||
* Gets the left vector of this matrix.
|
||||
*
|
||||
* @param dst The destination vector.
|
||||
*/
|
||||
void get_left_vector(Vec3* dst) const;
|
||||
|
||||
/**
|
||||
* Gets the right vector of this matrix.
|
||||
*
|
||||
* @param dst The destination vector.
|
||||
*/
|
||||
void get_right_vector(Vec3* dst) const;
|
||||
|
||||
/**
|
||||
* Gets the forward vector of this matrix.
|
||||
*
|
||||
* @param dst The destination vector.
|
||||
*/
|
||||
void get_forward_vector(Vec3* dst) const;
|
||||
|
||||
/**
|
||||
* Gets the backward vector of this matrix.
|
||||
*
|
||||
* @param dst The destination vector.
|
||||
*/
|
||||
void get_back_vector(Vec3* dst) const;
|
||||
|
||||
/**
|
||||
* Inverts this matrix.
|
||||
*
|
||||
* @return true if the matrix can be inverted, false otherwise.
|
||||
*/
|
||||
bool inverse();
|
||||
|
||||
/**
|
||||
* Get the inversed matrix.
|
||||
*/
|
||||
Mat4 get_inversed() const;
|
||||
|
||||
/**
|
||||
* Determines if this matrix is equal to the identity matrix.
|
||||
*
|
||||
* @return true if the matrix is an identity matrix, false otherwise.
|
||||
*/
|
||||
bool is_identity() const;
|
||||
|
||||
/**
|
||||
* Multiplies the components of this matrix by the specified scalar.
|
||||
*
|
||||
* @param scalar The scalar value.
|
||||
*/
|
||||
void multiply(float scalar);
|
||||
|
||||
/**
|
||||
* Multiplies the components of this matrix by a scalar and stores the result in dst.
|
||||
*
|
||||
* @param scalar The scalar value.
|
||||
* @param dst A matrix to store the result in.
|
||||
*/
|
||||
void multiply(float scalar, Mat4* dst) const;
|
||||
|
||||
/**
|
||||
* Multiplies the components of the specified matrix by a scalar and stores the result in dst.
|
||||
*
|
||||
* @param mat The matrix.
|
||||
* @param scalar The scalar value.
|
||||
* @param dst A matrix to store the result in.
|
||||
*/
|
||||
static void multiply(const Mat4& mat, float scalar, Mat4* dst);
|
||||
|
||||
/**
|
||||
* Multiplies this matrix by the specified one.
|
||||
*
|
||||
* @param mat The matrix to multiply.
|
||||
*/
|
||||
void multiply(const Mat4& mat);
|
||||
|
||||
/**
|
||||
* Multiplies m1 by m2 and stores the result in dst.
|
||||
*
|
||||
* @param m1 The first matrix to multiply.
|
||||
* @param m2 The second matrix to multiply.
|
||||
* @param dst A matrix to store the result in.
|
||||
*/
|
||||
static void multiply(const Mat4& m1, const Mat4& m2, Mat4* dst);
|
||||
|
||||
/**
|
||||
* Negates this matrix.
|
||||
*/
|
||||
void negate();
|
||||
|
||||
/**
|
||||
Get the Negated matrix.
|
||||
*/
|
||||
Mat4 get_negated() const;
|
||||
|
||||
/**
|
||||
* Post-multiplies this matrix by the matrix corresponding to the
|
||||
* specified rotation about the specified axis.
|
||||
*
|
||||
* @param axis The axis to rotate about.
|
||||
* @param angle The angle (in radians).
|
||||
*/
|
||||
void rotate(const Vec3& axis, float angle);
|
||||
|
||||
/**
|
||||
* Post-multiplies this matrix by the matrix corresponding to the specified
|
||||
* rotation about the specified axis and stores the result in dst.
|
||||
*
|
||||
* @param axis The axis to rotate about.
|
||||
* @param angle The angle (in radians).
|
||||
* @param dst A matrix to store the result in.
|
||||
*/
|
||||
void rotate(const Vec3& axis, float angle, Mat4* dst) const;
|
||||
|
||||
/**
|
||||
* Post-multiplies this matrix by the matrix corresponding to the
|
||||
* specified rotation around the x-axis.
|
||||
*
|
||||
* @param angle The angle (in radians).
|
||||
*/
|
||||
void rotate_x(float angle);
|
||||
|
||||
/**
|
||||
* Post-multiplies this matrix by the matrix corresponding to the
|
||||
* specified rotation around the x-axis and stores the result in dst.
|
||||
*
|
||||
* @param angle The angle (in radians).
|
||||
* @param dst A matrix to store the result in.
|
||||
*/
|
||||
void rotate_x(float angle, Mat4* dst) const;
|
||||
|
||||
/**
|
||||
* Post-multiplies this matrix by the matrix corresponding to the
|
||||
* specified rotation around the y-axis.
|
||||
*
|
||||
* @param angle The angle (in radians).
|
||||
*/
|
||||
void rotate_y(float angle);
|
||||
|
||||
/**
|
||||
* Post-multiplies this matrix by the matrix corresponding to the
|
||||
* specified rotation around the y-axis and stores the result in dst.
|
||||
*
|
||||
* @param angle The angle (in radians).
|
||||
* @param dst A matrix to store the result in.
|
||||
*/
|
||||
void rotate_y(float angle, Mat4* dst) const;
|
||||
|
||||
/**
|
||||
* Post-multiplies this matrix by the matrix corresponding to the
|
||||
* specified rotation around the z-axis.
|
||||
*
|
||||
* @param angle The angle (in radians).
|
||||
*/
|
||||
void rotate_z(float angle);
|
||||
|
||||
/**
|
||||
* Post-multiplies this matrix by the matrix corresponding to the
|
||||
* specified rotation around the z-axis and stores the result in dst.
|
||||
*
|
||||
* @param angle The angle (in radians).
|
||||
* @param dst A matrix to store the result in.
|
||||
*/
|
||||
void rotate_z(float angle, Mat4* dst) const;
|
||||
|
||||
/**
|
||||
* Post-multiplies this matrix by the matrix corresponding to the
|
||||
* specified scale transformation.
|
||||
*
|
||||
* @param value The amount to scale along all axes.
|
||||
*/
|
||||
void scale(float value);
|
||||
|
||||
/**
|
||||
* Post-multiplies this matrix by the matrix corresponding to the
|
||||
* specified scale transformation and stores the result in dst.
|
||||
*
|
||||
* @param value The amount to scale along all axes.
|
||||
* @param dst A matrix to store the result in.
|
||||
*/
|
||||
void scale(float value, Mat4* dst) const;
|
||||
|
||||
/**
|
||||
* Post-multiplies this matrix by the matrix corresponding to the
|
||||
* specified scale transformation.
|
||||
*
|
||||
* @param xScale The amount to scale along the x-axis.
|
||||
* @param yScale The amount to scale along the y-axis.
|
||||
* @param zScale The amount to scale along the z-axis.
|
||||
*/
|
||||
void scale(float xScale, float yScale, float zScale);
|
||||
|
||||
/**
|
||||
* Post-multiplies this matrix by the matrix corresponding to the
|
||||
* specified scale transformation and stores the result in dst.
|
||||
*
|
||||
* @param xScale The amount to scale along the x-axis.
|
||||
* @param yScale The amount to scale along the y-axis.
|
||||
* @param zScale The amount to scale along the z-axis.
|
||||
* @param dst A matrix to store the result in.
|
||||
*/
|
||||
void scale(float xScale, float yScale, float zScale, Mat4* dst) const;
|
||||
|
||||
/**
|
||||
* Post-multiplies this matrix by the matrix corresponding to the
|
||||
* specified scale transformation.
|
||||
*
|
||||
* @param s The scale values along the x, y and z axes.
|
||||
*/
|
||||
void scale(const Vec3& s);
|
||||
|
||||
/**
|
||||
* Post-multiplies this matrix by the matrix corresponding to the
|
||||
* specified scale transformation and stores the result in dst.
|
||||
*
|
||||
* @param s The scale values along the x, y and z axes.
|
||||
* @param dst A matrix to store the result in.
|
||||
*/
|
||||
void scale(const Vec3& s, Mat4* dst) const;
|
||||
|
||||
/**
|
||||
* Sets the values of this matrix.
|
||||
*
|
||||
* @param m11 The first element of the first row.
|
||||
* @param m12 The second element of the first row.
|
||||
* @param m13 The third element of the first row.
|
||||
* @param m14 The fourth element of the first row.
|
||||
* @param m21 The first element of the second row.
|
||||
* @param m22 The second element of the second row.
|
||||
* @param m23 The third element of the second row.
|
||||
* @param m24 The fourth element of the second row.
|
||||
* @param m31 The first element of the third row.
|
||||
* @param m32 The second element of the third row.
|
||||
* @param m33 The third element of the third row.
|
||||
* @param m34 The fourth element of the third row.
|
||||
* @param m41 The first element of the fourth row.
|
||||
* @param m42 The second element of the fourth row.
|
||||
* @param m43 The third element of the fourth row.
|
||||
* @param m44 The fourth element of the fourth row.
|
||||
*/
|
||||
void set(float m11, float m12, float m13, float m14, float m21, float m22, float m23, float m24,
|
||||
float m31, float m32, float m33, float m34, float m41, float m42, float m43, float m44);
|
||||
|
||||
/**
|
||||
* Sets the values of this matrix to those in the specified column-major array.
|
||||
*
|
||||
* @param mat An array containing 16 elements in column-major format.
|
||||
*/
|
||||
void set(const float* mat);
|
||||
|
||||
/**
|
||||
* Sets the values of this matrix to those of the specified matrix.
|
||||
*
|
||||
* @param mat The source matrix.
|
||||
*/
|
||||
void set(const Mat4& mat);
|
||||
|
||||
/**
|
||||
* Sets this matrix to the identity matrix.
|
||||
*/
|
||||
void set_identity();
|
||||
|
||||
/**
|
||||
* Sets all elements of the current matrix to zero.
|
||||
*/
|
||||
void set_zero();
|
||||
|
||||
/**
|
||||
* Subtracts the specified matrix from the current matrix.
|
||||
*
|
||||
* @param mat The matrix to subtract.
|
||||
*/
|
||||
void subtract(const Mat4& mat);
|
||||
|
||||
/**
|
||||
* Subtracts the specified matrix from the current matrix.
|
||||
*
|
||||
* @param m1 The first matrix.
|
||||
* @param m2 The second matrix.
|
||||
* @param dst A matrix to store the result in.
|
||||
*/
|
||||
static void subtract(const Mat4& m1, const Mat4& m2, Mat4* dst);
|
||||
|
||||
/**
|
||||
* Transforms the specified point by this matrix.
|
||||
*
|
||||
* The result of the transformation is stored directly into point.
|
||||
*
|
||||
* @param point The point to transform and also a vector to hold the result in.
|
||||
*/
|
||||
inline void transform_point(Vec3* point) const {
|
||||
transform_vector(point->x, point->y, point->z, 1.0f, point);
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms the specified point by this matrix, and stores
|
||||
* the result in dst.
|
||||
*
|
||||
* @param point The point to transform.
|
||||
* @param dst A vector to store the transformed point in.
|
||||
*/
|
||||
inline void transform_point(const Vec3& point, Vec3* dst) const {
|
||||
transform_vector(point.x, point.y, point.z, 1.0f, dst);
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms the specified vector by this matrix by
|
||||
* treating the fourth (w) coordinate as zero.
|
||||
*
|
||||
* The result of the transformation is stored directly into vector.
|
||||
*
|
||||
* @param vector The vector to transform and also a vector to hold the result in.
|
||||
*/
|
||||
void transform_vector(Vec3* vector) const;
|
||||
|
||||
/**
|
||||
* Transforms the specified vector by this matrix by
|
||||
* treating the fourth (w) coordinate as zero, and stores the
|
||||
* result in dst.
|
||||
*
|
||||
* @param vector The vector to transform.
|
||||
* @param dst A vector to store the transformed vector in.
|
||||
*/
|
||||
void transform_vector(const Vec3& vector, Vec3* dst) const;
|
||||
|
||||
/**
|
||||
* Transforms the specified vector by this matrix.
|
||||
*
|
||||
* @param x The vector x-coordinate to transform by.
|
||||
* @param y The vector y-coordinate to transform by.
|
||||
* @param z The vector z-coordinate to transform by.
|
||||
* @param w The vector w-coordinate to transform by.
|
||||
* @param dst A vector to store the transformed point in.
|
||||
*/
|
||||
void transform_vector(float x, float y, float z, float w, Vec3* dst) const;
|
||||
|
||||
/**
|
||||
* Transforms the specified vector by this matrix.
|
||||
*
|
||||
* The result of the transformation is stored directly into vector.
|
||||
*
|
||||
* @param vector The vector to transform.
|
||||
*/
|
||||
void transform_vector(Vec4* vector) const;
|
||||
|
||||
/**
|
||||
* Transforms the specified vector by this matrix.
|
||||
*
|
||||
* @param vector The vector to transform.
|
||||
* @param dst A vector to store the transformed point in.
|
||||
*/
|
||||
void transform_vector(const Vec4& vector, Vec4* dst) const;
|
||||
|
||||
/**
|
||||
* Post-multiplies this matrix by the matrix corresponding to the
|
||||
* specified translation.
|
||||
*
|
||||
* @param x The amount to translate along the x-axis.
|
||||
* @param y The amount to translate along the y-axis.
|
||||
* @param z The amount to translate along the z-axis.
|
||||
*/
|
||||
void translate(float x, float y, float z);
|
||||
|
||||
/**
|
||||
* Post-multiplies this matrix by the matrix corresponding to the
|
||||
* specified translation and stores the result in dst.
|
||||
*
|
||||
* @param x The amount to translate along the x-axis.
|
||||
* @param y The amount to translate along the y-axis.
|
||||
* @param z The amount to translate along the z-axis.
|
||||
* @param dst A matrix to store the result in.
|
||||
*/
|
||||
void translate(float x, float y, float z, Mat4* dst) const;
|
||||
|
||||
/**
|
||||
* Post-multiplies this matrix by the matrix corresponding to the
|
||||
* specified translation.
|
||||
*
|
||||
* @param t The translation values along the x, y and z axes.
|
||||
*/
|
||||
void translate(const Vec3& t);
|
||||
|
||||
/**
|
||||
* Post-multiplies this matrix by the matrix corresponding to the
|
||||
* specified translation and stores the result in dst.
|
||||
*
|
||||
* @param t The translation values along the x, y and z axes.
|
||||
* @param dst A matrix to store the result in.
|
||||
*/
|
||||
void translate(const Vec3& t, Mat4* dst) const;
|
||||
|
||||
/**
|
||||
* Transposes this matrix.
|
||||
*/
|
||||
void transpose();
|
||||
|
||||
/**
|
||||
* Get the Transposed matrix.
|
||||
*/
|
||||
Mat4 get_transposed() const;
|
||||
|
||||
/**
|
||||
* Calculates the sum of this matrix with the given matrix.
|
||||
*
|
||||
* Note: this does not modify this matrix.
|
||||
*
|
||||
* @param mat The matrix to add.
|
||||
* @return The matrix sum.
|
||||
*/
|
||||
inline Mat4 operator+(const Mat4& mat) const;
|
||||
|
||||
/**
|
||||
* Adds the given matrix to this matrix.
|
||||
*
|
||||
* @param mat The matrix to add.
|
||||
* @return This matrix, after the addition occurs.
|
||||
*/
|
||||
inline Mat4& operator+=(const Mat4& mat);
|
||||
|
||||
/**
|
||||
* Calculates the difference of this matrix with the given matrix.
|
||||
*
|
||||
* Note: this does not modify this matrix.
|
||||
*
|
||||
* @param mat The matrix to subtract.
|
||||
* @return The matrix difference.
|
||||
*/
|
||||
inline Mat4 operator-(const Mat4& mat) const;
|
||||
|
||||
/**
|
||||
* Subtracts the given matrix from this matrix.
|
||||
*
|
||||
* @param mat The matrix to subtract.
|
||||
* @return This matrix, after the subtraction occurs.
|
||||
*/
|
||||
inline Mat4& operator-=(const Mat4& mat);
|
||||
|
||||
/**
|
||||
* Calculates the negation of this matrix.
|
||||
*
|
||||
* Note: this does not modify this matrix.
|
||||
*
|
||||
* @return The negation of this matrix.
|
||||
*/
|
||||
inline Mat4 operator-() const;
|
||||
|
||||
/**
|
||||
* Calculates the matrix product of this matrix with the given matrix.
|
||||
*
|
||||
* Note: this does not modify this matrix.
|
||||
*
|
||||
* @param mat The matrix to multiply by.
|
||||
* @return The matrix product.
|
||||
*/
|
||||
inline Mat4 operator*(const Mat4& mat) const;
|
||||
|
||||
/**
|
||||
* Right-multiplies this matrix by the given matrix.
|
||||
*
|
||||
* @param mat The matrix to multiply by.
|
||||
* @return This matrix, after the multiplication occurs.
|
||||
*/
|
||||
inline Mat4& operator*=(const Mat4& mat);
|
||||
|
||||
const Mat4 operator+(float scalar) const;
|
||||
Mat4& operator+=(float scalar);
|
||||
const Mat4 operator-(float scalar) const;
|
||||
Mat4& operator-=(float scalar);
|
||||
const Mat4 operator*(float scalar) const;
|
||||
Mat4& operator*=(float scalar);
|
||||
|
||||
/** equals to a matrix full of zeros */
|
||||
static const Mat4 ZERO;
|
||||
/** equals to the identity matrix */
|
||||
static const Mat4 IDENTITY;
|
||||
};
|
||||
|
||||
/**
|
||||
* Transforms the given vector by the given matrix.
|
||||
*
|
||||
* Note: this treats the given vector as a vector and not as a point.
|
||||
*
|
||||
* @param v The vector to transform.
|
||||
* @param m The matrix to transform by.
|
||||
* @return This vector, after the transformation occurs.
|
||||
*/
|
||||
inline Vec3& operator*=(Vec3& v, const Mat4& m);
|
||||
|
||||
/**
|
||||
* Transforms the given vector by the given matrix.
|
||||
*
|
||||
* Note: this treats the given vector as a vector and not as a point.
|
||||
*
|
||||
* @param m The matrix to transform by.
|
||||
* @param v The vector to transform.
|
||||
* @return The resulting transformed vector.
|
||||
*/
|
||||
inline Vec3 operator*(const Mat4& m, const Vec3& v);
|
||||
|
||||
/**
|
||||
* Transforms the given vector by the given matrix.
|
||||
*
|
||||
* Note: this treats the given vector as a vector and not as a point.
|
||||
*
|
||||
* @param v The vector to transform.
|
||||
* @param m The matrix to transform by.
|
||||
* @return This vector, after the transformation occurs.
|
||||
*/
|
||||
inline Vec4& operator*=(Vec4& v, const Mat4& m);
|
||||
|
||||
/**
|
||||
* Transforms the given vector by the given matrix.
|
||||
*
|
||||
* Note: this treats the given vector as a vector and not as a point.
|
||||
*
|
||||
* @param m The matrix to transform by.
|
||||
* @param v The vector to transform.
|
||||
* @return The resulting transformed vector.
|
||||
*/
|
||||
inline Vec4 operator*(const Mat4& m, const Vec4& v);
|
||||
|
||||
}
|
||||
|
||||
#include "mat4.inl"
|
||||
|
||||
#endif /* MAT4_H */
|
85
mediapipe/render/core/math/mat4.inl
Normal file
85
mediapipe/render/core/math/mat4.inl
Normal file
|
@ -0,0 +1,85 @@
|
|||
//
|
||||
// mat4.inl
|
||||
// BdiEngine
|
||||
//
|
||||
// Created by Wang,Renzhu on 2018/11/20.
|
||||
// Copyright © 2018年 Wang,Renzhu. All rights reserved.
|
||||
//
|
||||
|
||||
#include "mat4.hpp"
|
||||
|
||||
namespace Quaramera {
|
||||
|
||||
inline Mat4 Mat4::operator+(const Mat4& mat) const
|
||||
{
|
||||
Mat4 result(*this);
|
||||
result.add(mat);
|
||||
return result;
|
||||
}
|
||||
|
||||
inline Mat4& Mat4::operator+=(const Mat4& mat)
|
||||
{
|
||||
add(mat);
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline Mat4 Mat4::operator-(const Mat4& mat) const
|
||||
{
|
||||
Mat4 result(*this);
|
||||
result.subtract(mat);
|
||||
return result;
|
||||
}
|
||||
|
||||
inline Mat4& Mat4::operator-=(const Mat4& mat)
|
||||
{
|
||||
subtract(mat);
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline Mat4 Mat4::operator-() const
|
||||
{
|
||||
Mat4 mat(*this);
|
||||
mat.negate();
|
||||
return mat;
|
||||
}
|
||||
|
||||
inline Mat4 Mat4::operator*(const Mat4& mat) const
|
||||
{
|
||||
Mat4 result(*this);
|
||||
result.multiply(mat);
|
||||
return result;
|
||||
}
|
||||
|
||||
inline Mat4& Mat4::operator*=(const Mat4& mat)
|
||||
{
|
||||
multiply(mat);
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline Vec3& operator*=(Vec3& v, const Mat4& m)
|
||||
{
|
||||
m.transform_vector(&v);
|
||||
return v;
|
||||
}
|
||||
|
||||
inline Vec3 operator*(const Mat4& m, const Vec3& v)
|
||||
{
|
||||
Vec3 x;
|
||||
m.transform_vector(v, &x);
|
||||
return x;
|
||||
}
|
||||
|
||||
inline Vec4& operator*=(Vec4& v, const Mat4& m)
|
||||
{
|
||||
m.transform_vector(&v);
|
||||
return v;
|
||||
}
|
||||
|
||||
inline Vec4 operator*(const Mat4& m, const Vec4& v)
|
||||
{
|
||||
Vec4 x;
|
||||
m.transform_vector(v, &x);
|
||||
return x;
|
||||
}
|
||||
|
||||
}
|
132
mediapipe/render/core/math/math_utils.cpp
Normal file
132
mediapipe/render/core/math/math_utils.cpp
Normal file
|
@ -0,0 +1,132 @@
|
|||
//
|
||||
// math_utils.cpp
|
||||
// Quaramera
|
||||
//
|
||||
// Created by Wang,Renzhu on 2018/11/20.
|
||||
// Copyright © 2018年 Wang,Renzhu. All rights reserved.
|
||||
//
|
||||
|
||||
#include "math_utils.hpp"
|
||||
#include <cstring>
|
||||
|
||||
namespace Quaramera {
|
||||
|
||||
static const int MATRIX_SIZE = (sizeof(float) * 16);
|
||||
|
||||
void MathUtils::add_matrix(const float* m, float scalar, float* dst) {
|
||||
for (int i = 0; i < 16; ++i) {
|
||||
dst[i] = m[i] + scalar;
|
||||
}
|
||||
}
|
||||
|
||||
void MathUtils::add_matrix(const float* m1, const float* m2, float* dst) {
|
||||
for (int i = 0; i < 16; ++i) {
|
||||
dst[i] = m1[i] + m2[i];
|
||||
}
|
||||
}
|
||||
|
||||
void MathUtils::subtract_matrix(const float* m1, const float* m2, float* dst) {
|
||||
for (int i = 0; i < 16; ++i) {
|
||||
dst[i] = m1[i] - m2[i];
|
||||
}
|
||||
}
|
||||
|
||||
void MathUtils::multiply_matrix(const float* m, float scalar, float* dst) {
|
||||
for (int i = 0; i < 16; ++i) {
|
||||
dst[i] = m[i] * scalar;
|
||||
}
|
||||
}
|
||||
|
||||
void MathUtils::multiply_matrix(const float* m1, const float* m2, float* dst) {
|
||||
// Support the case where m1 or m2 is the same array as dst.
|
||||
float product[16];
|
||||
|
||||
product[0] = m1[0] * m2[0] + m1[4] * m2[1] + m1[8] * m2[2] + m1[12] * m2[3];
|
||||
product[1] = m1[1] * m2[0] + m1[5] * m2[1] + m1[9] * m2[2] + m1[13] * m2[3];
|
||||
product[2] = m1[2] * m2[0] + m1[6] * m2[1] + m1[10] * m2[2] + m1[14] * m2[3];
|
||||
product[3] = m1[3] * m2[0] + m1[7] * m2[1] + m1[11] * m2[2] + m1[15] * m2[3];
|
||||
|
||||
product[4] = m1[0] * m2[4] + m1[4] * m2[5] + m1[8] * m2[6] + m1[12] * m2[7];
|
||||
product[5] = m1[1] * m2[4] + m1[5] * m2[5] + m1[9] * m2[6] + m1[13] * m2[7];
|
||||
product[6] = m1[2] * m2[4] + m1[6] * m2[5] + m1[10] * m2[6] + m1[14] * m2[7];
|
||||
product[7] = m1[3] * m2[4] + m1[7] * m2[5] + m1[11] * m2[6] + m1[15] * m2[7];
|
||||
|
||||
product[8] = m1[0] * m2[8] + m1[4] * m2[9] + m1[8] * m2[10] + m1[12] * m2[11];
|
||||
product[9] = m1[1] * m2[8] + m1[5] * m2[9] + m1[9] * m2[10] + m1[13] * m2[11];
|
||||
product[10] = m1[2] * m2[8] + m1[6] * m2[9] + m1[10] * m2[10] + m1[14] * m2[11];
|
||||
product[11] = m1[3] * m2[8] + m1[7] * m2[9] + m1[11] * m2[10] + m1[15] * m2[11];
|
||||
|
||||
product[12] = m1[0] * m2[12] + m1[4] * m2[13] + m1[8] * m2[14] + m1[12] * m2[15];
|
||||
product[13] = m1[1] * m2[12] + m1[5] * m2[13] + m1[9] * m2[14] + m1[13] * m2[15];
|
||||
product[14] = m1[2] * m2[12] + m1[6] * m2[13] + m1[10] * m2[14] + m1[14] * m2[15];
|
||||
product[15] = m1[3] * m2[12] + m1[7] * m2[13] + m1[11] * m2[14] + m1[15] * m2[15];
|
||||
|
||||
memcpy(dst, product, MATRIX_SIZE);
|
||||
}
|
||||
|
||||
void MathUtils::negate_matrix(const float* m, float* dst) {
|
||||
for (int i = 0; i < 16; ++i) {
|
||||
dst[i] = -m[i];
|
||||
}
|
||||
}
|
||||
|
||||
void MathUtils::transpose_matrix(const float* m, float* dst) {
|
||||
float t[16] = {
|
||||
m[0], m[4], m[8], m[12],
|
||||
m[1], m[5], m[9], m[13],
|
||||
m[2], m[6], m[10], m[14],
|
||||
m[3], m[7], m[11], m[15]
|
||||
};
|
||||
memcpy(dst, t, MATRIX_SIZE);
|
||||
}
|
||||
|
||||
void MathUtils::transform_vec4(const float* m, float x, float y, float z, float w, float* dst) {
|
||||
dst[0] = x * m[0] + y * m[4] + z * m[8] + w * m[12];
|
||||
dst[1] = x * m[1] + y * m[5] + z * m[9] + w * m[13];
|
||||
dst[2] = x * m[2] + y * m[6] + z * m[10] + w * m[14];
|
||||
}
|
||||
|
||||
void MathUtils::transform_vec4(const float* m, const float* v, float* dst) {
|
||||
// Handle case where v == dst.
|
||||
float x = v[0] * m[0] + v[1] * m[4] + v[2] * m[8] + v[3] * m[12];
|
||||
float y = v[0] * m[1] + v[1] * m[5] + v[2] * m[9] + v[3] * m[13];
|
||||
float z = v[0] * m[2] + v[1] * m[6] + v[2] * m[10] + v[3] * m[14];
|
||||
float w = v[0] * m[3] + v[1] * m[7] + v[2] * m[11] + v[3] * m[15];
|
||||
|
||||
dst[0] = x;
|
||||
dst[1] = y;
|
||||
dst[2] = z;
|
||||
dst[3] = w;
|
||||
}
|
||||
|
||||
void MathUtils::cross_vec3(const float* v1, const float* v2, float* dst) {
|
||||
float x = (v1[1] * v2[2]) - (v1[2] * v2[1]);
|
||||
float y = (v1[2] * v2[0]) - (v1[0] * v2[2]);
|
||||
float z = (v1[0] * v2[1]) - (v1[1] * v2[0]);
|
||||
|
||||
dst[0] = x;
|
||||
dst[1] = y;
|
||||
dst[2] = z;
|
||||
}
|
||||
|
||||
void MathUtils::smooth(float* x, float target, float elapsedTime, float responseTime)
|
||||
{
|
||||
if (elapsedTime > 0) {
|
||||
*x += (target - *x) * elapsedTime / (elapsedTime + responseTime);
|
||||
}
|
||||
}
|
||||
|
||||
void MathUtils::smooth(float* x, float target, float elapsedTime, float riseTime, float fallTime)
|
||||
{
|
||||
if (elapsedTime > 0) {
|
||||
float delta = target - *x;
|
||||
*x += delta * elapsedTime / (elapsedTime + (delta > 0 ? riseTime : fallTime));
|
||||
}
|
||||
}
|
||||
|
||||
float MathUtils::lerp(float from, float to, float alpha)
|
||||
{
|
||||
return from * (1.0f - alpha) + to * alpha;
|
||||
}
|
||||
|
||||
}
|
99
mediapipe/render/core/math/math_utils.hpp
Normal file
99
mediapipe/render/core/math/math_utils.hpp
Normal file
|
@ -0,0 +1,99 @@
|
|||
//
|
||||
// math_utils.h
|
||||
// Quaramera
|
||||
//
|
||||
// Created by Wang,Renzhu on 2018/11/20.
|
||||
// Copyright © 2018年 Wang,Renzhu. All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef DI_ENGINE_MATH_UTILS_H
|
||||
#define DI_ENGINE_MATH_UTILS_H
|
||||
|
||||
#include "mat4.hpp"
|
||||
#include "vec2.hpp"
|
||||
#include "vec3.hpp"
|
||||
#include "vec4.hpp"
|
||||
#include <cstring>
|
||||
|
||||
#define MATH_DEG_TO_RAD(x) ((x) * 0.0174532925f)
|
||||
#define MATH_RAD_TO_DEG(x) ((x)* 57.29577951f)
|
||||
|
||||
#define MATH_FLOAT_SMALL 1.0e-37f
|
||||
#define MATH_TOLERANCE 2e-37f
|
||||
#define MATH_PIOVER2 1.57079632679489661923f
|
||||
#define MATH_EPSILON 0.000001f
|
||||
|
||||
#define MATH_FLOAT_EQUAL(src, dst) (((src) >= (dst) - MATH_EPSILON) && ((src) <= (dst) + MATH_EPSILON))
|
||||
|
||||
|
||||
namespace Quaramera {
|
||||
|
||||
class MathUtils
|
||||
{
|
||||
public:
|
||||
static void add_matrix(const float* m, float scalar, float* dst);
|
||||
|
||||
static void add_matrix(const float* m1, const float* m2, float* dst);
|
||||
|
||||
static void subtract_matrix(const float* m1, const float* m2, float* dst);
|
||||
|
||||
static void multiply_matrix(const float* m, float scalar, float* dst);
|
||||
|
||||
static void multiply_matrix(const float* m1, const float* m2, float* dst);
|
||||
|
||||
static void negate_matrix(const float* m, float* dst);
|
||||
|
||||
static void transpose_matrix(const float* m, float* dst);
|
||||
|
||||
static void transform_vec4(const float* m, float x, float y, float z, float w, float* dst);
|
||||
|
||||
static void transform_vec4(const float* m, const float* v, float* dst);
|
||||
|
||||
static void cross_vec3(const float* v1, const float* v2, float* dst);
|
||||
|
||||
public:
|
||||
/**
|
||||
* Updates the given scalar towards the given target using a smoothing function.
|
||||
* The given response time determines the amount of smoothing (lag). A longer
|
||||
* response time yields a smoother result and more lag. To force the scalar to
|
||||
* follow the target closely, provide a response time that is very small relative
|
||||
* to the given elapsed time.
|
||||
*
|
||||
* @param x the scalar to update.
|
||||
* @param target target value.
|
||||
* @param elapsedTime elapsed time between calls.
|
||||
* @param responseTime response time (in the same units as elapsedTime).
|
||||
*/
|
||||
static void smooth(float* x, float target, float elapsedTime, float responseTime);
|
||||
|
||||
/**
|
||||
* Updates the given scalar towards the given target using a smoothing function.
|
||||
* The given rise and fall times determine the amount of smoothing (lag). Longer
|
||||
* rise and fall times yield a smoother result and more lag. To force the scalar to
|
||||
* follow the target closely, provide rise and fall times that are very small relative
|
||||
* to the given elapsed time.
|
||||
*
|
||||
* @param x the scalar to update.
|
||||
* @param target target value.
|
||||
* @param elapsedTime elapsed time between calls.
|
||||
* @param riseTime response time for rising slope (in the same units as elapsedTime).
|
||||
* @param fallTime response time for falling slope (in the same units as elapsedTime).
|
||||
*/
|
||||
static void smooth(float* x, float target, float elapsedTime, float riseTime, float fallTime);
|
||||
|
||||
/**
|
||||
* Linearly interpolates between from value to to value by alpha which is in
|
||||
* the range [0,1]
|
||||
*
|
||||
* @param from the from value.
|
||||
* @param to the to value.
|
||||
* @param alpha the alpha value between [0,1]
|
||||
*
|
||||
* @return interpolated float value
|
||||
*/
|
||||
static float lerp(float from, float to, float alpha);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif /* DI_ENGINE_MATH_UTILS_H */
|
174
mediapipe/render/core/math/vec2.cpp
Normal file
174
mediapipe/render/core/math/vec2.cpp
Normal file
|
@ -0,0 +1,174 @@
|
|||
//
|
||||
// vec2.cpp
|
||||
// Quaramera
|
||||
//
|
||||
// Created by Wang,Renzhu on 2018/11/20.
|
||||
// Copyright © 2018年 Wang,Renzhu. All rights reserved.
|
||||
//
|
||||
|
||||
#include "vec2.hpp"
|
||||
#include "math_utils.hpp"
|
||||
namespace Quaramera {
|
||||
|
||||
float Vec2::angle(const Vec2& v1, const Vec2& v2)
|
||||
{
|
||||
float dz = v1.x * v2.y - v1.y * v2.x;
|
||||
return atan2f(fabsf(dz) + MATH_FLOAT_SMALL, dot(v1, v2));
|
||||
}
|
||||
|
||||
void Vec2::add(const Vec2& v1, const Vec2& v2, Vec2* dst)
|
||||
{
|
||||
if (dst) {
|
||||
dst->x = v1.x + v2.x;
|
||||
dst->y = v1.y + v2.y;
|
||||
}
|
||||
}
|
||||
|
||||
void Vec2::clamp(const Vec2& min, const Vec2& max)
|
||||
{
|
||||
// Clamp the x value.
|
||||
if (x < min.x)
|
||||
x = min.x;
|
||||
if (x > max.x)
|
||||
x = max.x;
|
||||
|
||||
// Clamp the y value.
|
||||
if (y < min.y)
|
||||
y = min.y;
|
||||
if (y > max.y)
|
||||
y = max.y;
|
||||
}
|
||||
|
||||
void Vec2::clamp(const Vec2& v, const Vec2& min, const Vec2& max, Vec2* dst)
|
||||
{
|
||||
if (dst) {
|
||||
// Clamp the x value.
|
||||
dst->x = v.x;
|
||||
if (dst->x < min.x)
|
||||
dst->x = min.x;
|
||||
if (dst->x > max.x)
|
||||
dst->x = max.x;
|
||||
|
||||
// Clamp the y value.
|
||||
dst->y = v.y;
|
||||
if (dst->y < min.y)
|
||||
dst->y = min.y;
|
||||
if (dst->y > max.y)
|
||||
dst->y = max.y;
|
||||
}
|
||||
}
|
||||
|
||||
float Vec2::distance(const Vec2& v) const
|
||||
{
|
||||
float dx = v.x - x;
|
||||
float dy = v.y - y;
|
||||
|
||||
return std::sqrt(dx * dx + dy * dy);
|
||||
}
|
||||
|
||||
float Vec2::dot(const Vec2& v1, const Vec2& v2)
|
||||
{
|
||||
return (v1.x * v2.x + v1.y * v2.y);
|
||||
}
|
||||
|
||||
float Vec2::length() const
|
||||
{
|
||||
return std::sqrt(x * x + y * y);
|
||||
}
|
||||
|
||||
void Vec2::normalize()
|
||||
{
|
||||
float n = x * x + y * y;
|
||||
// Already normalized.
|
||||
if (n == 1.0f)
|
||||
return;
|
||||
|
||||
n = std::sqrt(n);
|
||||
// Too close to zero.
|
||||
if (n < MATH_TOLERANCE)
|
||||
return;
|
||||
|
||||
n = 1.0f / n;
|
||||
x *= n;
|
||||
y *= n;
|
||||
}
|
||||
|
||||
Vec2 Vec2::get_normalized() const
|
||||
{
|
||||
Vec2 v(*this);
|
||||
v.normalize();
|
||||
return v;
|
||||
}
|
||||
|
||||
void Vec2::rotate(const Vec2& point, float angle)
|
||||
{
|
||||
float sinAngle = std::sin(angle);
|
||||
float cosAngle = std::cos(angle);
|
||||
|
||||
if (point.is_zero())
|
||||
{
|
||||
float tempX = x * cosAngle - y * sinAngle;
|
||||
y = y * cosAngle + x * sinAngle;
|
||||
x = tempX;
|
||||
}
|
||||
else
|
||||
{
|
||||
float tempX = x - point.x;
|
||||
float tempY = y - point.y;
|
||||
|
||||
x = tempX * cosAngle - tempY * sinAngle + point.x;
|
||||
y = tempY * cosAngle + tempX * sinAngle + point.y;
|
||||
}
|
||||
}
|
||||
|
||||
void Vec2::set(const float* array)
|
||||
{
|
||||
if (array) {
|
||||
x = array[0];
|
||||
y = array[1];
|
||||
}
|
||||
}
|
||||
|
||||
void Vec2::subtract(const Vec2& v1, const Vec2& v2, Vec2* dst)
|
||||
{
|
||||
if (dst) {
|
||||
dst->x = v1.x - v2.x;
|
||||
dst->y = v1.y - v2.y;
|
||||
}
|
||||
}
|
||||
|
||||
bool Vec2::equals(const Vec2& target) const
|
||||
{
|
||||
return (std::abs(this->x - target.x) < MATH_EPSILON)
|
||||
&& (std::abs(this->y - target.y) < MATH_EPSILON);
|
||||
}
|
||||
|
||||
float Vec2::get_angle(const Vec2& other) const
|
||||
{
|
||||
Vec2 a2 = get_normalized();
|
||||
Vec2 b2 = other.get_normalized();
|
||||
float angle = atan2f(a2.cross(b2), a2.dot(b2));
|
||||
if (std::abs(angle) < MATH_EPSILON) return 0.f;
|
||||
return angle;
|
||||
}
|
||||
|
||||
Vec2 Vec2::rotate_by_angle(const Vec2& pivot, float angle) const
|
||||
{
|
||||
return pivot + (*this - pivot).rotate(Vec2::for_angle(angle));
|
||||
}
|
||||
|
||||
const Vec2 Vec2::ZERO(0.0f, 0.0f);
|
||||
const Vec2 Vec2::ONE(1.0f, 1.0f);
|
||||
const Vec2 Vec2::UNIT_X(1.0f, 0.0f);
|
||||
const Vec2 Vec2::UNIT_Y(0.0f, 1.0f);
|
||||
const Vec2 Vec2::ANCHOR_MIDDLE(0.5f, 0.5f);
|
||||
const Vec2 Vec2::ANCHOR_BOTTOM_LEFT(0.0f, 0.0f);
|
||||
const Vec2 Vec2::ANCHOR_TOP_LEFT(0.0f, 1.0f);
|
||||
const Vec2 Vec2::ANCHOR_BOTTOM_RIGHT(1.0f, 0.0f);
|
||||
const Vec2 Vec2::ANCHOR_TOP_RIGHT(1.0f, 1.0f);
|
||||
const Vec2 Vec2::ANCHOR_MIDDLE_RIGHT(1.0f, 0.5f);
|
||||
const Vec2 Vec2::ANCHOR_MIDDLE_LEFT(0.0f, 0.5f);
|
||||
const Vec2 Vec2::ANCHOR_MIDDLE_TOP(0.5f, 1.0f);
|
||||
const Vec2 Vec2::ANCHOR_MIDDLE_BOTTOM(0.5f, 0.0f);
|
||||
|
||||
}
|
615
mediapipe/render/core/math/vec2.hpp
Normal file
615
mediapipe/render/core/math/vec2.hpp
Normal file
|
@ -0,0 +1,615 @@
|
|||
//
|
||||
// vec2.h
|
||||
// Quaramera
|
||||
//
|
||||
// Created by Wang,Renzhu on 2018/11/20.
|
||||
// Copyright © 2018年 Wang,Renzhu. All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef VEC2_H
|
||||
#define VEC2_H
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
|
||||
namespace Quaramera {
|
||||
|
||||
inline float clampf(float value, float min_inclusive, float max_inclusive) {
|
||||
if (min_inclusive > max_inclusive) {
|
||||
std::swap(min_inclusive, max_inclusive);
|
||||
}
|
||||
return value < min_inclusive ? min_inclusive : value < max_inclusive ? value : max_inclusive;
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines a 2-element floating point vector.
|
||||
*/
|
||||
class Vec2
|
||||
{
|
||||
public:
|
||||
float x;
|
||||
float y;
|
||||
|
||||
/**
|
||||
* Constructs a new vector initialized to all zeros.
|
||||
*/
|
||||
Vec2();
|
||||
|
||||
/**
|
||||
* Constructs a new vector initialized to the specified values.
|
||||
*
|
||||
* @param xx The x coordinate.
|
||||
* @param yy The y coordinate.
|
||||
*/
|
||||
Vec2(float xx, float yy);
|
||||
|
||||
/**
|
||||
* Constructs a new vector from the values in the specified array.
|
||||
*
|
||||
* @param array An array containing the elements of the vector in the order x, y.
|
||||
*/
|
||||
Vec2(const float* array);
|
||||
|
||||
/**
|
||||
* Constructs a vector that describes the direction between the specified points.
|
||||
*
|
||||
* @param p1 The first point.
|
||||
* @param p2 The second point.
|
||||
*/
|
||||
Vec2(const Vec2& p1, const Vec2& p2);
|
||||
|
||||
/**
|
||||
* Constructs a new vector that is a copy of the specified vector.
|
||||
*
|
||||
* @param copy The vector to copy.
|
||||
*/
|
||||
Vec2(const Vec2& copy);
|
||||
|
||||
/**
|
||||
* Indicates whether this vector contains all zeros.
|
||||
*
|
||||
* @return true if this vector contains all zeros, false otherwise.
|
||||
*/
|
||||
inline bool is_zero() const;
|
||||
|
||||
/**
|
||||
* Indicates whether this vector contains all ones.
|
||||
*
|
||||
* @return true if this vector contains all ones, false otherwise.
|
||||
*/
|
||||
inline bool is_one() const;
|
||||
|
||||
/**
|
||||
* Returns the angle (in radians) between the specified vectors.
|
||||
*
|
||||
* @param v1 The first vector.
|
||||
* @param v2 The second vector.
|
||||
*
|
||||
* @return The angle between the two vectors (in radians).
|
||||
*/
|
||||
static float angle(const Vec2& v1, const Vec2& v2);
|
||||
|
||||
/**
|
||||
* Adds the elements of the specified vector to this one.
|
||||
*
|
||||
* @param v The vector to add.
|
||||
*/
|
||||
inline void add(const Vec2& v);
|
||||
|
||||
/**
|
||||
* Adds the specified vectors and stores the result in dst.
|
||||
*
|
||||
* @param v1 The first vector.
|
||||
* @param v2 The second vector.
|
||||
* @param dst A vector to store the result in.
|
||||
*/
|
||||
static void add(const Vec2& v1, const Vec2& v2, Vec2* dst);
|
||||
|
||||
/**
|
||||
* Clamps this vector within the specified range.
|
||||
*
|
||||
* @param min The minimum value.
|
||||
* @param max The maximum value.
|
||||
*/
|
||||
void clamp(const Vec2& min, const Vec2& max);
|
||||
|
||||
/**
|
||||
* Clamps the specified vector within the specified range and returns it in dst.
|
||||
*
|
||||
* @param v The vector to clamp.
|
||||
* @param min The minimum value.
|
||||
* @param max The maximum value.
|
||||
* @param dst A vector to store the result in.
|
||||
*/
|
||||
static void clamp(const Vec2& v, const Vec2& min, const Vec2& max, Vec2* dst);
|
||||
|
||||
/**
|
||||
* Returns the distance between this vector and v.
|
||||
*
|
||||
* @param v The other vector.
|
||||
*
|
||||
* @return The distance between this vector and v.
|
||||
*
|
||||
* @see distanceSquared
|
||||
*/
|
||||
float distance(const Vec2& v) const;
|
||||
|
||||
/**
|
||||
* Returns the squared distance between this vector and v.
|
||||
*
|
||||
* When it is not necessary to get the exact distance between
|
||||
* two vectors (for example, when simply comparing the
|
||||
* distance between different vectors), it is advised to use
|
||||
* this method instead of distance.
|
||||
*
|
||||
* @param v The other vector.
|
||||
*
|
||||
* @return The squared distance between this vector and v.
|
||||
*
|
||||
* @see distance
|
||||
*/
|
||||
inline float distance_squared(const Vec2& v) const;
|
||||
|
||||
/**
|
||||
* Returns the dot product of this vector and the specified vector.
|
||||
*
|
||||
* @param v The vector to compute the dot product with.
|
||||
*
|
||||
* @return The dot product.
|
||||
*/
|
||||
inline float dot(const Vec2& v) const;
|
||||
|
||||
/**
|
||||
* Returns the dot product between the specified vectors.
|
||||
*
|
||||
* @param v1 The first vector.
|
||||
* @param v2 The second vector.
|
||||
*
|
||||
* @return The dot product between the vectors.
|
||||
*/
|
||||
static float dot(const Vec2& v1, const Vec2& v2);
|
||||
|
||||
/**
|
||||
* Computes the length of this vector.
|
||||
*
|
||||
* @return The length of the vector.
|
||||
*
|
||||
* @see lengthSquared
|
||||
*/
|
||||
float length() const;
|
||||
|
||||
/**
|
||||
* Returns the squared length of this vector.
|
||||
*
|
||||
* When it is not necessary to get the exact length of a
|
||||
* vector (for example, when simply comparing the lengths of
|
||||
* different vectors), it is advised to use this method
|
||||
* instead of length.
|
||||
*
|
||||
* @return The squared length of the vector.
|
||||
*
|
||||
* @see length
|
||||
*/
|
||||
inline float length_squared() const;
|
||||
|
||||
/**
|
||||
* Negates this vector.
|
||||
*/
|
||||
inline void negate();
|
||||
|
||||
/**
|
||||
* Normalizes this vector.
|
||||
*
|
||||
* This method normalizes this Vec2 so that it is of
|
||||
* unit length (in other words, the length of the vector
|
||||
* after calling this method will be 1.0f). If the vector
|
||||
* already has unit length or if the length of the vector
|
||||
* is zero, this method does nothing.
|
||||
*/
|
||||
void normalize();
|
||||
|
||||
/**
|
||||
Get the normalized vector.
|
||||
*/
|
||||
Vec2 get_normalized() const;
|
||||
|
||||
/**
|
||||
* Scales all elements of this vector by the specified value.
|
||||
*
|
||||
* @param scalar The scalar value.
|
||||
*/
|
||||
inline void scale(float scalar);
|
||||
|
||||
/**
|
||||
* Scales each element of this vector by the matching component of scale.
|
||||
*
|
||||
* @param scale The vector to scale by.
|
||||
*/
|
||||
inline void scale(const Vec2& scale);
|
||||
|
||||
/**
|
||||
* Rotates this vector by angle (specified in radians) around the given point.
|
||||
*
|
||||
* @param point The point to rotate around.
|
||||
* @param angle The angle to rotate by (in radians).
|
||||
*/
|
||||
void rotate(const Vec2& point, float angle);
|
||||
|
||||
/**
|
||||
* Sets the elements of this vector to the specified values.
|
||||
*
|
||||
* @param xx The new x coordinate.
|
||||
* @param yy The new y coordinate.
|
||||
*/
|
||||
inline void set(float xx, float yy);
|
||||
|
||||
/**
|
||||
* Sets the elements of this vector from the values in the specified array.
|
||||
*
|
||||
* @param array An array containing the elements of the vector in the order x, y.
|
||||
*/
|
||||
void set(const float* array);
|
||||
|
||||
/**
|
||||
* Sets the elements of this vector to those in the specified vector.
|
||||
*
|
||||
* @param v The vector to copy.
|
||||
*/
|
||||
inline void set(const Vec2& v);
|
||||
|
||||
/**
|
||||
* Sets this vector to the directional vector between the specified points.
|
||||
*
|
||||
* @param p1 The first point.
|
||||
* @param p2 The second point.
|
||||
*/
|
||||
inline void set(const Vec2& p1, const Vec2& p2);
|
||||
|
||||
/**
|
||||
* Sets the elements of this vector to zero.
|
||||
*/
|
||||
inline void set_zero();
|
||||
|
||||
/**
|
||||
* Subtracts this vector and the specified vector as (this - v)
|
||||
* and stores the result in this vector.
|
||||
*
|
||||
* @param v The vector to subtract.
|
||||
*/
|
||||
inline void subtract(const Vec2& v);
|
||||
|
||||
/**
|
||||
* Subtracts the specified vectors and stores the result in dst.
|
||||
* The resulting vector is computed as (v1 - v2).
|
||||
*
|
||||
* @param v1 The first vector.
|
||||
* @param v2 The second vector.
|
||||
* @param dst The destination vector.
|
||||
*/
|
||||
static void subtract(const Vec2& v1, const Vec2& v2, Vec2* dst);
|
||||
|
||||
/**
|
||||
* Updates this vector towards the given target using a smoothing function.
|
||||
* The given response time determines the amount of smoothing (lag). A longer
|
||||
* response time yields a smoother result and more lag. To force this vector to
|
||||
* follow the target closely, provide a response time that is very small relative
|
||||
* to the given elapsed time.
|
||||
*
|
||||
* @param target target value.
|
||||
* @param elapsedTime elapsed time between calls.
|
||||
* @param responseTime response time (in the same units as elapsedTime).
|
||||
*/
|
||||
inline void smooth(const Vec2& target, float elapsedTime, float responseTime);
|
||||
|
||||
/**
|
||||
* Calculates the sum of this vector with the given vector.
|
||||
*
|
||||
* Note: this does not modify this vector.
|
||||
*
|
||||
* @param v The vector to add.
|
||||
* @return The vector sum.
|
||||
*/
|
||||
inline Vec2 operator+(const Vec2& v) const;
|
||||
|
||||
/**
|
||||
* Adds the given vector to this vector.
|
||||
*
|
||||
* @param v The vector to add.
|
||||
* @return This vector, after the addition occurs.
|
||||
*/
|
||||
inline Vec2& operator+=(const Vec2& v);
|
||||
|
||||
/**
|
||||
* Calculates the sum of this vector with the given vector.
|
||||
*
|
||||
* Note: this does not modify this vector.
|
||||
*
|
||||
* @param v The vector to add.
|
||||
* @return The vector sum.
|
||||
*/
|
||||
inline Vec2 operator-(const Vec2& v) const;
|
||||
|
||||
/**
|
||||
* Subtracts the given vector from this vector.
|
||||
*
|
||||
* @param v The vector to subtract.
|
||||
* @return This vector, after the subtraction occurs.
|
||||
*/
|
||||
inline Vec2& operator-=(const Vec2& v);
|
||||
|
||||
/**
|
||||
* Calculates the negation of this vector.
|
||||
*
|
||||
* Note: this does not modify this vector.
|
||||
*
|
||||
* @return The negation of this vector.
|
||||
*/
|
||||
inline Vec2 operator-() const;
|
||||
|
||||
/**
|
||||
* Calculates the scalar product of this vector with the given value.
|
||||
*
|
||||
* Note: this does not modify this vector.
|
||||
*
|
||||
* @param s The value to scale by.
|
||||
* @return The scaled vector.
|
||||
*/
|
||||
inline Vec2 operator*(float s) const;
|
||||
|
||||
/**
|
||||
* Scales this vector by the given value.
|
||||
*
|
||||
* @param s The value to scale by.
|
||||
* @return This vector, after the scale occurs.
|
||||
*/
|
||||
inline Vec2& operator*=(float s);
|
||||
|
||||
/**
|
||||
* Returns the components of this vector divided by the given constant
|
||||
*
|
||||
* Note: this does not modify this vector.
|
||||
*
|
||||
* @param s the constant to divide this vector with
|
||||
* @return a smaller vector
|
||||
*/
|
||||
inline Vec2 operator/(float s) const;
|
||||
|
||||
/**
|
||||
* Determines if this vector is less than the given vector.
|
||||
*
|
||||
* @param v The vector to compare against.
|
||||
*
|
||||
* @return True if this vector is less than the given vector, false otherwise.
|
||||
*/
|
||||
inline bool operator<(const Vec2& v) const;
|
||||
|
||||
/**
|
||||
* Determines if this vector is greater than the given vector.
|
||||
*
|
||||
* @param v The vector to compare against.
|
||||
*
|
||||
* @return True if this vector is greater than the given vector, false otherwise.
|
||||
*/
|
||||
inline bool operator>(const Vec2& v) const;
|
||||
|
||||
/**
|
||||
* Determines if this vector is equal to the given vector.
|
||||
*
|
||||
* @param v The vector to compare against.
|
||||
*
|
||||
* @return True if this vector is equal to the given vector, false otherwise.
|
||||
*/
|
||||
inline bool operator==(const Vec2& v) const;
|
||||
|
||||
/**
|
||||
* Determines if this vector is not equal to the given vector.
|
||||
*
|
||||
* @param v The vector to compare against.
|
||||
*
|
||||
* @return True if this vector is not equal to the given vector, false otherwise.
|
||||
*/
|
||||
inline bool operator!=(const Vec2& v) const;
|
||||
|
||||
//code added compatible for Point
|
||||
public:
|
||||
/**
|
||||
* @js NA
|
||||
* @lua NA
|
||||
*/
|
||||
inline void set_point(float xx, float yy);
|
||||
/**
|
||||
* @js NA
|
||||
*/
|
||||
bool equals(const Vec2& target) const;
|
||||
|
||||
/** Calculates distance between point an origin
|
||||
@return float
|
||||
@since v2.1.4
|
||||
* @js NA
|
||||
* @lua NA
|
||||
*/
|
||||
inline float get_length() const {
|
||||
return sqrtf(x*x + y*y);
|
||||
}
|
||||
|
||||
/** Calculates the square length of a Vec2 (not calling sqrt() )
|
||||
@return float
|
||||
@since v2.1.4
|
||||
* @js NA
|
||||
* @lua NA
|
||||
*/
|
||||
inline float get_length_sq() const {
|
||||
return dot(*this); //x*x + y*y;
|
||||
}
|
||||
|
||||
/** Calculates the square distance between two points (not calling sqrt() )
|
||||
@return float
|
||||
@since v2.1.4
|
||||
* @js NA
|
||||
* @lua NA
|
||||
*/
|
||||
inline float get_distance_sq(const Vec2& other) const {
|
||||
return (*this - other).get_length_sq();
|
||||
}
|
||||
|
||||
/** Calculates the distance between two points
|
||||
@return float
|
||||
@since v2.1.4
|
||||
* @js NA
|
||||
* @lua NA
|
||||
*/
|
||||
inline float get_distance(const Vec2& other) const {
|
||||
return (*this - other).get_length();
|
||||
}
|
||||
|
||||
/** @returns the angle in radians between this vector and the x axis
|
||||
@since v2.1.4
|
||||
* @js NA
|
||||
* @lua NA
|
||||
*/
|
||||
inline float get_angle() const {
|
||||
return atan2f(y, x);
|
||||
}
|
||||
|
||||
/** @returns the angle in radians between two vector directions
|
||||
@since v2.1.4
|
||||
* @js NA
|
||||
* @lua NA
|
||||
*/
|
||||
float get_angle(const Vec2& other) const;
|
||||
|
||||
/** Calculates cross product of two points.
|
||||
@return float
|
||||
@since v2.1.4
|
||||
* @js NA
|
||||
* @lua NA
|
||||
*/
|
||||
inline float cross(const Vec2& other) const {
|
||||
return x*other.y - y*other.x;
|
||||
}
|
||||
|
||||
/** Calculates midpoint between two points.
|
||||
@return Vec2
|
||||
@since v3.0
|
||||
* @js NA
|
||||
* @lua NA
|
||||
*/
|
||||
inline Vec2 get_mid_point(const Vec2& other) const {
|
||||
return Vec2((x + other.x) / 2.0f, (y + other.y) / 2.0f);
|
||||
}
|
||||
|
||||
/** Clamp a point between from and to.
|
||||
@since v3.0
|
||||
* @js NA
|
||||
* @lua NA
|
||||
*/
|
||||
inline Vec2 get_clamp_point(const Vec2& min_inclusive, const Vec2& max_inclusive) const {
|
||||
return Vec2(clampf(x, min_inclusive.x, max_inclusive.x), clampf(y, min_inclusive.y, max_inclusive.y));
|
||||
}
|
||||
|
||||
/** Calculates the projection of this over other.
|
||||
@return Vec2
|
||||
@since v2.1.4
|
||||
* @js NA
|
||||
* @lua NA
|
||||
*/
|
||||
inline Vec2 project(const Vec2& other) const {
|
||||
return other * (dot(other)/other.dot(other));
|
||||
}
|
||||
|
||||
/** Complex multiplication of two points ("rotates" two points).
|
||||
@return Vec2 vector with an angle of this.getAngle() + other.getAngle(),
|
||||
and a length of this.getLength() * other.getLength().
|
||||
@since v2.1.4
|
||||
* @js NA
|
||||
* @lua NA
|
||||
*/
|
||||
inline Vec2 rotate(const Vec2& other) const {
|
||||
return Vec2(x*other.x - y*other.y, x*other.y + y*other.x);
|
||||
}
|
||||
|
||||
/** Unrotates two points.
|
||||
@return Vec2 vector with an angle of this.getAngle() - other.getAngle(),
|
||||
and a length of this.getLength() * other.getLength().
|
||||
@since v2.1.4
|
||||
* @js NA
|
||||
* @lua NA
|
||||
*/
|
||||
inline Vec2 unrotate(const Vec2& other) const {
|
||||
return Vec2(x*other.x + y*other.y, y*other.x - x*other.y);
|
||||
}
|
||||
|
||||
/** Linear Interpolation between two points a and b
|
||||
@returns
|
||||
alpha == 0 ? a
|
||||
alpha == 1 ? b
|
||||
otherwise a value between a..b
|
||||
@since v2.1.4
|
||||
* @js NA
|
||||
* @lua NA
|
||||
*/
|
||||
inline Vec2 lerp(const Vec2& other, float alpha) const {
|
||||
return *this * (1.f - alpha) + other * alpha;
|
||||
}
|
||||
|
||||
/** Rotates a point counter clockwise by the angle around a pivot
|
||||
@param pivot is the pivot, naturally
|
||||
@param angle is the angle of rotation ccw in radians
|
||||
@returns the rotated point
|
||||
@since v2.1.4
|
||||
* @js NA
|
||||
* @lua NA
|
||||
*/
|
||||
Vec2 rotate_by_angle(const Vec2& pivot, float angle) const;
|
||||
|
||||
/**
|
||||
* @js NA
|
||||
* @lua NA
|
||||
*/
|
||||
static inline Vec2 for_angle(const float a) {
|
||||
return Vec2(cosf(a), sinf(a));
|
||||
}
|
||||
|
||||
/** equals to Vec2(0,0) */
|
||||
static const Vec2 ZERO;
|
||||
/** equals to Vec2(1,1) */
|
||||
static const Vec2 ONE;
|
||||
/** equals to Vec2(1,0) */
|
||||
static const Vec2 UNIT_X;
|
||||
/** equals to Vec2(0,1) */
|
||||
static const Vec2 UNIT_Y;
|
||||
/** equals to Vec2(0.5, 0.5) */
|
||||
static const Vec2 ANCHOR_MIDDLE;
|
||||
/** equals to Vec2(0, 0) */
|
||||
static const Vec2 ANCHOR_BOTTOM_LEFT;
|
||||
/** equals to Vec2(0, 1) */
|
||||
static const Vec2 ANCHOR_TOP_LEFT;
|
||||
/** equals to Vec2(1, 0) */
|
||||
static const Vec2 ANCHOR_BOTTOM_RIGHT;
|
||||
/** equals to Vec2(1, 1) */
|
||||
static const Vec2 ANCHOR_TOP_RIGHT;
|
||||
/** equals to Vec2(1, 0.5) */
|
||||
static const Vec2 ANCHOR_MIDDLE_RIGHT;
|
||||
/** equals to Vec2(0, 0.5) */
|
||||
static const Vec2 ANCHOR_MIDDLE_LEFT;
|
||||
/** equals to Vec2(0.5, 1) */
|
||||
static const Vec2 ANCHOR_MIDDLE_TOP;
|
||||
/** equals to Vec2(0.5, 0) */
|
||||
static const Vec2 ANCHOR_MIDDLE_BOTTOM;
|
||||
};
|
||||
|
||||
/**
|
||||
* Calculates the scalar product of the given vector with the given value.
|
||||
*
|
||||
* @param x The value to scale by.
|
||||
* @param v The vector to scale.
|
||||
* @return The scaled vector.
|
||||
*/
|
||||
inline Vec2 operator*(float x, const Vec2& v);
|
||||
|
||||
typedef Vec2 Point;
|
||||
}
|
||||
|
||||
#include "vec2.inl"
|
||||
|
||||
#endif /* VEC2_H */
|
216
mediapipe/render/core/math/vec2.inl
Normal file
216
mediapipe/render/core/math/vec2.inl
Normal file
|
@ -0,0 +1,216 @@
|
|||
//
|
||||
// vec2.inl
|
||||
// BdiEngine
|
||||
//
|
||||
// Created by Wang,Renzhu on 2018/11/20.
|
||||
// Copyright © 2018年 Wang,Renzhu. All rights reserved.
|
||||
//
|
||||
|
||||
#include "vec2.hpp"
|
||||
|
||||
namespace Quaramera {
|
||||
|
||||
inline Vec2::Vec2() : x(0.0f), y(0.0f)
|
||||
{
|
||||
}
|
||||
|
||||
inline Vec2::Vec2(float xx, float yy) : x(xx), y(yy)
|
||||
{
|
||||
}
|
||||
|
||||
inline Vec2::Vec2(const float* array)
|
||||
{
|
||||
set(array);
|
||||
}
|
||||
|
||||
inline Vec2::Vec2(const Vec2& p1, const Vec2& p2)
|
||||
{
|
||||
set(p1, p2);
|
||||
}
|
||||
|
||||
inline Vec2::Vec2(const Vec2& copy)
|
||||
{
|
||||
set(copy);
|
||||
}
|
||||
|
||||
inline bool Vec2::is_zero() const
|
||||
{
|
||||
return x == 0.0f && y == 0.0f;
|
||||
}
|
||||
|
||||
bool Vec2::is_one() const
|
||||
{
|
||||
return x == 1.0f && y == 1.0f;
|
||||
}
|
||||
|
||||
inline void Vec2::add(const Vec2& v)
|
||||
{
|
||||
x += v.x;
|
||||
y += v.y;
|
||||
}
|
||||
|
||||
inline float Vec2::distance_squared(const Vec2& v) const
|
||||
{
|
||||
float dx = v.x - x;
|
||||
float dy = v.y - y;
|
||||
return (dx * dx + dy * dy);
|
||||
}
|
||||
|
||||
inline float Vec2::dot(const Vec2& v) const
|
||||
{
|
||||
return (x * v.x + y * v.y);
|
||||
}
|
||||
|
||||
inline float Vec2::length_squared() const
|
||||
{
|
||||
return (x * x + y * y);
|
||||
}
|
||||
|
||||
inline void Vec2::negate()
|
||||
{
|
||||
x = -x;
|
||||
y = -y;
|
||||
}
|
||||
|
||||
inline void Vec2::scale(float scalar)
|
||||
{
|
||||
x *= scalar;
|
||||
y *= scalar;
|
||||
}
|
||||
|
||||
inline void Vec2::scale(const Vec2& scale)
|
||||
{
|
||||
x *= scale.x;
|
||||
y *= scale.y;
|
||||
}
|
||||
|
||||
inline void Vec2::set(float xx, float yy)
|
||||
{
|
||||
this->x = xx;
|
||||
this->y = yy;
|
||||
}
|
||||
|
||||
inline void Vec2::set(const Vec2& v)
|
||||
{
|
||||
this->x = v.x;
|
||||
this->y = v.y;
|
||||
}
|
||||
|
||||
inline void Vec2::set(const Vec2& p1, const Vec2& p2)
|
||||
{
|
||||
x = p2.x - p1.x;
|
||||
y = p2.y - p1.y;
|
||||
}
|
||||
|
||||
void Vec2::set_zero()
|
||||
{
|
||||
x = y = 0.0f;
|
||||
}
|
||||
|
||||
inline void Vec2::subtract(const Vec2& v)
|
||||
{
|
||||
x -= v.x;
|
||||
y -= v.y;
|
||||
}
|
||||
|
||||
inline void Vec2::smooth(const Vec2& target, float elapsedTime, float responseTime)
|
||||
{
|
||||
if (elapsedTime > 0)
|
||||
{
|
||||
*this += (target - *this) * (elapsedTime / (elapsedTime + responseTime));
|
||||
}
|
||||
}
|
||||
|
||||
inline Vec2 Vec2::operator+(const Vec2& v) const
|
||||
{
|
||||
Vec2 result(*this);
|
||||
result.add(v);
|
||||
return result;
|
||||
}
|
||||
|
||||
inline Vec2& Vec2::operator+=(const Vec2& v)
|
||||
{
|
||||
add(v);
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline Vec2 Vec2::operator-(const Vec2& v) const
|
||||
{
|
||||
Vec2 result(*this);
|
||||
result.subtract(v);
|
||||
return result;
|
||||
}
|
||||
|
||||
inline Vec2& Vec2::operator-=(const Vec2& v)
|
||||
{
|
||||
subtract(v);
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline Vec2 Vec2::operator-() const
|
||||
{
|
||||
Vec2 result(*this);
|
||||
result.negate();
|
||||
return result;
|
||||
}
|
||||
|
||||
inline Vec2 Vec2::operator*(float s) const
|
||||
{
|
||||
Vec2 result(*this);
|
||||
result.scale(s);
|
||||
return result;
|
||||
}
|
||||
|
||||
inline Vec2& Vec2::operator*=(float s)
|
||||
{
|
||||
scale(s);
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline Vec2 Vec2::operator/(const float s) const
|
||||
{
|
||||
return Vec2(this->x / s, this->y / s);
|
||||
}
|
||||
|
||||
inline bool Vec2::operator<(const Vec2& v) const
|
||||
{
|
||||
if (x == v.x)
|
||||
{
|
||||
return y < v.y;
|
||||
}
|
||||
return x < v.x;
|
||||
}
|
||||
|
||||
inline bool Vec2::operator>(const Vec2& v) const
|
||||
{
|
||||
if (x == v.x)
|
||||
{
|
||||
return y > v.y;
|
||||
}
|
||||
return x > v.x;
|
||||
}
|
||||
|
||||
inline bool Vec2::operator==(const Vec2& v) const
|
||||
{
|
||||
return x==v.x && y==v.y;
|
||||
}
|
||||
|
||||
inline bool Vec2::operator!=(const Vec2& v) const
|
||||
{
|
||||
return x!=v.x || y!=v.y;
|
||||
}
|
||||
|
||||
inline Vec2 operator*(float x, const Vec2& v)
|
||||
{
|
||||
Vec2 result(v);
|
||||
result.scale(x);
|
||||
return result;
|
||||
}
|
||||
|
||||
void Vec2::set_point(float xx, float yy)
|
||||
{
|
||||
this->x = xx;
|
||||
this->y = yy;
|
||||
}
|
||||
|
||||
}
|
190
mediapipe/render/core/math/vec3.cpp
Normal file
190
mediapipe/render/core/math/vec3.cpp
Normal file
|
@ -0,0 +1,190 @@
|
|||
//
|
||||
// vec3.cpp
|
||||
// Quaramera
|
||||
//
|
||||
// Created by Wang,Renzhu on 2018/11/20.
|
||||
// Copyright © 2018年 Wang,Renzhu. All rights reserved.
|
||||
//
|
||||
|
||||
// #include "vec3.hpp"
|
||||
#include "vec3.hpp"
|
||||
#include "math_utils.hpp"
|
||||
|
||||
|
||||
namespace Quaramera {
|
||||
|
||||
Vec3::Vec3() : x(0.0f), y(0.0f), z(0.0f) {
|
||||
}
|
||||
|
||||
Vec3::Vec3(float xx, float yy, float zz) : x(xx), y(yy), z(zz) {
|
||||
}
|
||||
|
||||
Vec3::Vec3(const float* array) {
|
||||
set(array);
|
||||
}
|
||||
|
||||
Vec3::Vec3(const Vec3& p1, const Vec3& p2) {
|
||||
set(p1, p2);
|
||||
}
|
||||
|
||||
Vec3::Vec3(const Vec3& copy) {
|
||||
set(copy);
|
||||
}
|
||||
|
||||
Vec3 Vec3::from_color(unsigned int color) {
|
||||
float components[3];
|
||||
int componentIndex = 0;
|
||||
|
||||
for (int i = 2; i >= 0; --i)
|
||||
{
|
||||
int component = (color >> i*8) & 0x0000ff;
|
||||
components[componentIndex++] = static_cast<float>(component) / 255.0f;
|
||||
}
|
||||
|
||||
Vec3 value(components);
|
||||
return value;
|
||||
}
|
||||
|
||||
float Vec3::angle(const Vec3& v1, const Vec3& v2) {
|
||||
float dx = v1.y * v2.z - v1.z * v2.y;
|
||||
float dy = v1.z * v2.x - v1.x * v2.z;
|
||||
float dz = v1.x * v2.y - v1.y * v2.x;
|
||||
|
||||
return std::atan2(std::sqrt(dx * dx + dy * dy + dz * dz) + MATH_FLOAT_SMALL, dot(v1, v2));
|
||||
}
|
||||
|
||||
void Vec3::add(const Vec3& v1, const Vec3& v2, Vec3* dst) {
|
||||
if (dst) {
|
||||
dst->x = v1.x + v2.x;
|
||||
dst->y = v1.y + v2.y;
|
||||
dst->z = v1.z + v2.z;
|
||||
}
|
||||
}
|
||||
|
||||
void Vec3::clamp(const Vec3& min, const Vec3& max) {
|
||||
// Clamp the x value.
|
||||
if (x < min.x)
|
||||
x = min.x;
|
||||
if (x > max.x)
|
||||
x = max.x;
|
||||
|
||||
// Clamp the y value.
|
||||
if (y < min.y)
|
||||
y = min.y;
|
||||
if (y > max.y)
|
||||
y = max.y;
|
||||
|
||||
// Clamp the z value.
|
||||
if (z < min.z)
|
||||
z = min.z;
|
||||
if (z > max.z)
|
||||
z = max.z;
|
||||
}
|
||||
|
||||
void Vec3::clamp(const Vec3& v, const Vec3& min, const Vec3& max, Vec3* dst) {
|
||||
if (dst) {
|
||||
// Clamp the x value.
|
||||
dst->x = v.x;
|
||||
if (dst->x < min.x)
|
||||
dst->x = min.x;
|
||||
if (dst->x > max.x)
|
||||
dst->x = max.x;
|
||||
|
||||
// Clamp the y value.
|
||||
dst->y = v.y;
|
||||
if (dst->y < min.y)
|
||||
dst->y = min.y;
|
||||
if (dst->y > max.y)
|
||||
dst->y = max.y;
|
||||
|
||||
// Clamp the z value.
|
||||
dst->z = v.z;
|
||||
if (dst->z < min.z)
|
||||
dst->z = min.z;
|
||||
if (dst->z > max.z)
|
||||
dst->z = max.z;
|
||||
}
|
||||
}
|
||||
|
||||
void Vec3::cross(const Vec3& v) {
|
||||
cross(*this, v, this);
|
||||
}
|
||||
|
||||
void Vec3::cross(const Vec3& v1, const Vec3& v2, Vec3* dst) {
|
||||
if (dst) {
|
||||
// NOTE: This code assumes Vec3 struct members are contiguous floats in memory.
|
||||
// We might want to revisit this (and other areas of code that make this assumption)
|
||||
// later to guarantee 100% safety/compatibility.
|
||||
MathUtils::cross_vec3(&v1.x, &v2.x, &dst->x);
|
||||
}
|
||||
}
|
||||
|
||||
float Vec3::distance(const Vec3& v) const {
|
||||
float dx = v.x - x;
|
||||
float dy = v.y - y;
|
||||
float dz = v.z - z;
|
||||
|
||||
return std::sqrt(dx * dx + dy * dy + dz * dz);
|
||||
}
|
||||
|
||||
float Vec3::distance_squared(const Vec3& v) const {
|
||||
float dx = v.x - x;
|
||||
float dy = v.y - y;
|
||||
float dz = v.z - z;
|
||||
|
||||
return (dx * dx + dy * dy + dz * dz);
|
||||
}
|
||||
|
||||
float Vec3::dot(const Vec3& v) const {
|
||||
return (x * v.x + y * v.y + z * v.z);
|
||||
}
|
||||
|
||||
float Vec3::dot(const Vec3& v1, const Vec3& v2) {
|
||||
return (v1.x * v2.x + v1.y * v2.y + v1.z * v2.z);
|
||||
}
|
||||
|
||||
void Vec3::normalize() {
|
||||
float n = x * x + y * y + z * z;
|
||||
// Already normalized.
|
||||
if (n == 1.0f)
|
||||
return;
|
||||
|
||||
n = std::sqrt(n);
|
||||
// Too close to zero.
|
||||
if (n < MATH_TOLERANCE)
|
||||
return;
|
||||
|
||||
n = 1.0f / n;
|
||||
x *= n;
|
||||
y *= n;
|
||||
z *= n;
|
||||
}
|
||||
|
||||
Vec3 Vec3::get_normalized() const {
|
||||
Vec3 v(*this);
|
||||
v.normalize();
|
||||
return v;
|
||||
}
|
||||
|
||||
void Vec3::subtract(const Vec3& v1, const Vec3& v2, Vec3* dst) {
|
||||
if (dst) {
|
||||
dst->x = v1.x - v2.x;
|
||||
dst->y = v1.y - v2.y;
|
||||
dst->z = v1.z - v2.z;
|
||||
}
|
||||
}
|
||||
|
||||
void Vec3::smooth(const Vec3& target, float elapsedTime, float responseTime) {
|
||||
if (elapsedTime > 0)
|
||||
{
|
||||
*this += (target - *this) * (elapsedTime / (elapsedTime + responseTime));
|
||||
}
|
||||
}
|
||||
|
||||
const Vec3 Vec3::ZERO(0.0f, 0.0f, 0.0f);
|
||||
const Vec3 Vec3::ONE(1.0f, 1.0f, 1.0f);
|
||||
const Vec3 Vec3::UNIT_X(1.0f, 0.0f, 0.0f);
|
||||
const Vec3 Vec3::UNIT_Y(0.0f, 1.0f, 0.0f);
|
||||
const Vec3 Vec3::UNIT_Z(0.0f, 0.0f, 1.0f);
|
||||
|
||||
}
|
454
mediapipe/render/core/math/vec3.hpp
Normal file
454
mediapipe/render/core/math/vec3.hpp
Normal file
|
@ -0,0 +1,454 @@
|
|||
//
|
||||
// vec3.h
|
||||
// Quaramera
|
||||
//
|
||||
// Created by Wang,Renzhu on 2018/11/20.
|
||||
// Copyright © 2018年 Wang,Renzhu. All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef VEC3_H
|
||||
#define VEC3_H
|
||||
|
||||
namespace Quaramera {
|
||||
|
||||
class Vec3
|
||||
{
|
||||
public:
|
||||
float x;
|
||||
float y;
|
||||
float z;
|
||||
|
||||
/**
|
||||
* Constructs a new vector initialized to all zeros.
|
||||
*/
|
||||
Vec3();
|
||||
|
||||
/**
|
||||
* Constructs a new vector initialized to the specified values.
|
||||
*
|
||||
* @param xx The x coordinate.
|
||||
* @param yy The y coordinate.
|
||||
* @param zz The z coordinate.
|
||||
*/
|
||||
Vec3(float xx, float yy, float zz);
|
||||
|
||||
/**
|
||||
* Constructs a new vector from the values in the specified array.
|
||||
*
|
||||
* @param array An array containing the elements of the vector in the order x, y, z.
|
||||
*/
|
||||
Vec3(const float* array);
|
||||
|
||||
/**
|
||||
* Constructs a vector that describes the direction between the specified points.
|
||||
*
|
||||
* @param p1 The first point.
|
||||
* @param p2 The second point.
|
||||
*/
|
||||
Vec3(const Vec3& p1, const Vec3& p2);
|
||||
|
||||
/**
|
||||
* Constructs a new vector that is a copy of the specified vector.
|
||||
*
|
||||
* @param copy The vector to copy.
|
||||
*/
|
||||
Vec3(const Vec3& copy);
|
||||
|
||||
/**
|
||||
* Creates a new vector from an integer interpreted as an RGB value.
|
||||
* E.g. 0xff0000 represents red or the vector (1, 0, 0).
|
||||
*
|
||||
* @param color The integer to interpret as an RGB value.
|
||||
*
|
||||
* @return A vector corresponding to the interpreted RGB color.
|
||||
*/
|
||||
static Vec3 from_color(unsigned int color);
|
||||
|
||||
/**
|
||||
* Indicates whether this vector contains all zeros.
|
||||
*
|
||||
* @return true if this vector contains all zeros, false otherwise.
|
||||
*/
|
||||
inline bool is_zero() const;
|
||||
|
||||
/**
|
||||
* Indicates whether this vector contains all ones.
|
||||
*
|
||||
* @return true if this vector contains all ones, false otherwise.
|
||||
*/
|
||||
inline bool is_one() const;
|
||||
|
||||
/**
|
||||
* Returns the angle (in radians) between the specified vectors.
|
||||
*
|
||||
* @param v1 The first vector.
|
||||
* @param v2 The second vector.
|
||||
*
|
||||
* @return The angle between the two vectors (in radians).
|
||||
*/
|
||||
static float angle(const Vec3& v1, const Vec3& v2);
|
||||
|
||||
|
||||
/**
|
||||
* Adds the elements of the specified vector to this one.
|
||||
*
|
||||
* @param v The vector to add.
|
||||
*/
|
||||
inline void add(const Vec3& v);
|
||||
|
||||
|
||||
/**
|
||||
* Adds the elements of this vector to the specified values.
|
||||
*
|
||||
* @param xx The add x coordinate.
|
||||
* @param yy The add y coordinate.
|
||||
* @param zz The add z coordinate.
|
||||
*/
|
||||
inline void add(float xx, float yy, float zz);
|
||||
|
||||
/**
|
||||
* Adds the specified vectors and stores the result in dst.
|
||||
*
|
||||
* @param v1 The first vector.
|
||||
* @param v2 The second vector.
|
||||
* @param dst A vector to store the result in.
|
||||
*/
|
||||
static void add(const Vec3& v1, const Vec3& v2, Vec3* dst);
|
||||
|
||||
/**
|
||||
* Clamps this vector within the specified range.
|
||||
*
|
||||
* @param min The minimum value.
|
||||
* @param max The maximum value.
|
||||
*/
|
||||
void clamp(const Vec3& min, const Vec3& max);
|
||||
|
||||
/**
|
||||
* Clamps the specified vector within the specified range and returns it in dst.
|
||||
*
|
||||
* @param v The vector to clamp.
|
||||
* @param min The minimum value.
|
||||
* @param max The maximum value.
|
||||
* @param dst A vector to store the result in.
|
||||
*/
|
||||
static void clamp(const Vec3& v, const Vec3& min, const Vec3& max, Vec3* dst);
|
||||
|
||||
/**
|
||||
* Sets this vector to the cross product between itself and the specified vector.
|
||||
*
|
||||
* @param v The vector to compute the cross product with.
|
||||
*/
|
||||
void cross(const Vec3& v);
|
||||
|
||||
/**
|
||||
* Computes the cross product of the specified vectors and stores the result in dst.
|
||||
*
|
||||
* @param v1 The first vector.
|
||||
* @param v2 The second vector.
|
||||
* @param dst A vector to store the result in.
|
||||
*/
|
||||
static void cross(const Vec3& v1, const Vec3& v2, Vec3* dst);
|
||||
|
||||
/**
|
||||
* Returns the distance between this vector and v.
|
||||
*
|
||||
* @param v The other vector.
|
||||
*
|
||||
* @return The distance between this vector and v.
|
||||
*
|
||||
* @see distanceSquared
|
||||
*/
|
||||
float distance(const Vec3& v) const;
|
||||
|
||||
/**
|
||||
* Returns the squared distance between this vector and v.
|
||||
*
|
||||
* When it is not necessary to get the exact distance between
|
||||
* two vectors (for example, when simply comparing the
|
||||
* distance between different vectors), it is advised to use
|
||||
* this method instead of distance.
|
||||
*
|
||||
* @param v The other vector.
|
||||
*
|
||||
* @return The squared distance between this vector and v.
|
||||
*
|
||||
* @see distance
|
||||
*/
|
||||
float distance_squared(const Vec3& v) const;
|
||||
|
||||
/**
|
||||
* Returns the dot product of this vector and the specified vector.
|
||||
*
|
||||
* @param v The vector to compute the dot product with.
|
||||
*
|
||||
* @return The dot product.
|
||||
*/
|
||||
float dot(const Vec3& v) const;
|
||||
|
||||
/**
|
||||
* Returns the dot product between the specified vectors.
|
||||
*
|
||||
* @param v1 The first vector.
|
||||
* @param v2 The second vector.
|
||||
*
|
||||
* @return The dot product between the vectors.
|
||||
*/
|
||||
static float dot(const Vec3& v1, const Vec3& v2);
|
||||
|
||||
/**
|
||||
* Computes the length of this vector.
|
||||
*
|
||||
* @return The length of the vector.
|
||||
*
|
||||
* @see lengthSquared
|
||||
*/
|
||||
inline float length() const;
|
||||
|
||||
/**
|
||||
* Returns the squared length of this vector.
|
||||
*
|
||||
* When it is not necessary to get the exact length of a
|
||||
* vector (for example, when simply comparing the lengths of
|
||||
* different vectors), it is advised to use this method
|
||||
* instead of length.
|
||||
*
|
||||
* @return The squared length of the vector.
|
||||
*
|
||||
* @see length
|
||||
*/
|
||||
inline float length_squared() const;
|
||||
|
||||
/**
|
||||
* Negates this vector.
|
||||
*/
|
||||
inline void negate();
|
||||
|
||||
/**
|
||||
* Normalizes this vector.
|
||||
*
|
||||
* This method normalizes this Vec3 so that it is of
|
||||
* unit length (in other words, the length of the vector
|
||||
* after calling this method will be 1.0f). If the vector
|
||||
* already has unit length or if the length of the vector
|
||||
* is zero, this method does nothing.
|
||||
*/
|
||||
void normalize();
|
||||
|
||||
/**
|
||||
* Get the normalized vector.
|
||||
*/
|
||||
Vec3 get_normalized() const;
|
||||
|
||||
/**
|
||||
* Scales all elements of this vector by the specified value.
|
||||
*
|
||||
* @param scalar The scalar value.
|
||||
*/
|
||||
inline void scale(float scalar);
|
||||
|
||||
/**
|
||||
* Sets the elements of this vector to the specified values.
|
||||
*
|
||||
* @param xx The new x coordinate.
|
||||
* @param yy The new y coordinate.
|
||||
* @param zz The new z coordinate.
|
||||
*/
|
||||
inline void set(float xx, float yy, float zz);
|
||||
|
||||
/**
|
||||
* Sets the elements of this vector from the values in the specified array.
|
||||
*
|
||||
* @param array An array containing the elements of the vector in the order x, y, z.
|
||||
*/
|
||||
inline void set(const float* array);
|
||||
|
||||
/**
|
||||
* Sets the elements of this vector to those in the specified vector.
|
||||
*
|
||||
* @param v The vector to copy.
|
||||
*/
|
||||
inline void set(const Vec3& v);
|
||||
|
||||
/**
|
||||
* Sets this vector to the directional vector between the specified points.
|
||||
*/
|
||||
inline void set(const Vec3& p1, const Vec3& p2);
|
||||
|
||||
/**
|
||||
* Sets the elements of this vector to zero.
|
||||
*/
|
||||
inline void set_zero();
|
||||
|
||||
/**
|
||||
* Subtracts this vector and the specified vector as (this - v)
|
||||
* and stores the result in this vector.
|
||||
*
|
||||
* @param v The vector to subtract.
|
||||
*/
|
||||
inline void subtract(const Vec3& v);
|
||||
|
||||
/**
|
||||
* Subtracts the specified vectors and stores the result in dst.
|
||||
* The resulting vector is computed as (v1 - v2).
|
||||
*
|
||||
* @param v1 The first vector.
|
||||
* @param v2 The second vector.
|
||||
* @param dst The destination vector.
|
||||
*/
|
||||
static void subtract(const Vec3& v1, const Vec3& v2, Vec3* dst);
|
||||
|
||||
/**
|
||||
* Updates this vector towards the given target using a smoothing function.
|
||||
* The given response time determines the amount of smoothing (lag). A longer
|
||||
* response time yields a smoother result and more lag. To force this vector to
|
||||
* follow the target closely, provide a response time that is very small relative
|
||||
* to the given elapsed time.
|
||||
*
|
||||
* @param target target value.
|
||||
* @param elapsedTime elapsed time between calls.
|
||||
* @param responseTime response time (in the same units as elapsedTime).
|
||||
*/
|
||||
void smooth(const Vec3& target, float elapsedTime, float responseTime);
|
||||
|
||||
/**
|
||||
* Linear interpolation between two vectors A and B by alpha which
|
||||
* is in the range [0,1]
|
||||
*/
|
||||
inline Vec3 lerp(const Vec3& target, float alpha) const;
|
||||
|
||||
/**
|
||||
* Calculates the sum of this vector with the given vector.
|
||||
*
|
||||
* Note: this does not modify this vector.
|
||||
*
|
||||
* @param v The vector to add.
|
||||
* @return The vector sum.
|
||||
*/
|
||||
inline Vec3 operator+(const Vec3& v) const;
|
||||
|
||||
/**
|
||||
* Adds the given vector to this vector.
|
||||
*
|
||||
* @param v The vector to add.
|
||||
* @return This vector, after the addition occurs.
|
||||
*/
|
||||
inline Vec3& operator+=(const Vec3& v);
|
||||
|
||||
/**
|
||||
* Calculates the difference of this vector with the given vector.
|
||||
*
|
||||
* Note: this does not modify this vector.
|
||||
*
|
||||
* @param v The vector to subtract.
|
||||
* @return The vector difference.
|
||||
*/
|
||||
inline Vec3 operator-(const Vec3& v) const;
|
||||
|
||||
/**
|
||||
* Subtracts the given vector from this vector.
|
||||
*
|
||||
* @param v The vector to subtract.
|
||||
* @return This vector, after the subtraction occurs.
|
||||
*/
|
||||
inline Vec3& operator-=(const Vec3& v);
|
||||
|
||||
/**
|
||||
* Calculates the negation of this vector.
|
||||
*
|
||||
* Note: this does not modify this vector.
|
||||
*
|
||||
* @return The negation of this vector.
|
||||
*/
|
||||
inline Vec3 operator-() const;
|
||||
|
||||
/**
|
||||
* Calculates the scalar product of this vector with the given value.
|
||||
*
|
||||
* Note: this does not modify this vector.
|
||||
*
|
||||
* @param s The value to scale by.
|
||||
* @return The scaled vector.
|
||||
*/
|
||||
inline Vec3 operator*(float s) const;
|
||||
|
||||
/**
|
||||
* Scales this vector by the given value.
|
||||
*
|
||||
* @param s The value to scale by.
|
||||
* @return This vector, after the scale occurs.
|
||||
*/
|
||||
inline Vec3& operator*=(float s);
|
||||
|
||||
/**
|
||||
* Returns the components of this vector divided by the given constant
|
||||
*
|
||||
* Note: this does not modify this vector.
|
||||
*
|
||||
* @param s the constant to divide this vector with
|
||||
* @return a smaller vector
|
||||
*/
|
||||
inline Vec3 operator/(float s) const;
|
||||
|
||||
/** Returns true if the vector's scalar components are all greater
|
||||
that the ones of the vector it is compared against.
|
||||
*/
|
||||
inline bool operator < (const Vec3& rhs) const
|
||||
{
|
||||
if (x < rhs.x && y < rhs.y && z < rhs.z)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/** Returns true if the vector's scalar components are all smaller
|
||||
that the ones of the vector it is compared against.
|
||||
*/
|
||||
inline bool operator >(const Vec3& rhs) const
|
||||
{
|
||||
if (x > rhs.x && y > rhs.y && z > rhs.z)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if this vector is equal to the given vector.
|
||||
*
|
||||
* @param v The vector to compare against.
|
||||
*
|
||||
* @return True if this vector is equal to the given vector, false otherwise.
|
||||
*/
|
||||
inline bool operator==(const Vec3& v) const;
|
||||
|
||||
/**
|
||||
* Determines if this vector is not equal to the given vector.
|
||||
*
|
||||
* @param v The vector to compare against.
|
||||
*
|
||||
* @return True if this vector is not equal to the given vector, false otherwise.
|
||||
*/
|
||||
inline bool operator!=(const Vec3& v) const;
|
||||
|
||||
/** equals to Vec3(0,0,0) */
|
||||
static const Vec3 ZERO;
|
||||
/** equals to Vec3(1,1,1) */
|
||||
static const Vec3 ONE;
|
||||
/** equals to Vec3(1,0,0) */
|
||||
static const Vec3 UNIT_X;
|
||||
/** equals to Vec3(0,1,0) */
|
||||
static const Vec3 UNIT_Y;
|
||||
/** equals to Vec3(0,0,1) */
|
||||
static const Vec3 UNIT_Z;
|
||||
};
|
||||
|
||||
/**
|
||||
* Calculates the scalar product of the given vector with the given value.
|
||||
*
|
||||
* @param x The value to scale by.
|
||||
* @param v The vector to scale.
|
||||
* @return The scaled vector.
|
||||
*/
|
||||
inline Vec3 operator*(float x, const Vec3& v);
|
||||
}
|
||||
|
||||
#include "vec3.inl"
|
||||
|
||||
#endif /* VEC3_H */
|
177
mediapipe/render/core/math/vec3.inl
Normal file
177
mediapipe/render/core/math/vec3.inl
Normal file
|
@ -0,0 +1,177 @@
|
|||
//
|
||||
// vec3.inl
|
||||
// BdiEngine
|
||||
//
|
||||
// Created by Wang,Renzhu on 2018/11/20.
|
||||
// Copyright © 2018年 Wang,Renzhu. All rights reserved.
|
||||
//
|
||||
|
||||
#include "vec3.hpp"
|
||||
#include <cmath>
|
||||
|
||||
namespace Quaramera {
|
||||
|
||||
inline bool Vec3::is_zero() const
|
||||
{
|
||||
return x == 0.0f && y == 0.0f && z == 0.0f;
|
||||
}
|
||||
|
||||
inline bool Vec3::is_one() const
|
||||
{
|
||||
return x == 1.0f && y == 1.0f && z == 1.0f;
|
||||
}
|
||||
|
||||
inline void Vec3::add(const Vec3& v)
|
||||
{
|
||||
x += v.x;
|
||||
y += v.y;
|
||||
z += v.z;
|
||||
}
|
||||
|
||||
inline void Vec3::add(float xx, float yy, float zz)
|
||||
{
|
||||
x += xx;
|
||||
y += yy;
|
||||
z += zz;
|
||||
}
|
||||
|
||||
inline float Vec3::length() const
|
||||
{
|
||||
return std::sqrt(x * x + y * y + z * z);
|
||||
}
|
||||
|
||||
inline float Vec3::length_squared() const
|
||||
{
|
||||
return (x * x + y * y + z * z);
|
||||
}
|
||||
|
||||
inline void Vec3::negate()
|
||||
{
|
||||
x = -x;
|
||||
y = -y;
|
||||
z = -z;
|
||||
}
|
||||
|
||||
inline void Vec3::scale(float scalar)
|
||||
{
|
||||
x *= scalar;
|
||||
y *= scalar;
|
||||
z *= scalar;
|
||||
}
|
||||
|
||||
inline Vec3 Vec3::lerp(const Vec3 &target, float alpha) const
|
||||
{
|
||||
return *this * (1.f - alpha) + target * alpha;
|
||||
}
|
||||
|
||||
inline void Vec3::set(float xx, float yy, float zz)
|
||||
{
|
||||
this->x = xx;
|
||||
this->y = yy;
|
||||
this->z = zz;
|
||||
}
|
||||
|
||||
inline void Vec3::set(const float* array)
|
||||
{
|
||||
if (array) {
|
||||
x = array[0];
|
||||
y = array[1];
|
||||
z = array[2];
|
||||
}
|
||||
}
|
||||
|
||||
inline void Vec3::set(const Vec3& v)
|
||||
{
|
||||
this->x = v.x;
|
||||
this->y = v.y;
|
||||
this->z = v.z;
|
||||
}
|
||||
|
||||
inline void Vec3::set(const Vec3& p1, const Vec3& p2)
|
||||
{
|
||||
x = p2.x - p1.x;
|
||||
y = p2.y - p1.y;
|
||||
z = p2.z - p1.z;
|
||||
}
|
||||
|
||||
inline void Vec3::set_zero()
|
||||
{
|
||||
x = y = z = 0.0f;
|
||||
}
|
||||
|
||||
inline void Vec3::subtract(const Vec3& v)
|
||||
{
|
||||
x -= v.x;
|
||||
y -= v.y;
|
||||
z -= v.z;
|
||||
}
|
||||
|
||||
inline Vec3 Vec3::operator+(const Vec3& v) const
|
||||
{
|
||||
Vec3 result(*this);
|
||||
result.add(v);
|
||||
return result;
|
||||
}
|
||||
|
||||
inline Vec3& Vec3::operator+=(const Vec3& v)
|
||||
{
|
||||
add(v);
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline Vec3 Vec3::operator-(const Vec3& v) const
|
||||
{
|
||||
Vec3 result(*this);
|
||||
result.subtract(v);
|
||||
return result;
|
||||
}
|
||||
|
||||
inline Vec3& Vec3::operator-=(const Vec3& v)
|
||||
{
|
||||
subtract(v);
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline Vec3 Vec3::operator-() const
|
||||
{
|
||||
Vec3 result(*this);
|
||||
result.negate();
|
||||
return result;
|
||||
}
|
||||
|
||||
inline Vec3 Vec3::operator*(float s) const
|
||||
{
|
||||
Vec3 result(*this);
|
||||
result.scale(s);
|
||||
return result;
|
||||
}
|
||||
|
||||
inline Vec3& Vec3::operator*=(float s)
|
||||
{
|
||||
scale(s);
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline Vec3 Vec3::operator/(const float s) const
|
||||
{
|
||||
return Vec3(this->x / s, this->y / s, this->z / s);
|
||||
}
|
||||
|
||||
inline bool Vec3::operator==(const Vec3& v) const
|
||||
{
|
||||
return x==v.x && y==v.y && z==v.z;
|
||||
}
|
||||
|
||||
inline bool Vec3::operator!=(const Vec3& v) const
|
||||
{
|
||||
return x!=v.x || y!=v.y || z!=v.z;
|
||||
}
|
||||
|
||||
inline Vec3 operator*(float x, const Vec3& v)
|
||||
{
|
||||
Vec3 result(v);
|
||||
result.scale(x);
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
292
mediapipe/render/core/math/vec4.cpp
Normal file
292
mediapipe/render/core/math/vec4.cpp
Normal file
|
@ -0,0 +1,292 @@
|
|||
//
|
||||
// vec4.cpp
|
||||
// Quaramera
|
||||
//
|
||||
// Created by Wang,Renzhu on 2018/11/20.
|
||||
// Copyright © 2018年 Wang,Renzhu. All rights reserved.
|
||||
//
|
||||
|
||||
#include "vec4.hpp"
|
||||
#include "math_utils.hpp"
|
||||
#include <cmath>
|
||||
|
||||
namespace Quaramera {
|
||||
|
||||
Vec4::Vec4() : x(0.0f), y(0.0f), z(0.0f), w(0.0f)
|
||||
{
|
||||
}
|
||||
|
||||
Vec4::Vec4(float xx, float yy, float zz, float ww) : x(xx), y(yy), z(zz), w(ww)
|
||||
{
|
||||
}
|
||||
|
||||
Vec4::Vec4(const float* src)
|
||||
{
|
||||
set(src);
|
||||
}
|
||||
|
||||
Vec4::Vec4(const Vec4& p1, const Vec4& p2)
|
||||
{
|
||||
set(p1, p2);
|
||||
}
|
||||
|
||||
Vec4::Vec4(const Vec4& copy)
|
||||
{
|
||||
set(copy);
|
||||
}
|
||||
|
||||
Vec4 Vec4::from_color(unsigned int color)
|
||||
{
|
||||
float components[4];
|
||||
int componentIndex = 0;
|
||||
for (int i = 3; i >= 0; --i)
|
||||
{
|
||||
int component = (color >> i*8) & 0x000000ff;
|
||||
|
||||
components[componentIndex++] = static_cast<float>(component) / 255.0f;
|
||||
}
|
||||
|
||||
Vec4 value(components);
|
||||
return value;
|
||||
}
|
||||
|
||||
bool Vec4::is_zero() const
|
||||
{
|
||||
return x == 0.0f && y == 0.0f && z == 0.0f && w == 0.0f;
|
||||
}
|
||||
|
||||
bool Vec4::is_one() const
|
||||
{
|
||||
return x == 1.0f && y == 1.0f && z == 1.0f && w == 1.0f;
|
||||
}
|
||||
|
||||
float Vec4::angle(const Vec4& v1, const Vec4& v2)
|
||||
{
|
||||
float dx = v1.w * v2.x - v1.x * v2.w - v1.y * v2.z + v1.z * v2.y;
|
||||
float dy = v1.w * v2.y - v1.y * v2.w - v1.z * v2.x + v1.x * v2.z;
|
||||
float dz = v1.w * v2.z - v1.z * v2.w - v1.x * v2.y + v1.y * v2.x;
|
||||
|
||||
return std::atan2(std::sqrt(dx * dx + dy * dy + dz * dz) + MATH_FLOAT_SMALL, dot(v1, v2));
|
||||
}
|
||||
|
||||
void Vec4::add(const Vec4& v)
|
||||
{
|
||||
x += v.x;
|
||||
y += v.y;
|
||||
z += v.z;
|
||||
w += v.w;
|
||||
}
|
||||
|
||||
void Vec4::add(const Vec4& v1, const Vec4& v2, Vec4* dst)
|
||||
{
|
||||
if (dst) {
|
||||
dst->x = v1.x + v2.x;
|
||||
dst->y = v1.y + v2.y;
|
||||
dst->z = v1.z + v2.z;
|
||||
dst->w = v1.w + v2.w;
|
||||
}
|
||||
}
|
||||
|
||||
void Vec4::clamp(const Vec4& min, const Vec4& max)
|
||||
{
|
||||
// Clamp the x value.
|
||||
if (x < min.x)
|
||||
x = min.x;
|
||||
if (x > max.x)
|
||||
x = max.x;
|
||||
|
||||
// Clamp the y value.
|
||||
if (y < min.y)
|
||||
y = min.y;
|
||||
if (y > max.y)
|
||||
y = max.y;
|
||||
|
||||
// Clamp the z value.
|
||||
if (z < min.z)
|
||||
z = min.z;
|
||||
if (z > max.z)
|
||||
z = max.z;
|
||||
|
||||
// Clamp the z value.
|
||||
if (w < min.w)
|
||||
w = min.w;
|
||||
if (w > max.w)
|
||||
w = max.w;
|
||||
}
|
||||
|
||||
void Vec4::clamp(const Vec4& v, const Vec4& min, const Vec4& max, Vec4* dst)
|
||||
{
|
||||
if (dst) {
|
||||
// Clamp the x value.
|
||||
dst->x = v.x;
|
||||
if (dst->x < min.x)
|
||||
dst->x = min.x;
|
||||
if (dst->x > max.x)
|
||||
dst->x = max.x;
|
||||
|
||||
// Clamp the y value.
|
||||
dst->y = v.y;
|
||||
if (dst->y < min.y)
|
||||
dst->y = min.y;
|
||||
if (dst->y > max.y)
|
||||
dst->y = max.y;
|
||||
|
||||
// Clamp the z value.
|
||||
dst->z = v.z;
|
||||
if (dst->z < min.z)
|
||||
dst->z = min.z;
|
||||
if (dst->z > max.z)
|
||||
dst->z = max.z;
|
||||
|
||||
// Clamp the w value.
|
||||
dst->w = v.w;
|
||||
if (dst->w < min.w)
|
||||
dst->w = min.w;
|
||||
if (dst->w > max.w)
|
||||
dst->w = max.w;
|
||||
}
|
||||
}
|
||||
|
||||
float Vec4::distance(const Vec4& v) const
|
||||
{
|
||||
float dx = v.x - x;
|
||||
float dy = v.y - y;
|
||||
float dz = v.z - z;
|
||||
float dw = v.w - w;
|
||||
|
||||
return std::sqrt(dx * dx + dy * dy + dz * dz + dw * dw);
|
||||
}
|
||||
|
||||
float Vec4::distance_squared(const Vec4& v) const
|
||||
{
|
||||
float dx = v.x - x;
|
||||
float dy = v.y - y;
|
||||
float dz = v.z - z;
|
||||
float dw = v.w - w;
|
||||
|
||||
return (dx * dx + dy * dy + dz * dz + dw * dw);
|
||||
}
|
||||
|
||||
float Vec4::dot(const Vec4& v) const
|
||||
{
|
||||
return (x * v.x + y * v.y + z * v.z + w * v.w);
|
||||
}
|
||||
|
||||
float Vec4::dot(const Vec4& v1, const Vec4& v2)
|
||||
{
|
||||
return (v1.x * v2.x + v1.y * v2.y + v1.z * v2.z + v1.w * v2.w);
|
||||
}
|
||||
|
||||
float Vec4::length() const
|
||||
{
|
||||
return std::sqrt(x * x + y * y + z * z + w * w);
|
||||
}
|
||||
|
||||
|
||||
float Vec4::length_squared() const
|
||||
{
|
||||
return (x * x + y * y + z * z + w * w);
|
||||
}
|
||||
|
||||
void Vec4::negate()
|
||||
{
|
||||
x = -x;
|
||||
y = -y;
|
||||
z = -z;
|
||||
w = -w;
|
||||
}
|
||||
|
||||
void Vec4::normalize()
|
||||
{
|
||||
float n = x * x + y * y + z * z + w * w;
|
||||
// Already normalized.
|
||||
if (n == 1.0f)
|
||||
return;
|
||||
|
||||
n = std::sqrt(n);
|
||||
// Too close to zero.
|
||||
if (n < MATH_TOLERANCE)
|
||||
return;
|
||||
|
||||
n = 1.0f / n;
|
||||
x *= n;
|
||||
y *= n;
|
||||
z *= n;
|
||||
w *= n;
|
||||
}
|
||||
|
||||
Vec4 Vec4::get_normalized() const
|
||||
{
|
||||
Vec4 v(*this);
|
||||
v.normalize();
|
||||
return v;
|
||||
}
|
||||
|
||||
void Vec4::scale(float scalar)
|
||||
{
|
||||
x *= scalar;
|
||||
y *= scalar;
|
||||
z *= scalar;
|
||||
w *= scalar;
|
||||
}
|
||||
|
||||
void Vec4::set(float xx, float yy, float zz, float ww)
|
||||
{
|
||||
this->x = xx;
|
||||
this->y = yy;
|
||||
this->z = zz;
|
||||
this->w = ww;
|
||||
}
|
||||
|
||||
void Vec4::set(const float* array)
|
||||
{
|
||||
if (array) {
|
||||
x = array[0];
|
||||
y = array[1];
|
||||
z = array[2];
|
||||
w = array[3];
|
||||
}
|
||||
}
|
||||
|
||||
void Vec4::set(const Vec4& v)
|
||||
{
|
||||
this->x = v.x;
|
||||
this->y = v.y;
|
||||
this->z = v.z;
|
||||
this->w = v.w;
|
||||
}
|
||||
|
||||
void Vec4::set(const Vec4& p1, const Vec4& p2)
|
||||
{
|
||||
x = p2.x - p1.x;
|
||||
y = p2.y - p1.y;
|
||||
z = p2.z - p1.z;
|
||||
w = p2.w - p1.w;
|
||||
}
|
||||
|
||||
void Vec4::subtract(const Vec4& v)
|
||||
{
|
||||
x -= v.x;
|
||||
y -= v.y;
|
||||
z -= v.z;
|
||||
w -= v.w;
|
||||
}
|
||||
|
||||
void Vec4::subtract(const Vec4& v1, const Vec4& v2, Vec4* dst)
|
||||
{
|
||||
if (dst) {
|
||||
dst->x = v1.x - v2.x;
|
||||
dst->y = v1.y - v2.y;
|
||||
dst->z = v1.z - v2.z;
|
||||
dst->w = v1.w - v2.w;
|
||||
}
|
||||
}
|
||||
|
||||
const Vec4 Vec4::ZERO = Vec4(0.0f, 0.0f, 0.0f, 0.0f);
|
||||
const Vec4 Vec4::ONE = Vec4(1.0f, 1.0f, 1.0f, 1.0f);
|
||||
const Vec4 Vec4::UNIT_X = Vec4(1.0f, 0.0f, 0.0f, 0.0f);
|
||||
const Vec4 Vec4::UNIT_Y = Vec4(0.0f, 1.0f, 0.0f, 0.0f);
|
||||
const Vec4 Vec4::UNIT_Z = Vec4(0.0f, 0.0f, 1.0f, 0.0f);
|
||||
const Vec4 Vec4::UNIT_W = Vec4(0.0f, 0.0f, 0.0f, 1.0f);
|
||||
|
||||
}
|
402
mediapipe/render/core/math/vec4.hpp
Normal file
402
mediapipe/render/core/math/vec4.hpp
Normal file
|
@ -0,0 +1,402 @@
|
|||
//
|
||||
// vec4.h
|
||||
// Quaramera
|
||||
//
|
||||
// Created by Wang,Renzhu on 2018/11/20.
|
||||
// Copyright © 2018年 Wang,Renzhu. All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef VEC4_H
|
||||
#define VEC4_H
|
||||
|
||||
namespace Quaramera {
|
||||
class Vec4
|
||||
{
|
||||
public:
|
||||
float x;
|
||||
float y;
|
||||
float z;
|
||||
float w;
|
||||
|
||||
/**
|
||||
* Constructs a new vector initialized to all zeros.
|
||||
*/
|
||||
Vec4();
|
||||
|
||||
/**
|
||||
* Constructs a new vector initialized to the specified values.
|
||||
*
|
||||
* @param xx The x coordinate.
|
||||
* @param yy The y coordinate.
|
||||
* @param zz The z coordinate.
|
||||
* @param ww The w coordinate.
|
||||
*/
|
||||
Vec4(float xx, float yy, float zz, float ww);
|
||||
|
||||
/**
|
||||
* Constructs a new vector from the values in the specified array.
|
||||
*
|
||||
* @param array An array containing the elements of the vector in the order x, y, z, w.
|
||||
*/
|
||||
Vec4(const float* array);
|
||||
|
||||
/**
|
||||
* Constructs a vector that describes the direction between the specified points.
|
||||
*
|
||||
* @param p1 The first point.
|
||||
* @param p2 The second point.
|
||||
*/
|
||||
Vec4(const Vec4& p1, const Vec4& p2);
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* Creates a new vector that is a copy of the specified vector.
|
||||
*
|
||||
* @param copy The vector to copy.
|
||||
*/
|
||||
Vec4(const Vec4& copy);
|
||||
|
||||
/**
|
||||
* Creates a new vector from an integer interpreted as an RGBA value.
|
||||
* E.g. 0xff0000ff represents opaque red or the vector (1, 0, 0, 1).
|
||||
*
|
||||
* @param color The integer to interpret as an RGBA value.
|
||||
*
|
||||
* @return A vector corresponding to the interpreted RGBA color.
|
||||
*/
|
||||
static Vec4 from_color(unsigned int color);
|
||||
|
||||
/**
|
||||
* Indicates whether this vector contains all zeros.
|
||||
*
|
||||
* @return true if this vector contains all zeros, false otherwise.
|
||||
*/
|
||||
bool is_zero() const;
|
||||
|
||||
/**
|
||||
* Indicates whether this vector contains all ones.
|
||||
*
|
||||
* @return true if this vector contains all ones, false otherwise.
|
||||
*/
|
||||
bool is_one() const;
|
||||
|
||||
/**
|
||||
* Returns the angle (in radians) between the specified vectors.
|
||||
*
|
||||
* @param v1 The first vector.
|
||||
* @param v2 The second vector.
|
||||
*
|
||||
* @return The angle between the two vectors (in radians).
|
||||
*/
|
||||
static float angle(const Vec4& v1, const Vec4& v2);
|
||||
|
||||
/**
|
||||
* Adds the elements of the specified vector to this one.
|
||||
*
|
||||
* @param v The vector to add.
|
||||
*/
|
||||
void add(const Vec4& v);
|
||||
|
||||
/**
|
||||
* Adds the specified vectors and stores the result in dst.
|
||||
*
|
||||
* @param v1 The first vector.
|
||||
* @param v2 The second vector.
|
||||
* @param dst A vector to store the result in.
|
||||
*/
|
||||
static void add(const Vec4& v1, const Vec4& v2, Vec4* dst);
|
||||
|
||||
/**
|
||||
* Clamps this vector within the specified range.
|
||||
*
|
||||
* @param min The minimum value.
|
||||
* @param max The maximum value.
|
||||
*/
|
||||
void clamp(const Vec4& min, const Vec4& max);
|
||||
|
||||
/**
|
||||
* Clamps the specified vector within the specified range and returns it in dst.
|
||||
*
|
||||
* @param v The vector to clamp.
|
||||
* @param min The minimum value.
|
||||
* @param max The maximum value.
|
||||
* @param dst A vector to store the result in.
|
||||
*/
|
||||
static void clamp(const Vec4& v, const Vec4& min, const Vec4& max, Vec4* dst);
|
||||
|
||||
/**
|
||||
* Returns the distance between this vector and v.
|
||||
*
|
||||
* @param v The other vector.
|
||||
*
|
||||
* @return The distance between this vector and v.
|
||||
*
|
||||
* @see distanceSquared
|
||||
*/
|
||||
float distance(const Vec4& v) const;
|
||||
|
||||
/**
|
||||
* Returns the squared distance between this vector and v.
|
||||
*
|
||||
* When it is not necessary to get the exact distance between
|
||||
* two vectors (for example, when simply comparing the
|
||||
* distance between different vectors), it is advised to use
|
||||
* this method instead of distance.
|
||||
*
|
||||
* @param v The other vector.
|
||||
*
|
||||
* @return The squared distance between this vector and v.
|
||||
*
|
||||
* @see distance
|
||||
*/
|
||||
float distance_squared(const Vec4& v) const;
|
||||
|
||||
/**
|
||||
* Returns the dot product of this vector and the specified vector.
|
||||
*
|
||||
* @param v The vector to compute the dot product with.
|
||||
*
|
||||
* @return The dot product.
|
||||
*/
|
||||
float dot(const Vec4& v) const;
|
||||
|
||||
/**
|
||||
* Returns the dot product between the specified vectors.
|
||||
*
|
||||
* @param v1 The first vector.
|
||||
* @param v2 The second vector.
|
||||
*
|
||||
* @return The dot product between the vectors.
|
||||
*/
|
||||
static float dot(const Vec4& v1, const Vec4& v2);
|
||||
|
||||
/**
|
||||
* Computes the length of this vector.
|
||||
*
|
||||
* @return The length of the vector.
|
||||
*
|
||||
* @see lengthSquared
|
||||
*/
|
||||
float length() const;
|
||||
|
||||
/**
|
||||
* Returns the squared length of this vector.
|
||||
*
|
||||
* When it is not necessary to get the exact length of a
|
||||
* vector (for example, when simply comparing the lengths of
|
||||
* different vectors), it is advised to use this method
|
||||
* instead of length.
|
||||
*
|
||||
* @return The squared length of the vector.
|
||||
*
|
||||
* @see length
|
||||
*/
|
||||
float length_squared() const;
|
||||
|
||||
/**
|
||||
* Negates this vector.
|
||||
*/
|
||||
void negate();
|
||||
|
||||
/**
|
||||
* Normalizes this vector.
|
||||
*
|
||||
* This method normalizes this Vec4 so that it is of
|
||||
* unit length (in other words, the length of the vector
|
||||
* after calling this method will be 1.0f). If the vector
|
||||
* already has unit length or if the length of the vector
|
||||
* is zero, this method does nothing.
|
||||
*/
|
||||
void normalize();
|
||||
|
||||
/**
|
||||
* Get the normalized vector.
|
||||
*/
|
||||
Vec4 get_normalized() const;
|
||||
|
||||
/**
|
||||
* Scales all elements of this vector by the specified value.
|
||||
*
|
||||
* @param scalar The scalar value.
|
||||
*/
|
||||
void scale(float scalar);
|
||||
|
||||
/**
|
||||
* Sets the elements of this vector to the specified values.
|
||||
*
|
||||
* @param xx The new x coordinate.
|
||||
* @param yy The new y coordinate.
|
||||
* @param zz The new z coordinate.
|
||||
* @param ww The new w coordinate.
|
||||
*/
|
||||
void set(float xx, float yy, float zz, float ww);
|
||||
|
||||
/**
|
||||
* Sets the elements of this vector from the values in the specified array.
|
||||
*
|
||||
* @param array An array containing the elements of the vector in the order x, y, z, w.
|
||||
*/
|
||||
void set(const float* array);
|
||||
|
||||
/**
|
||||
* Sets the elements of this vector to those in the specified vector.
|
||||
*
|
||||
* @param v The vector to copy.
|
||||
*/
|
||||
void set(const Vec4& v);
|
||||
|
||||
/**
|
||||
* Sets this vector to the directional vector between the specified points.
|
||||
*
|
||||
* @param p1 The first point.
|
||||
* @param p2 The second point.
|
||||
*/
|
||||
void set(const Vec4& p1, const Vec4& p2);
|
||||
|
||||
/**
|
||||
* Subtracts this vector and the specified vector as (this - v)
|
||||
* and stores the result in this vector.
|
||||
*
|
||||
* @param v The vector to subtract.
|
||||
*/
|
||||
void subtract(const Vec4& v);
|
||||
|
||||
/**
|
||||
* Subtracts the specified vectors and stores the result in dst.
|
||||
* The resulting vector is computed as (v1 - v2).
|
||||
*
|
||||
* @param v1 The first vector.
|
||||
* @param v2 The second vector.
|
||||
* @param dst The destination vector.
|
||||
*/
|
||||
static void subtract(const Vec4& v1, const Vec4& v2, Vec4* dst);
|
||||
|
||||
/**
|
||||
* Calculates the sum of this vector with the given vector.
|
||||
*
|
||||
* Note: this does not modify this vector.
|
||||
*
|
||||
* @param v The vector to add.
|
||||
* @return The vector sum.
|
||||
*/
|
||||
inline Vec4 operator+(const Vec4& v) const;
|
||||
|
||||
/**
|
||||
* Adds the given vector to this vector.
|
||||
*
|
||||
* @param v The vector to add.
|
||||
* @return This vector, after the addition occurs.
|
||||
*/
|
||||
inline Vec4& operator+=(const Vec4& v);
|
||||
|
||||
/**
|
||||
* Calculates the sum of this vector with the given vector.
|
||||
*
|
||||
* Note: this does not modify this vector.
|
||||
*
|
||||
* @param v The vector to add.
|
||||
* @return The vector sum.
|
||||
*/
|
||||
inline Vec4 operator-(const Vec4& v) const;
|
||||
|
||||
/**
|
||||
* Subtracts the given vector from this vector.
|
||||
*
|
||||
* @param v The vector to subtract.
|
||||
* @return This vector, after the subtraction occurs.
|
||||
*/
|
||||
inline Vec4& operator-=(const Vec4& v);
|
||||
|
||||
/**
|
||||
* Calculates the negation of this vector.
|
||||
*
|
||||
* Note: this does not modify this vector.
|
||||
*
|
||||
* @return The negation of this vector.
|
||||
*/
|
||||
inline Vec4 operator-() const;
|
||||
|
||||
/**
|
||||
* Calculates the scalar product of this vector with the given value.
|
||||
*
|
||||
* Note: this does not modify this vector.
|
||||
*
|
||||
* @param s The value to scale by.
|
||||
* @return The scaled vector.
|
||||
*/
|
||||
inline Vec4 operator*(float s) const;
|
||||
|
||||
/**
|
||||
* Scales this vector by the given value.
|
||||
*
|
||||
* @param s The value to scale by.
|
||||
* @return This vector, after the scale occurs.
|
||||
*/
|
||||
inline Vec4& operator*=(float s);
|
||||
|
||||
/**
|
||||
* Returns the components of this vector divided by the given constant
|
||||
*
|
||||
* Note: this does not modify this vector.
|
||||
*
|
||||
* @param s the constant to divide this vector with
|
||||
* @return a smaller vector
|
||||
*/
|
||||
inline Vec4 operator/(float s) const;
|
||||
|
||||
/**
|
||||
* Determines if this vector is less than the given vector.
|
||||
*
|
||||
* @param v The vector to compare against.
|
||||
*
|
||||
* @return True if this vector is less than the given vector, false otherwise.
|
||||
*/
|
||||
inline bool operator<(const Vec4& v) const;
|
||||
|
||||
/**
|
||||
* Determines if this vector is equal to the given vector.
|
||||
*
|
||||
* @param v The vector to compare against.
|
||||
*
|
||||
* @return True if this vector is equal to the given vector, false otherwise.
|
||||
*/
|
||||
inline bool operator==(const Vec4& v) const;
|
||||
|
||||
/**
|
||||
* Determines if this vector is not equal to the given vector.
|
||||
*
|
||||
* @param v The vector to compare against.
|
||||
*
|
||||
* @return True if this vector is not equal to the given vector, false otherwise.
|
||||
*/
|
||||
inline bool operator!=(const Vec4& v) const;
|
||||
|
||||
/** equals to Vec4(0,0,0,0) */
|
||||
static const Vec4 ZERO;
|
||||
/** equals to Vec4(1,1,1,1) */
|
||||
static const Vec4 ONE;
|
||||
/** equals to Vec4(1,0,0,0) */
|
||||
static const Vec4 UNIT_X;
|
||||
/** equals to Vec4(0,1,0,0) */
|
||||
static const Vec4 UNIT_Y;
|
||||
/** equals to Vec4(0,0,1,0) */
|
||||
static const Vec4 UNIT_Z;
|
||||
/** equals to Vec4(0,0,0,1) */
|
||||
static const Vec4 UNIT_W;
|
||||
};
|
||||
|
||||
/**
|
||||
* Calculates the scalar product of the given vector with the given value.
|
||||
*
|
||||
* @param x The value to scale by.
|
||||
* @param v The vector to scale.
|
||||
* @return The scaled vector.
|
||||
*/
|
||||
inline Vec4 operator*(float x, const Vec4& v);
|
||||
|
||||
}
|
||||
|
||||
#include "vec4.inl"
|
||||
|
||||
#endif /* VEC4_H */
|
97
mediapipe/render/core/math/vec4.inl
Normal file
97
mediapipe/render/core/math/vec4.inl
Normal file
|
@ -0,0 +1,97 @@
|
|||
//
|
||||
// vec4.inl
|
||||
// BdiEngine
|
||||
//
|
||||
// Created by Wang,Renzhu on 2018/11/20.
|
||||
// Copyright © 2018年 Wang,Renzhu. All rights reserved.
|
||||
//
|
||||
|
||||
#include "vec4.hpp"
|
||||
|
||||
namespace Quaramera {
|
||||
|
||||
inline Vec4 Vec4::operator+(const Vec4& v) const
|
||||
{
|
||||
Vec4 result(*this);
|
||||
result.add(v);
|
||||
return result;
|
||||
}
|
||||
|
||||
inline Vec4& Vec4::operator+=(const Vec4& v)
|
||||
{
|
||||
add(v);
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline Vec4 Vec4::operator-(const Vec4& v) const
|
||||
{
|
||||
Vec4 result(*this);
|
||||
result.subtract(v);
|
||||
return result;
|
||||
}
|
||||
|
||||
inline Vec4& Vec4::operator-=(const Vec4& v)
|
||||
{
|
||||
subtract(v);
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline Vec4 Vec4::operator-() const
|
||||
{
|
||||
Vec4 result(*this);
|
||||
result.negate();
|
||||
return result;
|
||||
}
|
||||
|
||||
inline Vec4 Vec4::operator*(float s) const
|
||||
{
|
||||
Vec4 result(*this);
|
||||
result.scale(s);
|
||||
return result;
|
||||
}
|
||||
|
||||
inline Vec4& Vec4::operator*=(float s)
|
||||
{
|
||||
scale(s);
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline Vec4 Vec4::operator/(const float s) const
|
||||
{
|
||||
return Vec4(this->x / s, this->y / s, this->z / s, this->w / s);
|
||||
}
|
||||
|
||||
inline bool Vec4::operator<(const Vec4& v) const
|
||||
{
|
||||
if (x == v.x) {
|
||||
if (y == v.y) {
|
||||
if (z == v.z) {
|
||||
if (w < v.w) {
|
||||
return w < v.w;
|
||||
}
|
||||
}
|
||||
return z < v.z;
|
||||
}
|
||||
return y < v.y;
|
||||
}
|
||||
return x < v.x;
|
||||
}
|
||||
|
||||
inline bool Vec4::operator==(const Vec4& v) const
|
||||
{
|
||||
return x == v.x && y == v.y && z == v.z && w == v.w;
|
||||
}
|
||||
|
||||
inline bool Vec4::operator!=(const Vec4& v) const
|
||||
{
|
||||
return x != v.x || y != v.y || z != v.z || w != v.w;
|
||||
}
|
||||
|
||||
inline Vec4 operator*(float x, const Vec4& v)
|
||||
{
|
||||
Vec4 result(v);
|
||||
result.scale(x);
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
58
mediapipe/render/ios/BUILD
Normal file
58
mediapipe/render/ios/BUILD
Normal file
|
@ -0,0 +1,58 @@
|
|||
load("@bazel_skylib//lib:selects.bzl", "selects")
|
||||
load("@build_bazel_rules_apple//apple:ios.bzl", "ios_unit_test")
|
||||
load(
|
||||
"//mediapipe/framework/tool:mediapipe_graph.bzl",
|
||||
"mediapipe_binary_graph",
|
||||
)
|
||||
|
||||
|
||||
load("@bazel_skylib//lib:selects.bzl", "selects")
|
||||
load("@build_bazel_rules_apple//apple:ios.bzl", "ios_unit_test")
|
||||
load("@build_bazel_rules_apple//apple:ios.bzl", "ios_framework")
|
||||
|
||||
ios_framework(
|
||||
name = "OlaRenderFramework",
|
||||
hdrs = [
|
||||
"OlaRender.h",
|
||||
],
|
||||
infoplists = ["Info.plist"],
|
||||
bundle_id = "com.noppelab.MyFramework",
|
||||
families = ["iphone", "ipad"],
|
||||
minimum_os_version = "10.0",
|
||||
deps = [
|
||||
":OlaRender",
|
||||
"@ios_opencv//:OpencvFramework",
|
||||
],
|
||||
)
|
||||
|
||||
objc_library(
|
||||
name = "OlaRender",
|
||||
srcs = [
|
||||
"OlaRender.mm",
|
||||
],
|
||||
hdrs = [
|
||||
"OlaRender.h",
|
||||
],
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//mediapipe/render/core:core",
|
||||
"//mediapipe/objc:mediapipe_framework_ios",
|
||||
"//mediapipe/objc:mediapipe_input_sources_ios",
|
||||
"//mediapipe/objc:mediapipe_layer_renderer",
|
||||
],
|
||||
copts = select({
|
||||
"//mediapipe:apple": [
|
||||
"-x objective-c++",
|
||||
"-fobjc-arc", # enable reference-counting
|
||||
],
|
||||
"//conditions:default": [],
|
||||
}),
|
||||
sdk_frameworks = [
|
||||
"AVFoundation",
|
||||
"CoreGraphics",
|
||||
"CoreMedia",
|
||||
"UIKit",
|
||||
"OpenGLES",
|
||||
"AssetsLibrary",
|
||||
],
|
||||
)
|
1
mediapipe/render/ios/Camera/BUILD
Normal file
1
mediapipe/render/ios/Camera/BUILD
Normal file
|
@ -0,0 +1 @@
|
|||
load("//mediapipe/gpu:metal.bzl", "metal_library")
|
22
mediapipe/render/ios/Camera/Info.plist
Normal file
22
mediapipe/render/ios/Camera/Info.plist
Normal file
|
@ -0,0 +1,22 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>$(EXECUTABLE_NAME)</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>$(PRODUCT_NAME)</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>$(CURRENT_PROJECT_VERSION)</string>
|
||||
</dict>
|
||||
</plist>
|
20
mediapipe/render/ios/Camera/OlaCameraFramework.h
Normal file
20
mediapipe/render/ios/Camera/OlaCameraFramework.h
Normal file
|
@ -0,0 +1,20 @@
|
|||
//
|
||||
// QuarameraFramework.h
|
||||
// QuarameraFramework
|
||||
//
|
||||
// Created by wangrenzhu on 2021/1/25.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <QuarameraFramework/QuarameraMTLCameraRenderView.h>
|
||||
|
||||
|
||||
//! Project version number for QuarameraFramework.
|
||||
FOUNDATION_EXPORT double QuarameraFrameworkVersionNumber;
|
||||
|
||||
//! Project version string for QuarameraFramework.
|
||||
FOUNDATION_EXPORT const unsigned char QuarameraFrameworkVersionString[];
|
||||
|
||||
// In this header, you should import all the public headers of your framework using statements like #import <QuarameraFramework/PublicHeader.h>
|
||||
|
||||
|
39
mediapipe/render/ios/Camera/OlaCameraRender.h
Normal file
39
mediapipe/render/ios/Camera/OlaCameraRender.h
Normal file
|
@ -0,0 +1,39 @@
|
|||
//
|
||||
// QuarameraCameraRender.h
|
||||
// QuarameraFramework
|
||||
//
|
||||
// Created by wangrenzhu on 2021/1/25.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <AVFoundation/AVFoundation.h>
|
||||
#import "QuarameraShareTexture.h"
|
||||
|
||||
@interface OlaCameraRender : NSObject
|
||||
@property (nonatomic, readonly) CGSize renderSize;
|
||||
@property (nonatomic, readonly) BOOL enable;
|
||||
|
||||
- (instancetype)initWithRenderSize:(CGSize)renderSize
|
||||
device:(id<MTLDevice>)device
|
||||
cameraTexture:(QuarameraShareTexture *)cameraTexture
|
||||
contentScaleFactor:(CGFloat)factor;
|
||||
|
||||
- (void)setupWithDevice:(id<MTLDevice>)device shareTexture:(QuarameraShareTexture *)shareTexture useRenderMode:(BOOL)useRenderMode;
|
||||
|
||||
/// 重置画布大小
|
||||
/// @param renderSize 画布大小
|
||||
- (void)resize:(CGSize)renderSize;
|
||||
|
||||
/// 处理相机采集流
|
||||
/// @param sampleBuffer 相机采集流
|
||||
- (void)processSampleBuffer:(CMSampleBufferRef)sampleBuffer;
|
||||
|
||||
|
||||
/// 渲染
|
||||
/// @param frameTime 帧时间
|
||||
- (void)render:(NSTimeInterval)frameTime;
|
||||
|
||||
- (void)updateCameraTexture:(QuarameraShareTexture *)cameraTexture;
|
||||
|
||||
|
||||
@end
|
53
mediapipe/render/ios/Camera/OlaCameraRender.m
Normal file
53
mediapipe/render/ios/Camera/OlaCameraRender.m
Normal file
|
@ -0,0 +1,53 @@
|
|||
//
|
||||
// QuarameraCameraRender.m
|
||||
// QuarameraFramework
|
||||
//
|
||||
// Created by wangrenzhu on 2021/1/25.
|
||||
//
|
||||
|
||||
#import "QuarameraCameraRender.h"
|
||||
|
||||
@implementation QuarameraCameraRender
|
||||
@synthesize renderSize = _renderSize;
|
||||
|
||||
- (instancetype)initWithRenderSize:(CGSize)renderSize
|
||||
device:(id<MTLDevice>)device
|
||||
cameraTexture:(QuarameraShareTexture *)cameraTexture
|
||||
contentScaleFactor:(CGFloat)factor
|
||||
{
|
||||
NSAssert(NO, @"subclass must implement this method");
|
||||
return nil;
|
||||
}
|
||||
|
||||
|
||||
- (void)setupWithDevice:(id<MTLDevice>)device shareTexture:(QuarameraShareTexture *)shareTexture useRenderMode:(BOOL)useRenderMode;
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
- (void)processSampleBuffer:(CMSampleBufferRef)sampleBuffer
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
- (void)resize:(CGSize)renderSize
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
- (void)render:(NSTimeInterval)frameTime
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
- (void)updateCameraTexture:(QuarameraShareTexture *)cameraTexture
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
- (BOOL)enable
|
||||
{
|
||||
return NO;
|
||||
}
|
||||
|
||||
@end
|
196
mediapipe/render/ios/Camera/QuarameraFramework.metal
Normal file
196
mediapipe/render/ios/Camera/QuarameraFramework.metal
Normal file
|
@ -0,0 +1,196 @@
|
|||
//
|
||||
// WebARShader.metal
|
||||
// Pods-WebAR-iOS
|
||||
//
|
||||
// Created by Wang Huai on 2019/9/16.
|
||||
//
|
||||
|
||||
#include <metal_stdlib>
|
||||
using namespace metal;
|
||||
|
||||
struct SingleInputVertexIO
|
||||
{
|
||||
float4 position [[position]];
|
||||
float2 textureCoordinate [[user(texturecoord)]];
|
||||
};
|
||||
|
||||
struct TextureScale
|
||||
{
|
||||
float3 scale;
|
||||
};
|
||||
|
||||
struct TwoInputVertexIO
|
||||
{
|
||||
float4 position [[position]];
|
||||
float2 textureCoordinate [[user(texturecoord)]];
|
||||
float2 textureCoordinate2 [[user(texturecoord2)]];
|
||||
};
|
||||
|
||||
fragment half4 yuvConversionFullRangeFragment(TwoInputVertexIO fragmentInput [[stage_in]],
|
||||
texture2d<half> inputTexture [[texture(0)]],
|
||||
texture2d<half> inputTexture2 [[texture(1)]],
|
||||
constant TextureScale &scaleUniform [[buffer(0)]])
|
||||
{
|
||||
constexpr sampler quadSampler;
|
||||
float2 scaleCoordinate = (fragmentInput.textureCoordinate - 0.5) * scaleUniform.scale.xy + 0.5;
|
||||
if(scaleUniform.scale.z == 1.0) {
|
||||
scaleCoordinate.y = 1.0 - scaleCoordinate.y;
|
||||
}
|
||||
// scaleCoordinate.y = -(scaleUniform.scale.z + scaleCoordinate.y);
|
||||
half3 yuv;
|
||||
yuv.x = inputTexture.sample(quadSampler, scaleCoordinate).r;
|
||||
yuv.yz = inputTexture2.sample(quadSampler, scaleCoordinate).rg - half2(0.5, 0.5);
|
||||
const half3x3 kColorConversion601Default = {
|
||||
{1.164, 1.164, 1.164},
|
||||
{0.0, -0.392, 2.017},
|
||||
{1.596, -0.813, 0.0},
|
||||
};
|
||||
|
||||
half3 rgb = kColorConversion601Default * yuv;
|
||||
|
||||
return half4(rgb, 1.0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
vertex TwoInputVertexIO twoInputVertex(const device packed_float2 *position [[buffer(0)]],
|
||||
const device packed_float2 *texturecoord [[buffer(1)]],
|
||||
const device packed_float2 *texturecoord2 [[buffer(2)]],
|
||||
uint vid [[vertex_id]])
|
||||
{
|
||||
TwoInputVertexIO outputVertices;
|
||||
|
||||
outputVertices.position = float4(position[vid], 0, 1.0);
|
||||
outputVertices.textureCoordinate = texturecoord[vid];
|
||||
outputVertices.textureCoordinate2 = texturecoord2[vid];
|
||||
|
||||
return outputVertices;
|
||||
}
|
||||
|
||||
constant half3 ColorOffsetFullRange = half3(0.0, -0.5, -0.5);
|
||||
|
||||
kernel void yuv2rgb(texture2d<half, access::read> y_tex [[ texture(0) ]],
|
||||
texture2d<half, access::read> uv_tex [[ texture(1) ]],
|
||||
texture2d<half, access::write> bgr_tex [[ texture(2) ]],
|
||||
uint2 gid [[thread_position_in_grid]])
|
||||
{
|
||||
|
||||
half3 yuv = half3(y_tex.read(gid).r, half2(uv_tex.read(gid/2).rg)) + ColorOffsetFullRange;
|
||||
|
||||
const half3x3 kColorConversion601Default = {
|
||||
{1.164, 1.164, 1.164},
|
||||
{0.0, -0.392, 2.017},
|
||||
{1.596, -0.813, 0.0},
|
||||
};
|
||||
|
||||
half4 conversion = half4(kColorConversion601Default * yuv, 1.0);
|
||||
bgr_tex.write(conversion, gid);
|
||||
}
|
||||
|
||||
|
||||
|
||||
vertex SingleInputVertexIO oneInputVertex(const device packed_float2 *position [[buffer(0)]],
|
||||
const device packed_float2 *texturecoord [[buffer(1)]],
|
||||
uint vid [[vertex_id]])
|
||||
{
|
||||
SingleInputVertexIO outputVertices;
|
||||
|
||||
outputVertices.position = float4(position[vid], 0, 1.0);
|
||||
outputVertices.textureCoordinate = texturecoord[vid];
|
||||
|
||||
return outputVertices;
|
||||
}
|
||||
|
||||
float udRoundBox(half2 p, half2 b, float r)
|
||||
{
|
||||
|
||||
return length(max(abs(p) - b + r, 0.0)) - r;
|
||||
}
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int useScan;
|
||||
float iRadius;
|
||||
float squareWidth;
|
||||
float width;
|
||||
float height;
|
||||
float iTime;
|
||||
} ScanUniform;
|
||||
|
||||
fragment half4 scanFragment(SingleInputVertexIO fragmentInput [[stage_in]],
|
||||
texture2d<half> inputTexture [[texture(0)]],
|
||||
constant ScanUniform& uniform [[buffer(1)]])
|
||||
{
|
||||
constexpr sampler quadSampler(mag_filter::linear,
|
||||
min_filter::linear);
|
||||
half4 color = inputTexture.sample(quadSampler, fragmentInput.textureCoordinate);
|
||||
if (uniform.useScan == 0) {
|
||||
return color;
|
||||
}
|
||||
|
||||
half2 iResolution = half2(uniform.width, uniform.height);
|
||||
half2 uv = half2(fragmentInput.textureCoordinate);
|
||||
half2 fragCoord = iResolution * uv;
|
||||
half2 center = iResolution / 2.0;
|
||||
half2 halfRes = 0.5 * half2(uniform.squareWidth);
|
||||
float b = udRoundBox(fragCoord.xy - center, halfRes, uniform.iRadius);
|
||||
color = half4(mix(color.rgb, half3(0.0), smoothstep(0.0, 1.0, b) * 0.5 ).rgb, 1.0);
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
fragment half4 passthroughFragment(SingleInputVertexIO fragmentInput [[stage_in]],
|
||||
texture2d<half> inputTexture [[texture(0)]])
|
||||
{
|
||||
constexpr sampler quadSampler(mag_filter::linear,
|
||||
min_filter::linear);
|
||||
half4 color = inputTexture.sample(quadSampler, fragmentInput.textureCoordinate);
|
||||
return color;
|
||||
}
|
||||
|
||||
|
||||
typedef struct {
|
||||
float4 position [[position]];
|
||||
float2 texCoord;
|
||||
} WAFrameVertexOut;
|
||||
|
||||
constant half3 c0 (1., 1., 1.);
|
||||
constant half3 c1 (0., -.18732, 1.8556);
|
||||
constant half3 c2 (1.57481, -.46813,0.);
|
||||
|
||||
vertex WAFrameVertexOut v_display(uint vertexID [[ vertex_id ]],
|
||||
constant packed_float4* vertexArray [[ buffer(0) ]]) {
|
||||
float4 vertexData = vertexArray[vertexID];
|
||||
WAFrameVertexOut out;
|
||||
out.position = float4(vertexData.xy,0.0,1.0);
|
||||
out.texCoord = vertexData.zw;
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
fragment float4 f_display(WAFrameVertexOut in [[stage_in]],
|
||||
texture2d<half, access::sample> colorTexture [[texture(0)]]) {
|
||||
|
||||
constexpr sampler textureSampler (mag_filter::linear,
|
||||
min_filter::linear);
|
||||
|
||||
// Sample the texture to obtain a color
|
||||
const half4 colorSample = colorTexture.sample(textureSampler, in.texCoord);
|
||||
|
||||
// return the color of the texture
|
||||
return float4(colorSample);
|
||||
}
|
||||
|
||||
kernel void k_ycr2rgb(texture2d<half, access::read> lumTexture [[texture(0)]],
|
||||
texture2d<half, access::read> chromeTexture [[texture(1)]],
|
||||
texture2d<half, access::write> outTexture [[texture(2)]],
|
||||
uint2 gid [[thread_position_in_grid]]) {
|
||||
if ((gid.x >= lumTexture.get_width()) || (gid.y >= lumTexture.get_height())) {
|
||||
return;
|
||||
}
|
||||
|
||||
half3 ycbcr = half3(lumTexture.read(gid).r , chromeTexture.read(gid/2).rg - 0.5);
|
||||
half3 color = half3x3(c0,c1,c2) * ycbcr;
|
||||
|
||||
outTexture.write(half4(color, 1.0), gid);
|
||||
}
|
63
mediapipe/render/ios/Camera/QuarameraMTLCameraRender.h
Normal file
63
mediapipe/render/ios/Camera/QuarameraMTLCameraRender.h
Normal file
|
@ -0,0 +1,63 @@
|
|||
//
|
||||
// QuarameraMTLRender.h
|
||||
// QuameraDemo
|
||||
//
|
||||
// Created by wangrenzhu on 2021/1/22.
|
||||
// Copyright © 2021 alibaba. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <AVFoundation/AVFoundation.h>
|
||||
#import <UIKit/UIKit.h>
|
||||
#import <MetalKit/MetalKit.h>
|
||||
#import "QuarameraShareTexture.h"
|
||||
#import "QuarameraCameraRender.h"
|
||||
|
||||
@protocol QuarameraMTLCameraRenderDelegate <NSObject>
|
||||
|
||||
/// 闪电拍照准备完毕
|
||||
- (void)lightningModelPrepared;
|
||||
|
||||
/// 首帧渲染完毕
|
||||
- (void)firstFrameRendered;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
|
||||
@interface QuarameraMTLCameraRender : QuarameraCameraRender
|
||||
|
||||
/// 输出CameraTexture
|
||||
@property (nonatomic) id<MTLTexture> outputTexture;
|
||||
@property (nonatomic) BOOL lightningMode;
|
||||
@property (nonatomic) BOOL useScan;
|
||||
@property (nonatomic) BOOL needFlip;
|
||||
@property (nonatomic) id<MTLBuffer> noRotationBuffer;
|
||||
@property (nonatomic) CGFloat contentScaleFactor;
|
||||
@property (nonatomic) id<MTLCommandQueue> commandQueue;
|
||||
|
||||
/// renderTarget 可以快速拿到相机的渲染结果
|
||||
@property (nonatomic, readonly) CVPixelBufferRef renderTarget;
|
||||
|
||||
|
||||
@property (nonatomic, weak) id<QuarameraMTLCameraRenderDelegate> renderDelegate;
|
||||
@property (nonatomic, strong) QuarameraShareTexture *offscreenCameraTexture;
|
||||
|
||||
/// 渲染到纹理指令
|
||||
/// @param displayTexture displayTexture description
|
||||
/// @param sourceTexture sourceTexture description
|
||||
/// @param commandBuffer commandBuffer description
|
||||
/// @param coordinateBuffer coordinateBuffer description
|
||||
- (void)renderToTexture:(id<MTLTexture>)displayTexture
|
||||
from:(id<MTLTexture>)sourceTexture
|
||||
commandBuffer:(id<MTLCommandBuffer>)commandBuffer
|
||||
textureCoordinate:(id<MTLBuffer>)coordinateBuffer;
|
||||
|
||||
- (void)renderToShareTexture:(id<MTLTexture>)shareTexture commandBuffer:(id<MTLCommandBuffer>)commandBuffer frameTime:(NSTimeInterval)frameTime;
|
||||
|
||||
/// 通过Metal处理相机数据
|
||||
/// @param pixelBuffer pixelBuffer description
|
||||
/// @param completedHandler completedHandler description
|
||||
- (void)renderToCameraTextureWithPixelBuffer:(CVPixelBufferRef)pixelBuffer completedHandler:(MTLCommandBufferHandler)completedHandler;
|
||||
|
||||
@end
|
458
mediapipe/render/ios/Camera/QuarameraMTLCameraRender.mm
Normal file
458
mediapipe/render/ios/Camera/QuarameraMTLCameraRender.mm
Normal file
|
@ -0,0 +1,458 @@
|
|||
//
|
||||
// QuarameraMTLRender.m
|
||||
// QuameraDemo
|
||||
//
|
||||
// Created by wangrenzhu on 2021/1/22.
|
||||
// Copyright © 2021 alibaba. All rights reserved.
|
||||
//
|
||||
#import <MetalKit/MetalKit.h>
|
||||
#import <simd/simd.h>
|
||||
#import "QuarameraMTLCameraRender.h"
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int useScan;
|
||||
float iRadius;
|
||||
float squareWidth;
|
||||
float width;
|
||||
float height;
|
||||
float iTime;
|
||||
} ScanUniform;
|
||||
|
||||
static const float noRotationTextureCoordinates[] = {
|
||||
0.0f, 0.0f,
|
||||
1.0f, 0.0f,
|
||||
0.0f, 1.0f,
|
||||
1.0f, 1.0f,
|
||||
};
|
||||
|
||||
static const float rotate90TextureCoordinates[] = {
|
||||
0.0f, 1.0f,
|
||||
0.0f, 0.0f,
|
||||
1.0f, 1.0f,
|
||||
1.0f, 0.0f,
|
||||
};
|
||||
|
||||
static const float standardImageVertices[] = {
|
||||
-1.0, 1.0,
|
||||
1.0, 1.0,
|
||||
-1.0, -1.0,
|
||||
1.0, -1.0
|
||||
};
|
||||
|
||||
struct TextureScale {
|
||||
simd_float3 scaleFlip;
|
||||
};
|
||||
|
||||
@interface QuarameraMTLCameraRender()
|
||||
|
||||
@property (nonatomic) id<MTLRenderPipelineState> colorConvertPipelineState;
|
||||
|
||||
@property (nonatomic, strong) MTLRenderPipelineDescriptor *colorConvertRenderPipelineDesc;
|
||||
@property (nonatomic) id<MTLTexture> cameraTexture;
|
||||
|
||||
@property (nonatomic) id<MTLRenderPipelineState> transformRenderPipeline;
|
||||
|
||||
@property (nonatomic) id<MTLTexture> luminanceTextureTexture;
|
||||
@property (nonatomic) id<MTLTexture> chrominanceTextureTexure;
|
||||
|
||||
@property (nonatomic, strong) MTLRenderPipelineDescriptor *renderPipelineDesc;
|
||||
|
||||
@property (nonatomic) CVMetalTextureCacheRef mtlTextureCacheRef;
|
||||
|
||||
@property (nonatomic) MTLSize threadGroups;
|
||||
@property (nonatomic) MTLSize threadsPerGroups;
|
||||
|
||||
@property (nonatomic) id<MTLLibrary> library;
|
||||
@property (nonatomic) id<MTLDevice> device;
|
||||
@property (nonatomic) id<MTLBuffer> textureCoordinateBuffer;
|
||||
@property (nonatomic) id<MTLBuffer> outputVertextBuffer;
|
||||
@property (nonatomic) id<MTLBuffer> textureScaleBuffer;
|
||||
|
||||
@property (nonatomic) float aspect;
|
||||
@property (nonatomic) TextureScale textureScale;
|
||||
@property (nonatomic) BOOL isInit;
|
||||
@property (nonatomic) NSTimeInterval iTime;
|
||||
@property (nonatomic) BOOL firstFrameRender;
|
||||
|
||||
@property (nonatomic) size_t cameraOutputWidth;
|
||||
@property (nonatomic) size_t cameraOutputHeight;
|
||||
|
||||
@property (nonatomic, strong) QuarameraShareTexture *shareTexture;
|
||||
|
||||
|
||||
@end
|
||||
|
||||
@implementation QuarameraMTLCameraRender
|
||||
@synthesize renderSize = _renderSize;
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
self.renderDelegate = nil;
|
||||
_luminanceTextureTexture = nil;
|
||||
_chrominanceTextureTexure = nil;
|
||||
_renderPipelineDesc = nil;
|
||||
_cameraTexture = nil;
|
||||
_colorConvertPipelineState = nil;
|
||||
|
||||
_transformRenderPipeline = nil;
|
||||
_commandQueue = nil;
|
||||
|
||||
_textureCoordinateBuffer = nil;
|
||||
_outputVertextBuffer = nil;
|
||||
if (_mtlTextureCacheRef) {
|
||||
CFRelease(_mtlTextureCacheRef);
|
||||
}
|
||||
|
||||
_offscreenCameraTexture = nil;
|
||||
_shareTexture = nil;
|
||||
|
||||
}
|
||||
|
||||
- (instancetype)initWithRenderSize:(CGSize)renderSize
|
||||
device:(id<MTLDevice>)device
|
||||
cameraTexture:(QuarameraShareTexture *)cameraTexture
|
||||
contentScaleFactor:(CGFloat)factor
|
||||
{
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_contentScaleFactor = factor;
|
||||
[self resize:renderSize];
|
||||
self.device = device;
|
||||
__unused NSError *error;
|
||||
_offscreenCameraTexture = cameraTexture;
|
||||
NSBundle *bundle = [NSBundle mainBundle];
|
||||
NSURL *shaderURL = [bundle URLForResource:@"QuarameraFramework" withExtension:@"metallib"];
|
||||
if (@available(iOS 11.0, *)) {
|
||||
if (shaderURL) {
|
||||
self.library = [self.device newLibraryWithURL:shaderURL error:&error];
|
||||
}
|
||||
} else {
|
||||
NSString *lib = [[NSBundle mainBundle] pathForResource:@"QuarameraFramework" ofType:@"metallib"];
|
||||
if (lib) {
|
||||
_library = [_device newLibraryWithFile:lib error:nil];
|
||||
}
|
||||
}
|
||||
NSDictionary * cacheAttributes = @{ (NSString *)kCVMetalTextureCacheMaximumTextureAgeKey: @(0.0) };
|
||||
NSAssert(error == nil, @"newDefaultLibraryWithBundle %@", error);
|
||||
CVMetalTextureCacheCreate(NULL, NULL, self.device,
|
||||
(__bridge CFDictionaryRef _Nullable)(cacheAttributes),
|
||||
&_mtlTextureCacheRef);
|
||||
|
||||
_aspect = self.renderSize.height / self.renderSize.width;
|
||||
|
||||
self.cameraOutputWidth = self.renderSize.width;
|
||||
self.cameraOutputHeight = self.renderSize.height;
|
||||
|
||||
[self initPipeline];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
#pragma mark
|
||||
#pragma mark Private
|
||||
|
||||
- (void)initPipeline
|
||||
{
|
||||
if (self.renderTarget == nil || self.offscreenCameraTexture == nil) {
|
||||
return;
|
||||
}
|
||||
|
||||
self.commandQueue = [self.device newCommandQueue];
|
||||
__unused NSError *error;
|
||||
NSAssert(error == nil, @"newDefaultLibraryWithBundle %@", error);
|
||||
|
||||
id<MTLFunction> colorVertexFunc = [self.library newFunctionWithName:@"twoInputVertex"];
|
||||
id<MTLFunction> colorFragFunc = [self.library newFunctionWithName:@"yuvConversionFullRangeFragment"];
|
||||
MTLRenderPipelineDescriptor *colorConvertRenderDesc = [MTLRenderPipelineDescriptor new];
|
||||
colorConvertRenderDesc.colorAttachments[0].pixelFormat = MTLPixelFormatBGRA8Unorm;
|
||||
colorConvertRenderDesc.rasterSampleCount = 1;
|
||||
colorConvertRenderDesc.vertexFunction = colorVertexFunc;
|
||||
colorConvertRenderDesc.fragmentFunction = colorFragFunc;
|
||||
self.colorConvertRenderPipelineDesc = colorConvertRenderDesc;
|
||||
|
||||
self.colorConvertPipelineState = [self.device
|
||||
newRenderPipelineStateWithDescriptor:self.colorConvertRenderPipelineDesc
|
||||
error:&error];
|
||||
|
||||
NSAssert(error == nil, @"colorConvertPipelineState newRenderPipelineStateWithDescriptor %@", error);
|
||||
|
||||
id<MTLFunction> vertexFunc = [self.library newFunctionWithName:@"oneInputVertex"];
|
||||
id<MTLFunction> fragFunc = [self.library newFunctionWithName:@"passthroughFragment"];
|
||||
|
||||
|
||||
MTLRenderPipelineDescriptor *renderDesc = [MTLRenderPipelineDescriptor new];
|
||||
renderDesc.colorAttachments[0].pixelFormat = MTLPixelFormatBGRA8Unorm;
|
||||
renderDesc.rasterSampleCount = 1;
|
||||
renderDesc.vertexFunction = vertexFunc;
|
||||
renderDesc.fragmentFunction = fragFunc;
|
||||
|
||||
self.renderPipelineDesc = renderDesc;
|
||||
|
||||
self.transformRenderPipeline = [self.device newRenderPipelineStateWithDescriptor:self.renderPipelineDesc error:&error];
|
||||
NSAssert(error == nil, @"transformRenderPipeline newRenderPipelineStateWithDescriptor %@", error);
|
||||
|
||||
|
||||
self.textureCoordinateBuffer = [self.device newBufferWithBytes:rotate90TextureCoordinates
|
||||
length:sizeof(rotate90TextureCoordinates)
|
||||
options:MTLResourceStorageModeShared];
|
||||
|
||||
self.noRotationBuffer = [self.device newBufferWithBytes:noRotationTextureCoordinates
|
||||
length:sizeof(noRotationTextureCoordinates)
|
||||
options:MTLResourceStorageModeShared];
|
||||
self.outputVertextBuffer = [self.device newBufferWithBytes:standardImageVertices
|
||||
length:sizeof(standardImageVertices)
|
||||
options:MTLResourceStorageModeShared];
|
||||
|
||||
self.isInit = YES;
|
||||
}
|
||||
|
||||
#pragma mark
|
||||
#pragma mark - Offscreen Render Camera
|
||||
|
||||
- (void)renderToCameraTextureWithPixelBuffer:(CVPixelBufferRef)pixelBuffer
|
||||
completedHandler:(MTLCommandBufferHandler)completedHandler
|
||||
{
|
||||
[self ensureTexture:pixelBuffer completedHandler:completedHandler];
|
||||
}
|
||||
|
||||
- (void)ensureTexture:(CVPixelBufferRef)cameraBuffer completedHandler:(MTLCommandBufferHandler)completedHandler
|
||||
{
|
||||
size_t outputWidth = CVPixelBufferGetWidth(cameraBuffer);
|
||||
size_t outputHeight = CVPixelBufferGetHeight(cameraBuffer);
|
||||
|
||||
if (self.renderTarget == nil || self.transformRenderPipeline == nil) {
|
||||
return; //renderTarget没创建不渲染
|
||||
}
|
||||
|
||||
if (@available(iOS 11.0, *)) {
|
||||
|
||||
MTLTextureDescriptor *luminanceTextureDesc = [MTLTextureDescriptor
|
||||
texture2DDescriptorWithPixelFormat:MTLPixelFormatR8Unorm
|
||||
width:outputWidth
|
||||
height:outputHeight
|
||||
mipmapped:NO];
|
||||
luminanceTextureDesc.storageMode = MTLStorageModeShared;
|
||||
luminanceTextureDesc.usage = MTLTextureUsageShaderRead;
|
||||
|
||||
MTLTextureDescriptor *chrominanceTextureDesc = [MTLTextureDescriptor
|
||||
texture2DDescriptorWithPixelFormat:MTLPixelFormatRG8Unorm
|
||||
width:outputWidth / 2
|
||||
height:outputHeight / 2
|
||||
mipmapped:NO];
|
||||
chrominanceTextureDesc.storageMode = MTLStorageModeShared;
|
||||
chrominanceTextureDesc.usage = MTLTextureUsageShaderRead;
|
||||
|
||||
self.luminanceTextureTexture = [self.device newTextureWithDescriptor:luminanceTextureDesc
|
||||
iosurface:CVPixelBufferGetIOSurface(cameraBuffer)
|
||||
plane:0];
|
||||
|
||||
self.chrominanceTextureTexure = [self.device newTextureWithDescriptor:chrominanceTextureDesc
|
||||
iosurface:CVPixelBufferGetIOSurface(cameraBuffer)
|
||||
plane:1];
|
||||
luminanceTextureDesc = nil;
|
||||
chrominanceTextureDesc = nil;
|
||||
} else {
|
||||
|
||||
CVMetalTextureRef luminanceTextureRef;
|
||||
CVMetalTextureRef chrominanceTextureRef;
|
||||
|
||||
CVMetalTextureCacheCreateTextureFromImage(kCFAllocatorDefault,
|
||||
self.mtlTextureCacheRef,
|
||||
cameraBuffer,
|
||||
NULL,
|
||||
MTLPixelFormatR8Unorm, outputWidth, outputHeight, 0,
|
||||
&luminanceTextureRef);
|
||||
|
||||
|
||||
CVMetalTextureCacheCreateTextureFromImage(kCFAllocatorDefault,
|
||||
self.mtlTextureCacheRef,
|
||||
cameraBuffer,
|
||||
NULL,
|
||||
MTLPixelFormatRG8Unorm, outputWidth / 2,
|
||||
outputHeight / 2, 1, &chrominanceTextureRef);
|
||||
|
||||
self.luminanceTextureTexture = CVMetalTextureGetTexture(luminanceTextureRef);
|
||||
CFRelease(luminanceTextureRef);
|
||||
self.chrominanceTextureTexure = CVMetalTextureGetTexture(chrominanceTextureRef);
|
||||
CFRelease(chrominanceTextureRef);
|
||||
}
|
||||
|
||||
id<MTLCommandBuffer> commandBuffer = [self.commandQueue commandBuffer];
|
||||
commandBuffer.label = @"color conversion buffer";
|
||||
|
||||
MTLRenderPassDescriptor *colorRenderPass = [MTLRenderPassDescriptor renderPassDescriptor];
|
||||
|
||||
colorRenderPass.colorAttachments[0].texture = self.offscreenCameraTexture.metalTexture;
|
||||
colorRenderPass.colorAttachments[0].loadAction = MTLLoadActionClear;
|
||||
colorRenderPass.colorAttachments[0].clearColor = MTLClearColorMake(0.0, 0.0, 0.0, 0.0);
|
||||
colorRenderPass.colorAttachments[0].storeAction = MTLStoreActionStore;
|
||||
|
||||
id<MTLRenderCommandEncoder> colorConversionEncoder = [commandBuffer renderCommandEncoderWithDescriptor:colorRenderPass];
|
||||
colorConversionEncoder.label = @"Color Encoder";
|
||||
float textureAspectRatio = (float)outputWidth / (float)outputHeight;
|
||||
float drawAspectRatio = self.renderSize.height / self.renderSize.width;
|
||||
|
||||
_textureScale.scaleFlip.x = 1.0;
|
||||
_textureScale.scaleFlip.y = 1.0;
|
||||
if (drawAspectRatio == textureAspectRatio) {
|
||||
_textureScale.scaleFlip.x = 1.0;
|
||||
_textureScale.scaleFlip.y = 1.0;
|
||||
} else if (self.renderSize.height > self.renderSize.width) {
|
||||
//竖屏
|
||||
float realHeight = outputHeight > outputWidth ? outputHeight : outputWidth;
|
||||
float realWidth = outputHeight < outputWidth ? outputHeight : outputWidth;
|
||||
if (drawAspectRatio > textureAspectRatio) {
|
||||
//太宽了
|
||||
float newWidth = (float)realHeight / drawAspectRatio;
|
||||
_textureScale.scaleFlip.y = newWidth / (float)realWidth;
|
||||
_textureScale.scaleFlip.x = 1.0;
|
||||
} else {
|
||||
//太高了
|
||||
float newHeight = (float)realWidth * drawAspectRatio;
|
||||
_textureScale.scaleFlip.x = newHeight / (float)realHeight;
|
||||
_textureScale.scaleFlip.y = 1.0;
|
||||
}
|
||||
} else {
|
||||
//横屏
|
||||
float realHeight = outputHeight < outputWidth ? outputHeight : outputWidth;
|
||||
float realWidth = outputHeight > outputWidth ? outputHeight : outputWidth;
|
||||
if (drawAspectRatio > textureAspectRatio) {
|
||||
//太宽了
|
||||
float newWidth = (float)realHeight / drawAspectRatio;
|
||||
_textureScale.scaleFlip.y = newWidth / (float)realWidth;
|
||||
_textureScale.scaleFlip.x = 1.0;
|
||||
} else {
|
||||
//太高了
|
||||
float newHeight = (float)realWidth * drawAspectRatio;
|
||||
_textureScale.scaleFlip.x = (float)newHeight / realHeight;
|
||||
_textureScale.scaleFlip.y = 1.0;
|
||||
}
|
||||
}
|
||||
|
||||
_textureScale.scaleFlip.z = self.needFlip ? 1.0 : 0.0;
|
||||
|
||||
self.textureScaleBuffer = [self.device newBufferWithBytes:&_textureScale length:sizeof(_textureScale) options:MTLResourceStorageModeShared];
|
||||
|
||||
[colorConversionEncoder setRenderPipelineState:self.colorConvertPipelineState];
|
||||
[colorConversionEncoder setFragmentTexture:self.luminanceTextureTexture atIndex:0];
|
||||
[colorConversionEncoder setFragmentTexture:self.chrominanceTextureTexure atIndex:1];
|
||||
[colorConversionEncoder setFragmentBuffer:self.textureScaleBuffer offset:0 atIndex:0];
|
||||
[colorConversionEncoder setVertexBuffer:self.outputVertextBuffer offset:0 atIndex:0];
|
||||
[colorConversionEncoder setVertexBuffer:self.textureCoordinateBuffer offset:0 atIndex:1];
|
||||
[colorConversionEncoder setVertexBuffer:self.textureCoordinateBuffer offset:0 atIndex:2];
|
||||
|
||||
[colorConversionEncoder drawPrimitives:MTLPrimitiveTypeTriangleStrip vertexStart:0 vertexCount:4];
|
||||
[colorConversionEncoder endEncoding];
|
||||
|
||||
__weak QuarameraMTLCameraRender *weakSelf = self;
|
||||
|
||||
[commandBuffer addCompletedHandler:^(id<MTLCommandBuffer> commandBuffer) {
|
||||
if (weakSelf == nil) {
|
||||
return;
|
||||
}
|
||||
__strong QuarameraMTLCameraRender *strongSelf = weakSelf;
|
||||
if (!strongSelf.firstFrameRender) {
|
||||
NSLog(@"相机首帧渲染完毕");
|
||||
//这里埋点时机和Android统一,收到相机帧时发送,但实际上还是渲染完后发送比较合适
|
||||
if (strongSelf.renderDelegate) {
|
||||
[strongSelf.renderDelegate firstFrameRendered];
|
||||
}
|
||||
strongSelf.firstFrameRender = YES;
|
||||
}
|
||||
|
||||
if (completedHandler) {
|
||||
completedHandler(commandBuffer);
|
||||
}
|
||||
}];
|
||||
|
||||
[commandBuffer commit];
|
||||
|
||||
if (self.lightningMode) {
|
||||
self.lightningMode = NO;
|
||||
if (self.renderDelegate) {
|
||||
[self.renderDelegate lightningModelPrepared];
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#pragma mark
|
||||
#pragma mark - offscreen Render
|
||||
- (void)renderToShareTexture:(id<MTLTexture>)shareTexture
|
||||
commandBuffer:(id<MTLCommandBuffer>)commandBuffer
|
||||
frameTime:(NSTimeInterval)frameTime
|
||||
{
|
||||
if (!self.isInit) {
|
||||
return;
|
||||
}
|
||||
self.iTime = frameTime;
|
||||
if (self.offscreenCameraTexture.metalTexture && self.transformRenderPipeline) {
|
||||
commandBuffer.label = @"Camera Command Buffer";
|
||||
|
||||
id<MTLTexture> sourceTexture = self.offscreenCameraTexture.metalTexture;
|
||||
|
||||
[self renderToTexture:shareTexture from:sourceTexture
|
||||
commandBuffer:commandBuffer
|
||||
textureCoordinate:self.noRotationBuffer];
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)renderToTexture:(id<MTLTexture>)displayTexture
|
||||
from:(id<MTLTexture>)sourceTexture
|
||||
commandBuffer:(id<MTLCommandBuffer>)commandBuffer
|
||||
textureCoordinate:(id<MTLBuffer>)coordinateBuffer
|
||||
{
|
||||
if (displayTexture == nil || sourceTexture == nil) {
|
||||
return;
|
||||
}
|
||||
MTLRenderPassDescriptor *renderPass = [MTLRenderPassDescriptor renderPassDescriptor];
|
||||
|
||||
renderPass.colorAttachments[0].texture = displayTexture;
|
||||
renderPass.colorAttachments[0].loadAction = MTLLoadActionClear;
|
||||
renderPass.colorAttachments[0].clearColor = MTLClearColorMake(0.0, 0.0, 0.0, 0.0);
|
||||
renderPass.colorAttachments[0].storeAction = MTLStoreActionStore;
|
||||
|
||||
id<MTLRenderCommandEncoder> renderEncoder = [commandBuffer renderCommandEncoderWithDescriptor:renderPass];
|
||||
[renderEncoder setRenderPipelineState:self.transformRenderPipeline];
|
||||
[renderEncoder setFragmentTexture:sourceTexture atIndex:0];
|
||||
[renderEncoder setVertexBuffer:self.outputVertextBuffer offset:0 atIndex:0];
|
||||
[renderEncoder setVertexBuffer:coordinateBuffer offset:0 atIndex:1];
|
||||
|
||||
[renderEncoder drawPrimitives:MTLPrimitiveTypeTriangleStrip vertexStart:0 vertexCount:4];
|
||||
[renderEncoder endEncoding];
|
||||
renderEncoder = nil;
|
||||
renderPass = nil;
|
||||
}
|
||||
|
||||
- (void)render:(NSTimeInterval)frameTime
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
#pragma mark
|
||||
#pragma mark - Properties
|
||||
|
||||
- (void)resize:(CGSize)renderSize
|
||||
{
|
||||
_renderSize = renderSize;
|
||||
_aspect = self.renderSize.height / self.renderSize.width;
|
||||
|
||||
self.cameraOutputWidth = self.renderSize.width;
|
||||
self.cameraOutputHeight = self.renderSize.height;
|
||||
}
|
||||
|
||||
- (void)updateCameraTexture:(QuarameraShareTexture *)cameraTexture
|
||||
{
|
||||
_offscreenCameraTexture = nil;
|
||||
_offscreenCameraTexture = cameraTexture;
|
||||
}
|
||||
|
||||
- (CVPixelBufferRef)renderTarget
|
||||
{
|
||||
return self.offscreenCameraTexture.renderTarget;
|
||||
}
|
||||
@end
|
84
mediapipe/render/ios/Camera/QuarameraMTLCameraRenderView.h
Normal file
84
mediapipe/render/ios/Camera/QuarameraMTLCameraRenderView.h
Normal file
|
@ -0,0 +1,84 @@
|
|||
//
|
||||
// WANativeMTLCameraPreviewView.h
|
||||
// WebAR-iOS
|
||||
// 基于Metal的相机预览视图,闪电拍照定制优化,具备相机预览的基础功能
|
||||
// Created by wangrenzhu on 2020/11/16.
|
||||
// Copyright © 2020 Taobao lnc. All rights reserved.
|
||||
//
|
||||
|
||||
#import <MetalKit/MetalKit.h>
|
||||
#import <AVFoundation/AVFoundation.h>
|
||||
#import <QuarameraFramework/QuarameraCameraRender.h>
|
||||
#import <QuarameraFramework/QuarameraMTLCameraRender.h>
|
||||
#import <QuarameraFramework/QuarameraShareTexture.h>
|
||||
|
||||
@protocol QuarameraMTLCameraRenderViewDelegate
|
||||
|
||||
- (void)draw:(NSTimeInterval)frameTime;
|
||||
|
||||
|
||||
/// 开放离屏相机纹理 用于外部分流
|
||||
/// @param texture texture description
|
||||
/// @param onScreenTexture 上屏纹理
|
||||
/// @param frameTime 帧时间
|
||||
- (IOSurfaceID)bgraCameraTextureReady:(QuarameraShareTexture *)texture
|
||||
onScreenTexture:(QuarameraShareTexture *)onScreenTexture
|
||||
frameTime:(NSTimeInterval)frameTime;
|
||||
|
||||
@optional
|
||||
|
||||
/// 渲染到TargetTexture上可以上屏,如果是GL则需要调用GLFlush来同步
|
||||
/// @param frameTime frameTime description
|
||||
/// @param targetTexture targetTexture description
|
||||
/// @param buffer MTL的CommandBuffer
|
||||
- (void)externalRender:(NSTimeInterval)frameTime
|
||||
targetTexture:(QuarameraShareTexture *)targetTexture
|
||||
commandBuffer:(id<MTLCommandBuffer>)buffer;
|
||||
|
||||
|
||||
/// YUV 相机纹理
|
||||
/// @param yTexture y纹理
|
||||
/// @param uvTexture yv纹理
|
||||
- (void)yuvTextureReady:(QuarameraShareTexture *)yTexture uvTexture:(QuarameraShareTexture *)uvTexture;
|
||||
|
||||
@end
|
||||
|
||||
@interface QuarameraMTLCameraRenderView : MTKView
|
||||
|
||||
/// MetalRender
|
||||
@property (nonatomic, strong, readonly) QuarameraMTLCameraRender *mtlRender;
|
||||
|
||||
@property (nonatomic, weak) id<QuarameraMTLCameraRenderViewDelegate> cameraDelegate;
|
||||
|
||||
@property (nonatomic) dispatch_queue_t displayRenderQueue;
|
||||
|
||||
/// 原始相机纹理 可以快速读取
|
||||
@property (nonatomic, readonly, strong) QuarameraShareTexture *cameraTexture;
|
||||
@property (nonatomic, readonly, strong) QuarameraShareTexture *shareTexture;
|
||||
|
||||
/// 不带后处理的相机渲染的原始纹理
|
||||
@property (nonatomic, readonly) CVPixelBufferRef renderTarget;
|
||||
|
||||
/// 是否镜像渲染 默认为NO
|
||||
@property (nonatomic) BOOL needFlip;
|
||||
|
||||
/// 恢复/开始渲染
|
||||
- (void)resume;
|
||||
|
||||
/// 暂停/挂起渲染
|
||||
- (void)suspend;
|
||||
|
||||
/// 处理相机采集流
|
||||
/// @param sampleBuffer 相机采集流
|
||||
- (void)cameraSampleBufferArrive:(CMSampleBufferRef)sampleBuffer;
|
||||
|
||||
- (void)addRender:(QuarameraCameraRender *)render;
|
||||
|
||||
|
||||
/// 是否开启Quaramera
|
||||
/// @param frame frame description
|
||||
- (instancetype)initWithFrame:(CGRect)frame;
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame shareContext:(EAGLContext *)context;
|
||||
|
||||
@end
|
347
mediapipe/render/ios/Camera/QuarameraMTLCameraRenderView.mm
Normal file
347
mediapipe/render/ios/Camera/QuarameraMTLCameraRenderView.mm
Normal file
|
@ -0,0 +1,347 @@
|
|||
//
|
||||
// WANativeMTLRenderView.m
|
||||
// WebAR-iOS
|
||||
//
|
||||
// Created by wangrenzhu on 2020/11/16.
|
||||
// Copyright © 2020 Taobao lnc. All rights reserved.
|
||||
//
|
||||
|
||||
#import "QuarameraMTLCameraRenderView.h"
|
||||
#import "QuarameraShareTexture.h"
|
||||
#import "QuarameraMTLCameraRender.h"
|
||||
#import <OpenGLES/EAGL.h>
|
||||
#import <OpenGLES/ES3/gl.h>
|
||||
|
||||
static const NSUInteger MaxFramesInFlight = 3;
|
||||
static size_t const kQuarameraDynamicTextureByteAlignment = 16;
|
||||
|
||||
NS_INLINE size_t QAAlignSize(size_t size)
|
||||
{
|
||||
return ceil(size / (double)kQuarameraDynamicTextureByteAlignment) * kQuarameraDynamicTextureByteAlignment;
|
||||
}
|
||||
|
||||
@interface QuarameraMTLCameraRenderView()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@property (nonatomic, strong) QuarameraMTLCameraRender *mtlRender;
|
||||
|
||||
@property (nonatomic) NSTimeInterval frameTime;
|
||||
@property (nonatomic, strong) QuarameraShareTexture *shareTexture;
|
||||
@property (nonatomic, strong) QuarameraShareTexture *cameraTexture;
|
||||
@property (nonatomic) id<MTLTexture> ioSurfaceTexture;
|
||||
@property (nonatomic) IOSurfaceID lastIOSurfaceID;
|
||||
@property (nonatomic, strong) EAGLContext *openGLContext;
|
||||
@property (nonatomic) dispatch_semaphore_t displayFrameRenderingSemaphore;
|
||||
|
||||
@property (nonatomic) dispatch_semaphore_t cameraFrameRenderingSemaphore;
|
||||
|
||||
@property (nonatomic, assign) BOOL useRenderMode;
|
||||
|
||||
@property (nonatomic, strong) NSMutableArray<QuarameraCameraRender *> *renders;
|
||||
@property (nonatomic) CGSize lastFrameSize;
|
||||
@end
|
||||
|
||||
@implementation QuarameraMTLCameraRenderView
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
_openGLContext = nil;
|
||||
_mtlRender = nil;
|
||||
|
||||
_shareTexture = nil;
|
||||
_cameraTexture = nil;
|
||||
|
||||
}
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame
|
||||
{
|
||||
self = [super initWithFrame:frame];
|
||||
if (self) {
|
||||
_renders = [NSMutableArray arrayWithCapacity:10];
|
||||
_openGLContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES3];
|
||||
[self initRender:frame];
|
||||
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame shareContext:(EAGLContext *)context
|
||||
{
|
||||
self = [super initWithFrame:frame];
|
||||
if (self) {
|
||||
_renders = [NSMutableArray arrayWithCapacity:10];
|
||||
_openGLContext = context;
|
||||
[self initRender:frame];
|
||||
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
- (void)initRender:(const CGRect &)frame
|
||||
{
|
||||
self.enableSetNeedsDisplay = NO;
|
||||
self.autoResizeDrawable = YES;
|
||||
self.colorPixelFormat = MTLPixelFormatBGRA8Unorm;
|
||||
self.device = MTLCreateSystemDefaultDevice();
|
||||
self.lastFrameSize = frame.size;
|
||||
|
||||
size_t alighWidth = QAAlignSize(frame.size.width * self.contentScaleFactor);
|
||||
|
||||
CGSize textureSize = CGSizeMake(float(alighWidth),
|
||||
frame.size.height * self.contentScaleFactor);
|
||||
|
||||
|
||||
_shareTexture = [[QuarameraShareTexture alloc] initWithMetalDevice:self.device
|
||||
openGLContext:self.openGLContext
|
||||
metalPixelFormat:self.colorPixelFormat
|
||||
size:textureSize];
|
||||
|
||||
_cameraTexture = [[QuarameraShareTexture alloc] initWithMetalDevice:self.device
|
||||
openGLContext:self.openGLContext
|
||||
metalPixelFormat:self.colorPixelFormat
|
||||
size:textureSize];
|
||||
|
||||
_mtlRender = [[QuarameraMTLCameraRender alloc] initWithRenderSize:textureSize
|
||||
device:self.device
|
||||
cameraTexture:self.cameraTexture
|
||||
contentScaleFactor:self.contentScaleFactor];
|
||||
|
||||
__unused BOOL isSetCurrent = [EAGLContext setCurrentContext:self.openGLContext];
|
||||
NSAssert(isSetCurrent, @"上下文设置失败");
|
||||
|
||||
dispatch_queue_attr_t interactive =
|
||||
dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL,
|
||||
QOS_CLASS_USER_INTERACTIVE, 0);
|
||||
self.displayFrameRenderingSemaphore = dispatch_semaphore_create(MaxFramesInFlight);
|
||||
self.displayRenderQueue = dispatch_queue_create("quaramera.ios.displayRenderQueue",
|
||||
interactive);
|
||||
|
||||
self.cameraFrameRenderingSemaphore = dispatch_semaphore_create(1);
|
||||
}
|
||||
|
||||
- (void)setNeedFlip:(BOOL)needFlip
|
||||
{
|
||||
[self.mtlRender setNeedFlip:needFlip];
|
||||
}
|
||||
|
||||
- (void)layoutSubviews
|
||||
{
|
||||
[super layoutSubviews];
|
||||
if (!CGSizeEqualToSize(self.lastFrameSize, self.frame.size)) {
|
||||
CGSize newRenderSize = CGSizeMake(self.frame.size.width * self.contentScaleFactor,
|
||||
self.frame.size.height * self.contentScaleFactor);
|
||||
self.lastFrameSize = self.frame.size;
|
||||
self.paused = YES;
|
||||
dispatch_async(self.displayRenderQueue, ^{
|
||||
|
||||
size_t alighWidth = QAAlignSize(newRenderSize.width);
|
||||
|
||||
CGSize textureSize = CGSizeMake(float(alighWidth),
|
||||
newRenderSize.height);
|
||||
|
||||
[self.mtlRender resize:textureSize];
|
||||
|
||||
[self.renders enumerateObjectsUsingBlock:^(QuarameraCameraRender * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
|
||||
[obj resize:textureSize];
|
||||
}];
|
||||
self.paused = NO;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark
|
||||
#pragma mark Private Method
|
||||
|
||||
- (void)willMoveToSuperview:(UIView *)newSuperview
|
||||
{
|
||||
[self setPaused:NO];
|
||||
}
|
||||
|
||||
- (void)resume
|
||||
{
|
||||
[self setPaused:NO];
|
||||
}
|
||||
|
||||
- (void)suspend
|
||||
{
|
||||
[self setPaused:YES];
|
||||
}
|
||||
|
||||
- (void)draw
|
||||
{
|
||||
|
||||
#if !TARGET_OS_SIMULATOR
|
||||
|
||||
id<CAMetalDrawable> drawable = [((CAMetalLayer *)self.layer) nextDrawable];
|
||||
|
||||
__weak QuarameraMTLCameraRenderView *weakSelf = self;
|
||||
|
||||
// dispatch_semaphore_t block_camera_sema = self.cameraFrameRenderingSemaphore;
|
||||
dispatch_semaphore_t block_display_sema = self.displayFrameRenderingSemaphore;
|
||||
|
||||
void (^renderCompleted)(id<MTLCommandBuffer> buffer) = ^(id<MTLCommandBuffer> buffer)
|
||||
{
|
||||
// dispatch_semaphore_signal(block_camera_sema);
|
||||
dispatch_semaphore_signal(block_display_sema);
|
||||
};
|
||||
|
||||
NSMutableArray<QuarameraCameraRender *> *renders = [self.renders copy];
|
||||
|
||||
dispatch_async(self.displayRenderQueue, ^{
|
||||
if (weakSelf == nil) {
|
||||
return;
|
||||
}
|
||||
|
||||
__strong QuarameraMTLCameraRenderView *strongSelf = weakSelf;
|
||||
|
||||
strongSelf.frameTime += (1.0 / strongSelf.preferredFramesPerSecond) * 1000.0;
|
||||
if (dispatch_semaphore_wait(block_display_sema, DISPATCH_TIME_NOW) != 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
id<MTLCommandBuffer> commandBuffer = nil;
|
||||
|
||||
commandBuffer = [strongSelf.mtlRender.commandQueue commandBuffer];
|
||||
[strongSelf.mtlRender renderToShareTexture:strongSelf.shareTexture.metalTexture
|
||||
commandBuffer:commandBuffer
|
||||
frameTime:strongSelf.frameTime];
|
||||
[commandBuffer commit];
|
||||
|
||||
commandBuffer = [strongSelf.mtlRender.commandQueue commandBuffer];
|
||||
// 然后将渲染结果交给外部引擎 作为输入
|
||||
if (renders.count > 0) {
|
||||
//这个版本的Quarkit用的OpenGL渲染 所以需要glFlush
|
||||
//quarkitRendre把相机渲染到shareTexture上
|
||||
|
||||
glFlush();
|
||||
[renders enumerateObjectsUsingBlock:^(QuarameraCameraRender * _Nonnull obj,
|
||||
NSUInteger idx, BOOL * _Nonnull stop) {
|
||||
if (obj.enable) {
|
||||
[obj render:weakSelf.frameTime];
|
||||
}
|
||||
}];
|
||||
|
||||
|
||||
}
|
||||
|
||||
if (strongSelf.cameraDelegate && !strongSelf.isPaused) {
|
||||
if (@available(iOS 11.0, *)) {
|
||||
glFlush();
|
||||
[strongSelf.cameraDelegate draw:strongSelf.frameTime];
|
||||
|
||||
[strongSelf.cameraDelegate externalRender:strongSelf.frameTime
|
||||
targetTexture:strongSelf.shareTexture
|
||||
commandBuffer:commandBuffer];
|
||||
[EAGLContext setCurrentContext:self.openGLContext];
|
||||
IOSurfaceID surfaceId = [strongSelf.cameraDelegate bgraCameraTextureReady:strongSelf.cameraTexture
|
||||
onScreenTexture:strongSelf.shareTexture
|
||||
frameTime:strongSelf.frameTime * 1000];
|
||||
if (surfaceId != -1) {
|
||||
//这里渲染surfaceId
|
||||
IOSurfaceRef ioSurface = IOSurfaceLookup(surfaceId);
|
||||
IOSurfaceLock(ioSurface, kIOSurfaceLockReadOnly, nil);
|
||||
if (ioSurface) {
|
||||
if (self.lastIOSurfaceID != surfaceId || self.ioSurfaceTexture == nil) {
|
||||
id<MTLTexture> texture;
|
||||
MTLTextureDescriptor *textureDescriptor = [MTLTextureDescriptor
|
||||
texture2DDescriptorWithPixelFormat:MTLPixelFormatBGRA8Unorm
|
||||
width:strongSelf.cameraTexture.size.width
|
||||
height:strongSelf.cameraTexture.size.height
|
||||
mipmapped:NO];
|
||||
textureDescriptor.storageMode = MTLStorageModeShared;
|
||||
textureDescriptor.usage = MTLTextureUsageRenderTarget | MTLTextureUsageShaderRead;
|
||||
texture = [self.device newTextureWithDescriptor:textureDescriptor iosurface:ioSurface plane:0];
|
||||
self.ioSurfaceTexture = texture;
|
||||
textureDescriptor = nil;
|
||||
}
|
||||
|
||||
IOSurfaceUnlock(ioSurface, kIOSurfaceLockReadOnly, nil);
|
||||
CFRelease(ioSurface);
|
||||
|
||||
self.lastIOSurfaceID = surfaceId;
|
||||
if (self.ioSurfaceTexture) {
|
||||
[strongSelf.mtlRender renderToTexture:drawable.texture
|
||||
from:self.ioSurfaceTexture
|
||||
commandBuffer:commandBuffer
|
||||
textureCoordinate:strongSelf.mtlRender.noRotationBuffer];
|
||||
if (drawable) {
|
||||
[commandBuffer presentDrawable:drawable];
|
||||
[commandBuffer addCompletedHandler:renderCompleted];
|
||||
[commandBuffer commit];
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
glFlush();
|
||||
//将混合渲染结果 渲染到屏幕
|
||||
[strongSelf.mtlRender renderToTexture:drawable.texture
|
||||
from:strongSelf.shareTexture.metalTexture
|
||||
commandBuffer:commandBuffer
|
||||
textureCoordinate:strongSelf.mtlRender.noRotationBuffer];
|
||||
if (drawable) {
|
||||
[commandBuffer presentDrawable:drawable];
|
||||
[commandBuffer addCompletedHandler:renderCompleted];
|
||||
[commandBuffer commit];
|
||||
}
|
||||
});
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
- (void)cameraSampleBufferArrive:(CMSampleBufferRef)sampleBuffer
|
||||
{
|
||||
if (self.isPaused) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (dispatch_semaphore_wait(self.cameraFrameRenderingSemaphore, DISPATCH_TIME_NOW) != 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
dispatch_semaphore_t block_camera_sema = self.cameraFrameRenderingSemaphore;
|
||||
__strong QuarameraMTLCameraRenderView *weakSelf = self;
|
||||
void (^renderCompleted)(id<MTLCommandBuffer> buffer) = ^(id<MTLCommandBuffer> buffer)
|
||||
{
|
||||
dispatch_semaphore_signal(block_camera_sema);
|
||||
};
|
||||
|
||||
CFRetain(sampleBuffer);
|
||||
dispatch_async(self.displayRenderQueue, ^{
|
||||
if (weakSelf == nil) {
|
||||
CFRelease(sampleBuffer);
|
||||
return;
|
||||
}
|
||||
__strong QuarameraMTLCameraRenderView *strongSelf = weakSelf;
|
||||
CVPixelBufferRef pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);
|
||||
[strongSelf.mtlRender renderToCameraTextureWithPixelBuffer:pixelBuffer completedHandler:renderCompleted];
|
||||
|
||||
CFRelease(sampleBuffer);
|
||||
});
|
||||
}
|
||||
|
||||
- (CVPixelBufferRef)renderTarget
|
||||
{
|
||||
return self.cameraTexture.renderTarget;
|
||||
}
|
||||
|
||||
- (void)addRender:(QuarameraCameraRender *)render
|
||||
{
|
||||
NSAssert([NSThread isMainThread], @"call on main Thread");
|
||||
|
||||
[render setupWithDevice:self.device shareTexture:self.shareTexture useRenderMode:self.useRenderMode];
|
||||
|
||||
[self.renders addObject:render];
|
||||
}
|
||||
@end
|
46
mediapipe/render/ios/Camera/QuarameraShareTexture.h
Normal file
46
mediapipe/render/ios/Camera/QuarameraShareTexture.h
Normal file
|
@ -0,0 +1,46 @@
|
|||
//
|
||||
// QuarameraShareTexture.h
|
||||
// QuameraDemo
|
||||
//
|
||||
// Created by wangrenzhu on 2021/1/21.
|
||||
// Copyright © 2021 alibaba. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <UIKit/UIKit.h>
|
||||
#import <Metal/Metal.h>
|
||||
#import <GLKit/GLKTextureLoader.h>
|
||||
|
||||
typedef struct {
|
||||
int cvPixelFormat;
|
||||
MTLPixelFormat mtlFormat;
|
||||
GLuint glInternalFormat;
|
||||
GLuint glFormat;
|
||||
GLuint glType;
|
||||
} QuarameraTextureFormatInfo;
|
||||
|
||||
@interface QuarameraShareTexture : NSObject
|
||||
|
||||
- (nonnull instancetype)initWithMetalDevice:(nonnull id<MTLDevice>)mtlDevice
|
||||
openGLContext:(nonnull EAGLContext*)glContext
|
||||
metalPixelFormat:(MTLPixelFormat)mtlPixelFormat
|
||||
size:(CGSize)size;
|
||||
|
||||
- (nonnull instancetype)initWithMetalDevice:(nonnull id<MTLDevice>)mtlDevice
|
||||
openGLContext:(nonnull EAGLContext*)glContext
|
||||
metalPixelFormat:(MTLPixelFormat)mtlPixelFormat
|
||||
sourceImage:(nonnull UIImage *)sourceImage;
|
||||
|
||||
@property (readonly, nonnull, nonatomic) CVPixelBufferRef renderTarget;
|
||||
@property (readonly, nonnull, nonatomic) id<MTLDevice> metalDevice;
|
||||
@property (readonly, nonnull, nonatomic) id<MTLTexture> metalTexture;
|
||||
|
||||
@property (readonly, nonnull, nonatomic) EAGLContext *openGLContext;
|
||||
@property (readonly, nonatomic) GLuint openGLTexture;
|
||||
|
||||
@property (readonly, nonatomic) CGSize size;
|
||||
@property (strong, nullable, nonatomic) NSString *name;
|
||||
@property (readonly, nonnull, nonatomic) QuarameraTextureFormatInfo *formatInfo;
|
||||
@property (readonly, nonatomic) IOSurfaceID surfaceID;
|
||||
|
||||
@end
|
381
mediapipe/render/ios/Camera/QuarameraShareTexture.m
Normal file
381
mediapipe/render/ios/Camera/QuarameraShareTexture.m
Normal file
|
@ -0,0 +1,381 @@
|
|||
//
|
||||
// QuarameraShareTexture.m
|
||||
// QuameraDemo
|
||||
//
|
||||
// Created by wangrenzhu on 2021/1/21.
|
||||
// Copyright © 2021 alibaba. All rights reserved.
|
||||
//
|
||||
|
||||
#import "QuarameraShareTexture.h"
|
||||
#import <OpenGLES/ES2/gl.h>
|
||||
#import <OpenGLES/ES2/glext.h>
|
||||
#import <MetalKit/MetalKit.h>
|
||||
#import <CoreVideo/CoreVideo.h>
|
||||
#import <Metal/Metal.h>
|
||||
#if !TARGET_OS_SIMULATOR
|
||||
#import <OpenGLES/EAGLIOSurface.h>
|
||||
#endif
|
||||
|
||||
#define GL_UNSIGNED_INT_8_8_8_8_REV 0x8367
|
||||
|
||||
__unused static QuarameraTextureFormatInfo formatTable[] =
|
||||
{
|
||||
// Core Video Pixel Format, Metal Pixel Format, GL internalformat, GL format, GL type
|
||||
{ kCVPixelFormatType_32BGRA, MTLPixelFormatBGRA8Unorm, GL_RGBA, GL_BGRA_EXT, GL_UNSIGNED_INT_8_8_8_8_REV },
|
||||
};
|
||||
|
||||
static const float noRotationTextureCoordinates[] = {
|
||||
0.0f, 0.0f,
|
||||
1.0f, 0.0f,
|
||||
0.0f, 1.0f,
|
||||
1.0f, 1.0f,
|
||||
};
|
||||
|
||||
static const float standardImageVertices[] = {
|
||||
-1.0, 1.0,
|
||||
1.0, 1.0,
|
||||
-1.0, -1.0,
|
||||
1.0, -1.0
|
||||
};
|
||||
|
||||
static const NSUInteger interopFormats = sizeof(formatTable) / sizeof(QuarameraTextureFormatInfo);
|
||||
|
||||
QuarameraTextureFormatInfo* textureFormatInfoFromMetalPixelFormat(MTLPixelFormat pixelFormat)
|
||||
{
|
||||
for(int i = 0; i < interopFormats; i++) {
|
||||
if(pixelFormat == formatTable[i].mtlFormat) {
|
||||
return &formatTable[i];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@interface QuarameraShareTexture() {
|
||||
|
||||
}
|
||||
|
||||
@property (nonatomic) id<MTLLibrary> library;
|
||||
@property (nonatomic) id<MTLBuffer> outputVertextBuffer;
|
||||
@property (nonatomic) id<MTLRenderPipelineState> renderPipeline;
|
||||
@property (nonatomic) id<MTLBuffer> noRotationBuffer;
|
||||
|
||||
@end
|
||||
|
||||
@implementation QuarameraShareTexture
|
||||
{
|
||||
QuarameraTextureFormatInfo *_formatInfo;
|
||||
CVPixelBufferRef _pixelBuffer;
|
||||
CVMetalTextureRef _mtlTexture;
|
||||
|
||||
CVOpenGLESTextureRef _glTexture;
|
||||
CVOpenGLESTextureCacheRef _glTextureCache;
|
||||
CVMetalTextureCacheRef _mtlTextureCache;
|
||||
IOSurfaceID _ioSurfaceId;
|
||||
IOSurfaceRef renderIOSurface;
|
||||
CGSize _size;
|
||||
}
|
||||
@synthesize surfaceID = _ioSurfaceId;
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
if (_mtlTexture) {
|
||||
CFRelease(_mtlTexture);
|
||||
}
|
||||
|
||||
if (_glTexture) {
|
||||
CFRelease(_glTexture);
|
||||
}
|
||||
|
||||
if (_glTextureCache) {
|
||||
CFRelease(_glTextureCache);
|
||||
}
|
||||
|
||||
if (_mtlTextureCache) {
|
||||
CFRelease(_mtlTextureCache);
|
||||
}
|
||||
|
||||
if (_pixelBuffer) {
|
||||
CVPixelBufferRelease(_pixelBuffer);
|
||||
_pixelBuffer = nil;
|
||||
}
|
||||
|
||||
#if !TARGET_OS_SIMULATOR
|
||||
if (renderIOSurface) {
|
||||
CFRelease(renderIOSurface);
|
||||
}
|
||||
#endif
|
||||
|
||||
_formatInfo = nil;
|
||||
|
||||
_openGLContext = nil;
|
||||
_metalDevice = nil;
|
||||
_outputVertextBuffer = nil;
|
||||
}
|
||||
|
||||
- (nonnull instancetype)initWithMetalDevice:(id<MTLDevice>)mtlDevice
|
||||
openGLContext:(EAGLContext *)glContext
|
||||
metalPixelFormat:(MTLPixelFormat)mtlPixelFormat
|
||||
sourceImage:(UIImage *)sourceImage
|
||||
{
|
||||
self = [self initWithMetalDevice:mtlDevice openGLContext:glContext metalPixelFormat:mtlPixelFormat size:sourceImage.size];
|
||||
if (self) {
|
||||
[self renderUIImageToShareTexture:sourceImage];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
- (nonnull instancetype)initWithMetalDevice:(nonnull id <MTLDevice>) metalevice
|
||||
openGLContext:(nonnull EAGLContext *) glContext
|
||||
metalPixelFormat:(MTLPixelFormat)mtlPixelFormat
|
||||
size:(CGSize)size
|
||||
{
|
||||
self = [super init];
|
||||
if(self) {
|
||||
_formatInfo =
|
||||
textureFormatInfoFromMetalPixelFormat(mtlPixelFormat);
|
||||
|
||||
NSAssert(_formatInfo, @"不支持这个格式");
|
||||
|
||||
_size = size;
|
||||
_metalDevice = metalevice;
|
||||
_openGLContext = glContext;
|
||||
NSDictionary* cvBufferProperties = @{
|
||||
(__bridge NSString*)kCVPixelBufferIOSurfacePropertiesKey : @{},
|
||||
(__bridge NSString*)kCVPixelBufferOpenGLCompatibilityKey : @YES,
|
||||
(__bridge NSString*)kCVPixelBufferIOSurfaceOpenGLESTextureCompatibilityKey: @YES,
|
||||
(__bridge NSString*)kCVPixelBufferMetalCompatibilityKey : @YES,
|
||||
};
|
||||
|
||||
#if !TARGET_OS_SIMULATOR
|
||||
if (@available(iOS 11.0, *)) {
|
||||
int _width = size.width;
|
||||
int _height = size.height;
|
||||
unsigned bytesPerElement = 4;
|
||||
|
||||
|
||||
size_t bytesPerRow = IOSurfaceAlignProperty(kIOSurfaceBytesPerRow, _width * bytesPerElement);
|
||||
size_t totalBytes = IOSurfaceAlignProperty(kIOSurfaceAllocSize, _height * bytesPerRow);
|
||||
NSDictionary *dict = @{
|
||||
(id)kIOSurfaceWidth : @(_width),
|
||||
(id)kIOSurfaceHeight : @(_height),
|
||||
(id)kIOSurfacePixelFormat : @(kCVPixelFormatType_32BGRA),
|
||||
(id)kIOSurfaceBytesPerElement : @(bytesPerElement),
|
||||
(id)kIOSurfaceBytesPerRow : @(bytesPerRow),
|
||||
(id)kIOSurfaceAllocSize : @(totalBytes),
|
||||
(id)kIOSurfaceIsGlobal: @YES
|
||||
};
|
||||
|
||||
renderIOSurface = IOSurfaceCreate((CFDictionaryRef)dict);
|
||||
_ioSurfaceId = IOSurfaceGetID(renderIOSurface);
|
||||
CVPixelBufferCreateWithIOSurface(kCFAllocatorDefault, renderIOSurface,
|
||||
(__bridge CFDictionaryRef)cvBufferProperties, &_pixelBuffer);
|
||||
|
||||
MTLTextureDescriptor *textureDescriptor = [MTLTextureDescriptor
|
||||
texture2DDescriptorWithPixelFormat:MTLPixelFormatBGRA8Unorm
|
||||
width:_width
|
||||
height:_height
|
||||
mipmapped:NO];
|
||||
textureDescriptor.storageMode = MTLStorageModeShared;
|
||||
textureDescriptor.usage = MTLTextureUsageRenderTarget | MTLTextureUsageShaderRead;
|
||||
_metalTexture = [_metalDevice newTextureWithDescriptor:textureDescriptor
|
||||
iosurface:renderIOSurface
|
||||
plane:0];
|
||||
textureDescriptor = nil;
|
||||
[EAGLContext setCurrentContext:_openGLContext];
|
||||
|
||||
glGenTextures(1, &_openGLTexture);
|
||||
glBindTexture(GL_TEXTURE_2D, _openGLTexture);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
|
||||
GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
|
||||
GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, _openGLTexture);
|
||||
#if !TARGET_OS_SIMULATOR
|
||||
BOOL rs = [_openGLContext texImageIOSurface:renderIOSurface
|
||||
target:GL_TEXTURE_2D
|
||||
internalFormat:GL_RGBA
|
||||
width:_width height:_height
|
||||
format:GL_BGRA_EXT
|
||||
type:GL_UNSIGNED_BYTE plane:0];
|
||||
NSAssert(rs, @"IOSurface binding 失败");
|
||||
#endif
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
|
||||
} else {
|
||||
#endif
|
||||
|
||||
__unused CVReturn cvret = CVPixelBufferCreate(kCFAllocatorDefault,
|
||||
size.width,
|
||||
size.height,
|
||||
self.formatInfo->cvPixelFormat,
|
||||
(__bridge CFDictionaryRef)cvBufferProperties,
|
||||
&_pixelBuffer);
|
||||
NSAssert(cvret == kCVReturnSuccess, @"Failed to create CVPixelBuffer");
|
||||
|
||||
[self createGLTexture];
|
||||
[self createMetalTexture];
|
||||
#if !TARGET_OS_SIMULATOR
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
return self;
|
||||
|
||||
}
|
||||
|
||||
|
||||
- (void)createGLTexture
|
||||
{
|
||||
__unused CVReturn cvret;
|
||||
cvret = CVOpenGLESTextureCacheCreate(kCFAllocatorDefault,
|
||||
nil,
|
||||
_openGLContext,
|
||||
nil,
|
||||
&_glTextureCache);
|
||||
|
||||
|
||||
cvret = CVOpenGLESTextureCacheCreateTextureFromImage(kCFAllocatorDefault,
|
||||
_glTextureCache,
|
||||
_pixelBuffer,
|
||||
nil,
|
||||
GL_TEXTURE_2D,
|
||||
_formatInfo->glInternalFormat,
|
||||
_size.width, _size.height,
|
||||
_formatInfo->glFormat,
|
||||
_formatInfo->glType,
|
||||
0,
|
||||
&_glTexture);
|
||||
|
||||
|
||||
NSAssert(cvret == kCVReturnSuccess, @"OpenGL 纹理创建失败");
|
||||
|
||||
_openGLTexture = CVOpenGLESTextureGetName(_glTexture);
|
||||
}
|
||||
|
||||
|
||||
|
||||
- (void)createMetalTexture
|
||||
{
|
||||
__unused CVReturn cvret;
|
||||
|
||||
cvret = CVMetalTextureCacheCreate(
|
||||
kCFAllocatorDefault,
|
||||
nil,
|
||||
_metalDevice,
|
||||
nil,
|
||||
&_mtlTextureCache);
|
||||
|
||||
cvret = CVMetalTextureCacheCreateTextureFromImage(
|
||||
kCFAllocatorDefault,
|
||||
_mtlTextureCache,
|
||||
_pixelBuffer, nil,
|
||||
_formatInfo->mtlFormat,
|
||||
_size.width, _size.height,
|
||||
0,
|
||||
&_mtlTexture);
|
||||
|
||||
NSAssert(cvret == kCVReturnSuccess, @"Metal 纹理创建失败");
|
||||
|
||||
_metalTexture = CVMetalTextureGetTexture(_mtlTexture);
|
||||
|
||||
}
|
||||
|
||||
- (CVPixelBufferRef)renderTarget
|
||||
{
|
||||
return _pixelBuffer;
|
||||
}
|
||||
|
||||
- (QuarameraTextureFormatInfo *)formatInfo
|
||||
{
|
||||
return (QuarameraTextureFormatInfo *)_formatInfo;
|
||||
}
|
||||
|
||||
- (id<MTLTexture>)loadTextureFromImage:(UIImage *)image
|
||||
{
|
||||
MTKTextureLoader *loader =[[MTKTextureLoader alloc] initWithDevice:self.metalDevice];
|
||||
NSError *error;
|
||||
id<MTLTexture> sourceTexture = [loader newTextureWithCGImage:image.CGImage options:@{
|
||||
MTKTextureLoaderOptionTextureUsage : @(MTLTextureUsageShaderRead),
|
||||
MTKTextureLoaderOptionTextureStorageMode : @(MTLStorageModeShared),
|
||||
} error:&error];
|
||||
|
||||
|
||||
if (error) {
|
||||
return nil;
|
||||
} else {
|
||||
return sourceTexture;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)renderUIImageToShareTexture:(UIImage *)sourceImage
|
||||
{
|
||||
id<MTLTexture> sourceTexture = [self loadTextureFromImage:sourceImage];
|
||||
if (sourceTexture) {
|
||||
|
||||
NSError *error;
|
||||
NSBundle *bundle = [NSBundle mainBundle];
|
||||
NSURL *shaderURL = [bundle URLForResource:@"QuarameraFramework" withExtension:@"metallib"];
|
||||
if (@available(iOS 11.0, *)) {
|
||||
if (shaderURL) {
|
||||
self.library = [self.metalDevice newLibraryWithURL:shaderURL error:&error];
|
||||
}
|
||||
} else {
|
||||
NSString *lib = [[NSBundle mainBundle] pathForResource:@"QuarameraFramework" ofType:@"metallib"];
|
||||
if (lib) {
|
||||
_library = [_metalDevice newLibraryWithFile:lib error:nil];
|
||||
}
|
||||
}
|
||||
|
||||
self.noRotationBuffer = [self.metalDevice newBufferWithBytes:noRotationTextureCoordinates
|
||||
length:sizeof(noRotationTextureCoordinates)
|
||||
options:MTLResourceStorageModeShared];
|
||||
|
||||
self.outputVertextBuffer = [self.metalDevice newBufferWithBytes:standardImageVertices
|
||||
length:sizeof(standardImageVertices)
|
||||
options:MTLResourceStorageModeShared];
|
||||
|
||||
id<MTLFunction> vertexFunc = [self.library newFunctionWithName:@"oneInputVertex"];
|
||||
id<MTLFunction> fragFunc = [self.library newFunctionWithName:@"passthroughFragment"];
|
||||
|
||||
id<MTLCommandQueue> commandQueue = [self.metalDevice newCommandQueue];
|
||||
id<MTLCommandBuffer> commandBuffer = [commandQueue commandBuffer];
|
||||
|
||||
MTLRenderPipelineDescriptor *renderDesc = [MTLRenderPipelineDescriptor new];
|
||||
renderDesc.colorAttachments[0].pixelFormat = MTLPixelFormatBGRA8Unorm;
|
||||
renderDesc.rasterSampleCount = 1;
|
||||
renderDesc.vertexFunction = vertexFunc;
|
||||
renderDesc.fragmentFunction = fragFunc;
|
||||
|
||||
self.renderPipeline = [self.metalDevice newRenderPipelineStateWithDescriptor:renderDesc error:&error];
|
||||
|
||||
MTLRenderPassDescriptor *renderPass = [MTLRenderPassDescriptor renderPassDescriptor];
|
||||
|
||||
renderPass.colorAttachments[0].texture = self.metalTexture;
|
||||
renderPass.colorAttachments[0].loadAction = MTLLoadActionClear;
|
||||
renderPass.colorAttachments[0].clearColor = MTLClearColorMake(0.0, 0.0, 0.0, 0.0);
|
||||
renderPass.colorAttachments[0].storeAction = MTLStoreActionStore;
|
||||
|
||||
id<MTLRenderCommandEncoder> renderEncoder = [commandBuffer renderCommandEncoderWithDescriptor:renderPass];
|
||||
[renderEncoder setRenderPipelineState:self.renderPipeline];
|
||||
[renderEncoder setFragmentTexture:sourceTexture atIndex:0];
|
||||
[renderEncoder setVertexBuffer:self.outputVertextBuffer offset:0 atIndex:0];
|
||||
[renderEncoder setVertexBuffer:self.noRotationBuffer offset:0 atIndex:1];
|
||||
|
||||
[renderEncoder drawPrimitives:MTLPrimitiveTypeTriangleStrip vertexStart:0 vertexCount:4];
|
||||
[renderEncoder endEncoding];
|
||||
|
||||
[commandBuffer commit];
|
||||
[commandBuffer waitUntilCompleted];
|
||||
|
||||
commandBuffer = nil;
|
||||
renderEncoder = nil;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
25
mediapipe/render/ios/Info.plist
Normal file
25
mediapipe/render/ios/Info.plist
Normal file
|
@ -0,0 +1,25 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>UIApplicationSceneManifest</key>
|
||||
<dict>
|
||||
<key>UIApplicationSupportsMultipleScenes</key>
|
||||
<false/>
|
||||
<key>UISceneConfigurations</key>
|
||||
<dict>
|
||||
<key>UIWindowSceneSessionRoleApplication</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>UISceneConfigurationName</key>
|
||||
<string>Default Configuration</string>
|
||||
<key>UISceneDelegateClassName</key>
|
||||
<string>SceneDelegate</string>
|
||||
<key>UISceneStoryboardFile</key>
|
||||
<string>Main</string>
|
||||
</dict>
|
||||
</array>
|
||||
</dict>
|
||||
</dict>
|
||||
</dict>
|
||||
</plist>
|
12
mediapipe/render/ios/OlaRender.h
Normal file
12
mediapipe/render/ios/OlaRender.h
Normal file
|
@ -0,0 +1,12 @@
|
|||
//
|
||||
// OlaRender.h
|
||||
// OlaRender
|
||||
// Created by Renzhu wang on 2022/7/12.
|
||||
// Copyright © 2022 Ola. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@interface OlaRender : NSObject
|
||||
|
||||
@end
|
14
mediapipe/render/ios/OlaRender.mm
Normal file
14
mediapipe/render/ios/OlaRender.mm
Normal file
|
@ -0,0 +1,14 @@
|
|||
//
|
||||
// OlaRender.h
|
||||
// OlaRender
|
||||
// Created by Renzhu wang on 2022/7/12.
|
||||
// Copyright © 2022 Ola. All rights reserved.
|
||||
//
|
||||
|
||||
#import "OlaRender.h"
|
||||
|
||||
|
||||
@implementation OlaRender
|
||||
|
||||
|
||||
@end
|
|
@ -44,13 +44,13 @@ licenses=$4
|
|||
if [ -z $1 ]
|
||||
then
|
||||
echo "Warning: android_sdk_path (argument 1) is not specified. Fallback to ~/Android/Sdk/"
|
||||
android_sdk_path=$HOME"/Android/Sdk"
|
||||
android_sdk_path=$HOME"/Android/sdk"
|
||||
fi
|
||||
|
||||
if [ -z $2 ]
|
||||
then
|
||||
echo "Warning: android_ndk_path (argument 2) is not specified. Fallback to ~/Android/Sdk/ndk-bundle/android-ndk-<NDK_VERSION>/"
|
||||
android_ndk_path=$HOME"/Android/Sdk/ndk-bundle"
|
||||
android_ndk_path=$HOME"/Android/sdk/ndk"
|
||||
fi
|
||||
|
||||
if [ -z $3 ]
|
||||
|
|
42
third_party/opencv_android.BUILD-e
vendored
Normal file
42
third_party/opencv_android.BUILD-e
vendored
Normal file
|
@ -0,0 +1,42 @@
|
|||
# Description:
|
||||
# OpenCV libraries for video/image processing on Android
|
||||
|
||||
licenses(["notice"]) # BSD license
|
||||
|
||||
exports_files(["LICENSE"])
|
||||
|
||||
OPENCV_LIBRARY_NAME = "libopencv_java3.so"
|
||||
|
||||
OPENCVANDROIDSDK_NATIVELIBS_PATH = "sdk/native/libs/"
|
||||
|
||||
OPENCVANDROIDSDK_JNI_PATH = "sdk/native/jni/"
|
||||
|
||||
[cc_library(
|
||||
name = "libopencv_" + arch,
|
||||
srcs = [OPENCVANDROIDSDK_NATIVELIBS_PATH + arch + "/" + OPENCV_LIBRARY_NAME],
|
||||
hdrs = glob([
|
||||
OPENCVANDROIDSDK_JNI_PATH + "include/**/*.h",
|
||||
OPENCVANDROIDSDK_JNI_PATH + "include/**/*.hpp",
|
||||
]),
|
||||
includes = [
|
||||
OPENCVANDROIDSDK_JNI_PATH + "include",
|
||||
],
|
||||
visibility = ["//visibility:public"],
|
||||
alwayslink = 1,
|
||||
) for arch in [
|
||||
"arm64-v8a",
|
||||
"armeabi-v7a",
|
||||
"x86",
|
||||
"x86_64",
|
||||
]]
|
||||
|
||||
[alias(
|
||||
name = "libopencv_java3_so_" + arch,
|
||||
actual = OPENCVANDROIDSDK_NATIVELIBS_PATH + arch + "/" + OPENCV_LIBRARY_NAME,
|
||||
visibility = ["//visibility:public"],
|
||||
) for arch in [
|
||||
"arm64-v8a",
|
||||
"armeabi-v7a",
|
||||
"x86",
|
||||
"x86_64",
|
||||
]]
|
Loading…
Reference in New Issue
Block a user