ADD_SUBDIRECTORY(inference)
ADD_SUBDIRECTORY(services)
ADD_SUBDIRECTORY(test)
+ADD_SUBDIRECTORY(visualizer)
SET(PC_NAME ${PROJECT_NAME})
SET(PC_LDFLAGS -l${PROJECT_NAME})
--- /dev/null
+/**
+ * Copyright (c) 2024 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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 __SINGLEO_NATIVE_CAPI_INTERNAL_H__
+#define __SINGLEO_NATIVE_CAPI_INTERNAL_H__
+
+#include "singleo_native_capi.h"
+
+typedef void (*singleo_user_cb_t)(unsigned char *buffer, unsigned int width, unsigned int height,
+ unsigned int bytes_per_pixel, void *user_data);
+
+/**
+ * @internal
+ * @brief Registers user-given callback for user to receive result mixed with input data.
+ *
+ * @since_tizen 9.0
+ * @remarks With this function, user can receive result mixed with input data by callback.
+ * This API is valid only in case of using asynchronous mode.
+ *
+ * @param[in] handle The handle to the service.
+ *
+ * @return 0 on success, otherwise a negative error value
+ * @retval #SINGLEO_SERVICE_ERROR_NONE Successful
+ * @retval #SINGLEO_SERVICE_ERROR_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #SINGLEO_SERVICE_ERROR_ERROR_INVALID_OPERATION Invalid operation
+ *
+ * @pre Create a source handle by calling singleo_service_create()
+ */
+int singleo_service_register_user_callback(singleo_service_h handle,
+ void (*callback_ptr)(unsigned char *buffer, unsigned int width,
+ unsigned int height, unsigned int bytes_per_pixel,
+ void *user_data),
+ void *user_data);
+
+/**
+ * @internal
+ * @brief Unregisters user-given callback.
+ *
+ * @since_tizen 9.0
+ * @remarks This API unregister the callback registered by user.
+ *
+ * @param[in] handle The handle to the service.
+ *
+ * @return 0 on success, otherwise a negative error value
+ * @retval #SINGLEO_SERVICE_ERROR_NONE Successful
+ * @retval #SINGLEO_SERVICE_ERROR_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #SINGLEO_SERVICE_ERROR_ERROR_INVALID_OPERATION Invalid operation
+ *
+ * @pre Create a source handle by calling singleo_service_create()
+ * @pre Register a callback by calling singleo_service_register_user_callback()
+ */
+int singleo_service_unregister_user_callback(singleo_service_h handle);
+
+#endif
\ No newline at end of file
Source0: %{name}-%{version}.tar.gz
BuildRequires: cmake
BuildRequires: pkgconfig(capi-media-vision)
+BuildRequires: pkgconfig(capi-media-tool)
BuildRequires: pkgconfig(opencv)
BuildRequires: pkgconfig(dlog)
BuildRequires: gtest-devel
+BuildRequires: pkgconfig(libdrm)
+BuildRequires: pkgconfig(wayland-egl)
+BuildRequires: pkgconfig(glesv2)
+BuildRequires: pkgconfig(protobuf)
+BuildRequires: pkgconfig(grpc++)
+BuildRequires: pkgconfig(re2)
%define enable_autozoom_api 1
%define BUILD_OPTIONS -DPLATFORM_IS_TIZEN=0 -DUSE_EXTERNAL_INFERENCE_SERVICE=0 -DUSE_AUTOZOOM_API=%{enable_autozoom_api}
%{_libdir}/libsingleo_service.so
%{_libdir}/libsingleo_input.so
%{_libdir}/libsingleo_input_backend.so
+%{_libdir}/libsingleo_visualizer.so
%files test
%{_bindir}/test_singleo
+%{_bindir}/test_autozoom_on_screen
inference::TaskType _task_type { inference::TaskType::FACE_DETECTION };
bool isKeyValid(std::string key);
- void updateResult();
+ void updateResult(BaseDataType &input_data);
std::unique_ptr<AsyncManager<ImageDataType, AutoZoomResult> > _async_manager;
+ singleo_user_cb_t _user_cb {};
+ void *_user_data {};
public:
explicit AutoZoom(input::InputConfigBase &config);
void performAsync() override;
void getResultCnt(unsigned int *cnt) override;
void getResultInt(unsigned int idx, std::string key, unsigned int *value) override;
+ void registerUserCallback(singleo_user_cb_t user_cb, void *user_data) override;
+ void unregisterUserCallback() override;
std::unique_ptr<AsyncManager<ImageDataType, AutoZoomResult> > &getAsyncManager()
{
_inference_service->invoke(image_data);
- updateResult();
+ updateResult(preprocessor.getData());
}
void AutoZoom::perform()
preprocessed_image.setData(preprocessor.getData());
_inference_service->invoke(preprocessed_image);
- updateResult();
+ updateResult(preprocessor.getData());
}
void AutoZoom::performAsync()
input_container.setData(data);
auto_zoom->getInferenceService()->invoke(input_container);
- auto_zoom->updateResult();
+ auto_zoom->updateResult(data);
// This buffer was allocated and copied in inputServiceCb callback.
// So make sure to release this buffer here.
});
}
-void AutoZoom::updateResult()
+void AutoZoom::updateResult(BaseDataType &in_data)
{
auto &output_data = _inference_service->result();
unsigned int frame_number = output_data.getFrameNumber();
}
}
+ // For debug
+ ImagePreprocessor preprocessed_result(in_data);
+
+ // If detected object exists then draw a box on captured image.
+ if (result_cnt > 0)
+ preprocessed_result.drawBox(rect, 0, 0, 255);
+
// TODO. implement Postprocessor which calculates Autozoom position using above 'result' vector.
SINGLEO_LOGD("result cnt = %zu", result_cnt);
_result.num_of_result = result_cnt;
+ // If user callback exists then call it. This callback is used for the debug.
+ if (_user_cb) {
+ auto imageData = dynamic_cast<ImageDataType &>(preprocessed_result.getData());
+
+ _user_cb(imageData.ptr, imageData.width, imageData.height, imageData.byte_per_pixel, _user_data);
+ }
+
if (result_cnt == 0) {
SINGLEO_LOGW("No detected objects.");
return;
}
}
+void AutoZoom::registerUserCallback(singleo_user_cb_t user_cb, void *user_data)
+{
+ _user_cb = user_cb;
+ _user_data = user_data;
+}
+
+void AutoZoom::unregisterUserCallback()
+{
+ _user_cb = nullptr;
+ _user_data = nullptr;
+}
+
}
}
#ifndef __ISERVICE_H__
#define __ISERVICE_H__
+#include "singleo_native_capi_internal.h"
+
#include "SingleoCommonTypes.h"
#include "IPreprocessor.h"
#include "InputDataType.h"
virtual void performAsync() = 0;
virtual void getResultCnt(unsigned int *cnt) = 0;
virtual void getResultInt(unsigned int idx, std::string key, unsigned int *value) = 0;
+ virtual void registerUserCallback(singleo_user_cb_t user_cb, void *user_data) = 0;
+ virtual void unregisterUserCallback() = 0;
};
}
#include <memory>
#include <string>
+
#include <opencv2/opencv.hpp>
#include "IPreprocessor.h"
void setData(BaseDataType &data) override;
BaseDataType &getData() override;
- // For debug
- void drawRedBox(Rect &rect);
+ void drawBox(Rect &rect, unsigned char r, unsigned char g, unsigned char b);
void toFile(std::string file_name);
};
return _image_data;
}
-void ImagePreprocessor::drawRedBox(Rect &rect)
+void ImagePreprocessor::drawBox(Rect &rect, unsigned char r, unsigned char g, unsigned char b)
{
cv::Point leftTop(rect.left, rect.top);
cv::Point rightBottom(rect.right, rect.bottom);
- cv::rectangle(_cv_image, cv::Rect(leftTop, rightBottom), cv::Scalar(0, 0, 255));
+ cv::rectangle(_cv_image, cv::Rect(leftTop, rightBottom), cv::Scalar(r, g, b));
}
void ImagePreprocessor::toFile(string file_name)
#include <dlfcn.h>
-#include "singleo_native_capi.h"
+#include "singleo_native_capi_internal.h"
#include "SingleoException.h"
#include "Context.h"
#include "ServiceConfigParser.h"
return SINGLEO_ERROR_NONE;
}
+
+int singleo_service_register_user_callback(singleo_service_h handle, singleo_user_cb_t user_cb, void *user_data)
+{
+ try {
+ auto context = static_cast<Context *>(handle);
+ context->_service_handle->registerUserCallback(user_cb, user_data);
+ } catch (const BaseException &e) {
+ return e.getError();
+ }
+
+ return SINGLEO_ERROR_NONE;
+}
+
+int singleo_service_unregister_user_callback(singleo_service_h handle)
+{
+ try {
+ auto context = static_cast<Context *>(handle);
+ context->_service_handle->unregisterUserCallback();
+ } catch (const BaseException &e) {
+ return e.getError();
+ }
+
+ return SINGLEO_ERROR_NONE;
+}
\ No newline at end of file
-add_subdirectory(services)
\ No newline at end of file
+add_subdirectory(services)
TARGET_LINK_LIBRARIES(${PROJECT_NAME}
gtest gtest_main pthread singleo_service)
-install(TARGETS ${PROJECT_NAME} DESTINATION ${CMAKE_INSTALL_BINDIR})
\ No newline at end of file
+install(TARGETS ${PROJECT_NAME} DESTINATION ${CMAKE_INSTALL_BINDIR})
+
+SET(TEST_SOURCE_ON_SCREEN_LIST test_autozoom_on_screen.cpp)
+
+ADD_EXECUTABLE(test_singleo_on_screen ${TEST_SOURCE_ON_SCREEN_LIST})
+TARGET_COMPILE_DEFINITIONS(test_singleo_on_screen PRIVATE -DTEST_RES_PATH="${TEST_RES_PATH}")
+TARGET_INCLUDE_DIRECTORIES(test_singleo_on_screen PRIVATE ../../capi/ ../../common/include ../../visualizer/include)
+TARGET_LINK_LIBRARIES(test_singleo_on_screen
+ gtest gtest_main pthread singleo_service singleo_visualizer opencv_imgcodecs)
+
+install(TARGETS test_singleo_on_screen DESTINATION ${CMAKE_INSTALL_BINDIR})
--- /dev/null
+/**
+ * Copyright (c) 2024 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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 <iostream>
+#include <algorithm>
+#include <memory>
+#include <string.h>
+#include <thread>
+
+#include <opencv2/opencv.hpp>
+
+#include "gtest/gtest.h"
+#include "singleo_native_capi_internal.h"
+#include "singleo_util_visualizer_2d.h"
+#include "singleo_error.h"
+
+using namespace testing;
+using namespace std;
+
+void autozoom_callback(void *user_data)
+{
+ singleo_service_h handle = static_cast<singleo_service_h>(user_data);
+ bool is_loop_exit = false;
+ unsigned long frame_number = 0;
+
+ while (!is_loop_exit) {
+ unsigned int cnt;
+
+ int ret = singleo_service_get_result_cnt(handle, &cnt);
+ if (ret != SINGLEO_ERROR_NONE)
+ break;
+
+ ASSERT_EQ(ret, SINGLEO_ERROR_NONE);
+
+ for (unsigned int idx = 0; idx < cnt; ++idx) {
+ unsigned int x, y, w, h;
+
+ ret = singleo_service_get_result_int(handle, idx, "x", &x);
+ ASSERT_EQ(ret, SINGLEO_ERROR_NONE);
+ ret = singleo_service_get_result_int(handle, idx, "y", &y);
+ ASSERT_EQ(ret, SINGLEO_ERROR_NONE);
+ ret = singleo_service_get_result_int(handle, idx, "width", &w);
+ ASSERT_EQ(ret, SINGLEO_ERROR_NONE);
+ ret = singleo_service_get_result_int(handle, idx, "height", &h);
+ ASSERT_EQ(ret, SINGLEO_ERROR_NONE);
+
+ cout << x << " x " << y << " ~ " << w << " x " << h << endl;
+ }
+
+ if (++frame_number > 500 && cnt > 0)
+ is_loop_exit = true;
+ }
+}
+
+void user_callback(unsigned char *buffer, unsigned int width, unsigned int height, unsigned int bytes_per_pixel,
+ void *user_data)
+{
+ cv::Mat cv_image(cv::Size(width, height), CV_MAKETYPE(CV_8U, 3), buffer);
+
+ cv::cvtColor(cv_image, cv_image, cv::COLOR_BGR2RGBA);
+
+ cv::Mat resized_image(cv::Size(1600, 900), CV_8UC4, cv::Scalar(0, 0, 0, 0));
+ cv::resize(cv_image, resized_image, resized_image.size());
+
+ singleo_util_visualizer_2d(resized_image, NULL);
+}
+
+TEST(AutoZoomAsyncOnScreenTest, InferenceRequestWithCameraInputFeedShouldBeOk)
+{
+ singleo_service_h handle;
+
+ int ret =
+ singleo_service_create("service=auto_zoom, input=camera, camera_backend=opencv, fps=30, async=1", &handle);
+ ASSERT_EQ(ret, SINGLEO_ERROR_NONE);
+
+ ret = singleo_service_register_user_callback(handle, user_callback, nullptr);
+ ASSERT_EQ(ret, SINGLEO_ERROR_NONE);
+
+ ret = singleo_service_perform(handle);
+ ASSERT_EQ(ret, SINGLEO_ERROR_NONE);
+
+ unique_ptr<thread> thread_handle = make_unique<thread>(&autozoom_callback, static_cast<void *>(handle));
+
+ thread_handle->join();
+
+ ret = singleo_service_unregister_user_callback(handle);
+ ASSERT_EQ(ret, SINGLEO_ERROR_NONE);
+
+ ret = singleo_service_destroy(handle);
+ ASSERT_EQ(ret, SINGLEO_ERROR_NONE);
+}
--- /dev/null
+project(singleo_visualizer)
+cmake_minimum_required(VERSION 3.13)
+
+execute_process(COMMAND protoc -I=${CMAKE_CURRENT_SOURCE_DIR}
+ ${PROJECT_SOURCE_DIR}/singleo_util_visualizer_rd.proto
+ --cpp_out=${PROJECT_SOURCE_DIR}/src)
+
+execute_process(COMMAND protoc -I=${CMAKE_CURRENT_SOURCE_DIR}
+ ${PROJECT_SOURCE_DIR}/singleo_util_visualizer_rd.proto
+ --grpc_out=${PROJECT_SOURCE_DIR}/src
+ --plugin=protoc-gen-grpc=/usr/bin/grpc_cpp_plugin)
+
+file(GLOB MV_VISUALIZER_SRC_LIST "${PROJECT_SOURCE_DIR}/src/*.cpp"
+ "${PROJECT_SOURCE_DIR}/src/*.cc")
+
+include(FindPkgConfig)
+
+pkg_check_modules(${PROJECT_NAME}_DEP REQUIRED capi-media-tool libdrm wayland-egl glesv2 dlog protobuf grpc++ re2)
+
+find_package(OpenCV REQUIRED imgproc)
+if(NOT OpenCV_FOUND)
+ message(SEND_ERROR "Failed to find OpenCV")
+ return()
+endif()
+
+add_library(${PROJECT_NAME} SHARED ${MV_VISUALIZER_SRC_LIST})
+target_include_directories(${PROJECT_NAME} PUBLIC
+ ${${PROJECT_NAME}_DEP_INCLUDE_DIRS}
+ ${OpenCV_INCLUDE_DIRS}
+ ${PROJECT_SOURCE_DIR}/include
+ ../common/include
+ ../log/include)
+target_link_libraries(${PROJECT_NAME} ${${PROJECT_NAME}_DEP_LIBRARIES}
+ ${OpenCV_LIBS} singleo_log)
+install(TARGETS ${PROJECT_NAME} DESTINATION ${LIB_INSTALL_DIR})
--- /dev/null
+/**
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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 __SINGLEO_UTIL_MATRIX_H__
+#define __SINGLEO_UTIL_MATRIX_H__
+
+int matrix_translate(float *m, float x, float y, float z);
+int matrix_rotate(float *m, float angle, float x, float y, float z);
+int matrix_scale(float *m, float x, float y, float z);
+int matrix_mult(float *m, float *m1, float *m2);
+int matrix_identity(float *m);
+void matrix_copy(float *d, float *s);
+void matrix_invert(float *m);
+void matrix_transpose(float *m);
+void matrix_proj_perspective(float *mat, float fovy, float aspect, float znear, float zfar);
+void quaternion_mult(float *lpR, float *lpP, float *lpQ);
+void quaternion_to_matrix(float *lpM, float *lpQ);
+void quaternion_rotate(float *lpQ, float rad, float ax, float ay, float az);
+void quaternion_identity(float *lpQ);
+void quaternion_copy(float *lpTo, float *lpFrom);
+float vec3_normalize(float *v);
+
+#endif /* __SINGLEO_UTIL_MATRIX_H__ */
--- /dev/null
+/**
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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 __SINGLEO_UTIL_RENDER_2D_H__
+#define __SINGLEO_UTIL_RENDER_2D_H__
+
+#include <opencv2/opencv.hpp>
+#include <mv_common.h>
+#include <cmath>
+
+#define pixfmt_fourcc(a, b, c, d) ((uint32_t)(a) | ((uint32_t)(b) << 8) | ((uint32_t)(c) << 16) | ((uint32_t)(d) << 24))
+
+typedef struct _texture_2d_t {
+ uint32_t texid;
+ int width;
+ int height;
+ uint32_t format;
+} texture_2d_t;
+
+uint32_t create_2d_texture(void *imgbuf, int width, int height);
+int init_2d_renderer(int w, int h);
+int load_texture(cv::Mat &source, int *lpTexID, int *lpWidth, int *lpHeight);
+int draw_2d_texture(texture_2d_t *tex, int x, int y, int w, int h, int upsidedown);
+int egl_init_with_platform_window_surface(int gles_version, int depth_size, int stencil_size, int sample_num, int win_w,
+ int win_h);
+int egl_swap();
+
+#endif /* __SINGLEO_UTIL_RENDER_2D_H__ */
--- /dev/null
+/**
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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 __SINGLEO_UTIL_SHADER_H__
+#define __SINGLEO_UTIL_SHADER_H__
+
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+#include <cstdlib>
+
+typedef struct shader_obj_t {
+ GLuint program;
+ GLint loc_vtx;
+ GLint loc_nrm;
+ GLint loc_clr;
+ GLint loc_uv;
+ GLint loc_tex;
+ GLint loc_mtx;
+ GLint loc_mtx_nrm;
+} shader_obj_t;
+
+typedef struct _mesh_obj_t {
+ float *vtx_array;
+ float *uv_array;
+ unsigned short *idx_array;
+
+ GLuint vbo_vtx;
+ GLuint vbo_uv;
+ GLuint vbo_idx;
+
+ int num_tile_w;
+ int num_tile_h;
+ int num_idx;
+} mesh_obj_t;
+
+GLuint compile_shader_text(GLenum shaderType, const char *text);
+GLuint link_shaders(GLuint vertShader, GLuint fragShader);
+int generate_shader(shader_obj_t *sobj, char *str_vs, char *str_fs);
+
+#endif /* __SINGLEO_UTIL_SHADER_H__*/
\ No newline at end of file
--- /dev/null
+/**
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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 __SINGLEO_UTIL_VISUALIZER_2D_H__
+#define __SINGLEO_UTIL_VISUALIZER_2D_H__
+
+#include <opencv2/opencv.hpp>
+#include <GLES2/gl2.h>
+
+#include "singleo_util_render_2d.h"
+
+int singleo_util_visualizer_2d(cv::Mat &source, const char *url);
+
+#endif /* __SINGLEO_UTIL_VISUALIZER_2D_H__*/
--- /dev/null
+/**
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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 __SINGLEO_UTIL_WINSYS_H_
+#define __SINGLEO_UTIL_WINSYS_H_
+
+struct Window;
+struct Display {
+ struct wl_display *wlDisplay;
+ struct wl_registry *wlRegistry;
+ struct wl_compositor *wlCompositor;
+ struct wl_shell *wlShell;
+ struct wl_pointer *pointer;
+ uint32_t serial;
+ struct Window *window;
+};
+
+struct Geometry {
+ int width, height;
+};
+
+struct Window {
+ struct Display *display;
+ struct wl_egl_window *wlEGLNativeWindow;
+ struct wl_surface *wlSurface;
+ struct wl_shell_surface *wlShellSurface;
+ struct wl_callback *callback;
+ struct Geometry geometry, window_size;
+};
+
+void *winsys_init_native_display(void);
+void *winsys_init_native_window(void *dpy, int win_w, int win_h);
+
+#endif /* __SINGLEO_UTIL_WINSYS_H_ */
--- /dev/null
+syntax = "proto3";
+
+message Empty {
+}
+
+message NLImage {
+ int32 length = 1;
+ bytes data = 2;
+}
+
+message NLImageDrawRequest {
+ NLImage image = 1;
+}
+
+service NLImageService {
+ rpc DrawImage(NLImageDrawRequest) returns (Empty);
+}
+
--- /dev/null
+/**
+ * Copyright(c) 2022 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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.
+ */
+
+#define _USE_MATH_DEFINES
+#include "singleo_util_matrix.h"
+#include <math.h>
+#include <cstring>
+#include "SingleoLog.h"
+#include "singleo_error.h"
+
+static float vec3_length(float *v)
+{
+ return (float) sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
+}
+
+static void turn_x(float *m, float cosA, float sinA)
+{
+ float mx01, mx02;
+ float mx11, mx12;
+ float mx21, mx22;
+ float mx31, mx32;
+
+ mx01 = cosA * m[4];
+ mx02 = sinA * m[4];
+
+ mx11 = cosA * m[5];
+ mx12 = sinA * m[5];
+
+ mx21 = cosA * m[6];
+ mx22 = sinA * m[6];
+
+ mx31 = cosA * m[7];
+ mx32 = sinA * m[7];
+
+ mx01 = sinA * m[8] + mx01;
+ mx02 = cosA * m[8] - mx02;
+
+ mx11 = sinA * m[9] + mx11;
+ mx12 = cosA * m[9] - mx12;
+
+ mx21 = sinA * m[10] + mx21;
+ mx22 = cosA * m[10] - mx22;
+
+ mx31 = sinA * m[11] + mx31;
+ mx32 = cosA * m[11] - mx32;
+
+ m[4] = mx01;
+ m[8] = mx02;
+
+ m[5] = mx11;
+ m[9] = mx12;
+
+ m[6] = mx21;
+ m[10] = mx22;
+
+ m[7] = mx31;
+ m[11] = mx32;
+}
+
+static void turn_y(float *m, float cosA, float sinA)
+{
+ float mx00, mx02;
+ float mx10, mx12;
+ float mx20, mx22;
+ float mx30, mx32;
+
+ mx00 = cosA * m[0];
+ mx02 = sinA * m[0];
+
+ mx10 = cosA * m[1];
+ mx12 = sinA * m[1];
+
+ mx20 = cosA * m[2];
+ mx22 = sinA * m[2];
+
+ mx30 = cosA * m[3];
+ mx32 = sinA * m[3];
+
+ mx00 = -sinA * m[8] + mx00;
+ mx02 = cosA * m[8] + mx02;
+
+ mx10 = -sinA * m[9] + mx10;
+ mx12 = cosA * m[9] + mx12;
+
+ mx20 = -sinA * m[10] + mx20;
+ mx22 = cosA * m[10] + mx22;
+
+ mx30 = -sinA * m[11] + mx30;
+ mx32 = cosA * m[11] + mx32;
+
+ m[0] = mx00;
+ m[8] = mx02;
+
+ m[1] = mx10;
+ m[9] = mx12;
+
+ m[2] = mx20;
+ m[10] = mx22;
+
+ m[3] = mx30;
+ m[11] = mx32;
+}
+
+static void turn_z(float *m, float cosA, float sinA)
+{
+ float mx00, mx01;
+ float mx10, mx11;
+ float mx20, mx21;
+ float mx30, mx31;
+
+ mx00 = cosA * m[0];
+ mx01 = sinA * m[0];
+
+ mx10 = cosA * m[1];
+ mx11 = sinA * m[1];
+
+ mx20 = cosA * m[2];
+ mx21 = sinA * m[2];
+
+ mx30 = cosA * m[3];
+ mx31 = sinA * m[3];
+
+ mx00 = sinA * m[4] + mx00;
+ mx01 = cosA * m[4] - mx01;
+
+ mx10 = sinA * m[5] + mx10;
+ mx11 = cosA * m[5] - mx11;
+
+ mx20 = sinA * m[6] + mx20;
+ mx21 = cosA * m[6] - mx21;
+
+ mx30 = sinA * m[7] + mx30;
+ mx31 = cosA * m[7] - mx31;
+
+ m[0] = mx00;
+ m[4] = mx01;
+ m[1] = mx10;
+ m[5] = mx11;
+ m[2] = mx20;
+ m[6] = mx21;
+ m[3] = mx30;
+ m[7] = mx31;
+}
+
+int matrix_translate(float *m, float x, float y, float z)
+{
+ if (m == NULL) {
+ SINGLEO_LOGE("m is NULL");
+ return SINGLEO_ERROR_EPERM;
+ }
+
+ m[12] += m[8] * z;
+ m[13] += m[9] * z;
+ m[14] += m[10] * z;
+ m[15] += m[11] * z;
+
+ m[12] += m[4] * y;
+ m[13] += m[5] * y;
+ m[14] += m[6] * y;
+ m[15] += m[7] * y;
+
+ m[12] += m[0] * x;
+ m[13] += m[1] * x;
+ m[14] += m[2] * x;
+ m[15] += m[3] * x;
+
+ return SINGLEO_ERROR_NONE;
+}
+
+int matrix_rotate(float *m, float angle, float x, float y, float z)
+{
+ float v[3], angleRadian;
+ float sinA, cosA, cosA2;
+ float xcosA2, ycosA2, zcosA2;
+ float xsinA, ysinA, zsinA;
+
+ if (m == NULL) {
+ SINGLEO_LOGE("m is NULL");
+ return SINGLEO_ERROR_EPERM;
+ }
+
+ angleRadian = angle * (M_PI / 180.0f);
+ sinA = (float) sin(angleRadian);
+ cosA = (float) cos(angleRadian);
+
+ if (x == 0.0f && y == 0.0f && z != 0.0f) {
+ if (z < 0.0f) {
+ sinA = -sinA;
+ }
+ turn_z(m, cosA, sinA);
+ return SINGLEO_ERROR_NONE;
+ } else if (x == 0.0f && y != 0.0f && z == 0.0f) {
+ if (y < 0.0f) {
+ sinA = -sinA;
+ }
+ turn_y(m, cosA, sinA);
+ return SINGLEO_ERROR_NONE;
+ } else if (x != 0.0f && y == 0.0f && z == 0.0f) {
+ if (x < 0.0f) {
+ sinA = -sinA;
+ }
+ turn_x(m, cosA, sinA);
+ return SINGLEO_ERROR_NONE;
+ }
+
+ {
+ float r00, r01, r02;
+ float r10, r11, r12;
+ float r20, r21, r22;
+
+ v[0] = x;
+ v[1] = y;
+ v[2] = z;
+ vec3_normalize(v);
+
+ x = v[0];
+ y = v[1];
+ z = v[2];
+
+ cosA2 = 1.0f - cosA;
+ xsinA = x * sinA;
+ ysinA = y * sinA;
+ zsinA = z * sinA;
+ xcosA2 = x * cosA2;
+ ycosA2 = y * cosA2;
+ zcosA2 = z * cosA2;
+
+ r00 = x * xcosA2 + cosA;
+ r10 = y * xcosA2 + zsinA;
+ r20 = z * xcosA2 - ysinA;
+
+ r01 = x * ycosA2 - zsinA;
+ r11 = y * ycosA2 + cosA;
+ r21 = z * ycosA2 + xsinA;
+
+ r02 = x * zcosA2 + ysinA;
+ r12 = y * zcosA2 - xsinA;
+ r22 = z * zcosA2 + cosA;
+
+ {
+ float fm0, fm1, fm2;
+ float mx, my, mz;
+
+ fm0 = m[0];
+ fm1 = m[4];
+ fm2 = m[8];
+
+ mx = fm0 * r00;
+ my = fm0 * r01;
+ mz = fm0 * r02;
+
+ mx += fm1 * r10;
+ my += fm1 * r11;
+ mz += fm1 * r12;
+
+ mx += fm2 * r20;
+ my += fm2 * r21;
+ mz += fm2 * r22;
+
+ fm0 = m[1];
+ fm1 = m[5];
+ fm2 = m[9];
+
+ m[0] = mx;
+ m[4] = my;
+ m[8] = mz;
+
+ mx = fm0 * r00;
+ my = fm0 * r01;
+ mz = fm0 * r02;
+
+ mx += fm1 * r10;
+ my += fm1 * r11;
+ mz += fm1 * r12;
+
+ mx += fm2 * r20;
+ my += fm2 * r21;
+ mz += fm2 * r22;
+
+ fm0 = m[2];
+ fm1 = m[6];
+ fm2 = m[10];
+
+ m[1] = mx;
+ m[5] = my;
+ m[9] = mz;
+
+ mx = fm0 * r00;
+ my = fm0 * r01;
+ mz = fm0 * r02;
+
+ mx += fm1 * r10;
+ my += fm1 * r11;
+ mz += fm1 * r12;
+
+ mx += fm2 * r20;
+ my += fm2 * r21;
+ mz += fm2 * r22;
+
+ fm0 = m[3];
+ fm1 = m[7];
+ fm2 = m[11];
+
+ m[2] = mx;
+ m[6] = my;
+ m[10] = mz;
+
+ mx = fm0 * r00;
+ my = fm0 * r01;
+ mz = fm0 * r02;
+
+ mx += fm1 * r10;
+ my += fm1 * r11;
+ mz += fm1 * r12;
+
+ mx += fm2 * r20;
+ my += fm2 * r21;
+ mz += fm2 * r22;
+
+ m[3] = mx;
+ m[7] = my;
+ m[11] = mz;
+ }
+ }
+
+ return SINGLEO_ERROR_NONE;
+}
+
+int matrix_scale(float *m, float x, float y, float z)
+{
+ float m00, m01, m02, m03;
+ float m04, m05, m06, m07;
+ float m08, m09, m10, m11;
+
+ if (m == NULL) {
+ SINGLEO_LOGE("m is NULL");
+ return SINGLEO_ERROR_EPERM;
+ }
+
+ m00 = m[0];
+ m04 = m[4];
+ m08 = m[8];
+ m01 = m[1];
+ m05 = m[5];
+ m09 = m[9];
+ m02 = m[2];
+ m06 = m[6];
+ m10 = m[10];
+ m03 = m[3];
+ m07 = m[7];
+ m11 = m[11];
+
+ m00 = m00 * x;
+ m04 = m04 * y;
+ m08 = m08 * z;
+
+ m01 = m01 * x;
+ m05 = m05 * y;
+ m09 = m09 * z;
+
+ m02 = m02 * x;
+ m06 = m06 * y;
+ m10 = m10 * z;
+
+ m03 = m03 * x;
+ m07 = m07 * y;
+ m11 = m11 * z;
+
+ m[0] = m00;
+ m[4] = m04;
+ m[8] = m08;
+
+ m[1] = m01;
+ m[5] = m05;
+ m[9] = m09;
+
+ m[2] = m02;
+ m[6] = m06;
+ m[10] = m10;
+
+ m[3] = m03;
+ m[7] = m07;
+ m[11] = m11;
+
+ return SINGLEO_ERROR_NONE;
+}
+
+int matrix_mult(float *m, float *m1, float *m2)
+{
+ float fm0, fm1, fm2, fm3;
+ float fpm00, fpm01, fpm02, fpm03;
+ float fpm10, fpm11, fpm12, fpm13;
+ float fpm20, fpm21, fpm22, fpm23;
+ float fpm30, fpm31, fpm32, fpm33;
+ float x, y, z, w;
+
+ if (m == NULL) {
+ SINGLEO_LOGE("m is NULL");
+ return SINGLEO_ERROR_EPERM;
+ }
+
+ /* load pMb */
+ fpm00 = m2[0];
+ fpm01 = m2[4];
+ fpm02 = m2[8];
+ fpm03 = m2[12];
+
+ fpm10 = m2[1];
+ fpm11 = m2[5];
+ fpm12 = m2[9];
+ fpm13 = m2[13];
+
+ fpm20 = m2[2];
+ fpm21 = m2[6];
+ fpm22 = m2[10];
+ fpm23 = m2[14];
+
+ fpm30 = m2[3];
+ fpm31 = m2[7];
+ fpm32 = m2[11];
+ fpm33 = m2[15];
+
+ fm0 = m1[0];
+ fm1 = m1[4];
+ fm2 = m1[8];
+ fm3 = m1[12];
+
+ x = fm0 * fpm00;
+ y = fm0 * fpm01;
+ z = fm0 * fpm02;
+ w = fm0 * fpm03;
+
+ x += fm1 * fpm10;
+ y += fm1 * fpm11;
+ z += fm1 * fpm12;
+ w += fm1 * fpm13;
+
+ x += fm2 * fpm20;
+ y += fm2 * fpm21;
+ z += fm2 * fpm22;
+ w += fm2 * fpm23;
+
+ x += fm3 * fpm30;
+ y += fm3 * fpm31;
+ z += fm3 * fpm32;
+ w += fm3 * fpm33;
+
+ fm0 = m1[1];
+ fm1 = m1[5];
+ fm2 = m1[9];
+ fm3 = m1[13];
+
+ m[0] = x;
+ m[4] = y;
+ m[8] = z;
+ m[12] = w;
+
+ x = fm0 * fpm00;
+ y = fm0 * fpm01;
+ z = fm0 * fpm02;
+ w = fm0 * fpm03;
+
+ x += fm1 * fpm10;
+ y += fm1 * fpm11;
+ z += fm1 * fpm12;
+ w += fm1 * fpm13;
+
+ x += fm2 * fpm20;
+ y += fm2 * fpm21;
+ z += fm2 * fpm22;
+ w += fm2 * fpm23;
+
+ x += fm3 * fpm30;
+ y += fm3 * fpm31;
+ z += fm3 * fpm32;
+ w += fm3 * fpm33;
+
+ fm0 = m1[2];
+ fm1 = m1[6];
+ fm2 = m1[10];
+ fm3 = m1[14];
+
+ m[1] = x;
+ m[5] = y;
+ m[9] = z;
+ m[13] = w;
+
+ x = fm0 * fpm00;
+ y = fm0 * fpm01;
+ z = fm0 * fpm02;
+ w = fm0 * fpm03;
+
+ x += fm1 * fpm10;
+ y += fm1 * fpm11;
+ z += fm1 * fpm12;
+ w += fm1 * fpm13;
+
+ x += fm2 * fpm20;
+ y += fm2 * fpm21;
+ z += fm2 * fpm22;
+ w += fm2 * fpm23;
+
+ x += fm3 * fpm30;
+ y += fm3 * fpm31;
+ z += fm3 * fpm32;
+ w += fm3 * fpm33;
+
+ fm0 = m1[3];
+ fm1 = m1[7];
+ fm2 = m1[11];
+ fm3 = m1[15];
+
+ m[2] = x;
+ m[6] = y;
+ m[10] = z;
+ m[14] = w;
+
+ x = fm0 * fpm00;
+ y = fm0 * fpm01;
+ z = fm0 * fpm02;
+ w = fm0 * fpm03;
+
+ x += fm1 * fpm10;
+ y += fm1 * fpm11;
+ z += fm1 * fpm12;
+ w += fm1 * fpm13;
+
+ x += fm2 * fpm20;
+ y += fm2 * fpm21;
+ z += fm2 * fpm22;
+ w += fm2 * fpm23;
+
+ x += fm3 * fpm30;
+ y += fm3 * fpm31;
+ z += fm3 * fpm32;
+ w += fm3 * fpm33;
+
+ m[3] = x;
+ m[7] = y;
+ m[11] = z;
+ m[15] = w;
+
+ return SINGLEO_ERROR_NONE;
+}
+
+int matrix_identity(float *m)
+{
+ if (m == NULL) {
+ SINGLEO_LOGE("m is NULL");
+ return SINGLEO_ERROR_EPERM;
+ }
+
+ m[0] = 1.0f;
+ m[4] = 0.0f;
+ m[8] = 0.0f;
+ m[12] = 0.0f;
+ m[1] = 0.0f;
+ m[5] = 1.0f;
+ m[9] = 0.0f;
+ m[13] = 0.0f;
+ m[2] = 0.0f;
+ m[6] = 0.0f;
+ m[10] = 1.0f;
+ m[14] = 0.0f;
+ m[3] = 0.0f;
+ m[7] = 0.0f;
+ m[11] = 0.0f;
+ m[15] = 1.0f;
+
+ return SINGLEO_ERROR_NONE;
+}
+
+void matrix_copy(float *d, float *s)
+{
+ memcpy(d, s, sizeof(float) * 16);
+}
+
+void matrix_transpose(float *m)
+{
+ float m01, m02, m03;
+ float m04, m06, m07;
+ float m08, m09, m11;
+ float m12, m13, m14;
+
+ ;
+ m04 = m[4];
+ m08 = m[8];
+ m12 = m[12];
+ m01 = m[1];
+ m09 = m[9];
+ m13 = m[13];
+ m02 = m[2];
+ m06 = m[6];
+ m14 = m[14];
+ m03 = m[3];
+ m07 = m[7];
+ m11 = m[11];
+
+ /*m[ 0] = m00;*/
+ m[1] = m04;
+ m[2] = m08;
+ m[3] = m12;
+ m[4] = m01;
+ /*m[ 5] = m05;*/
+ m[6] = m09;
+ m[7] = m13;
+ m[8] = m02;
+ m[9] = m06;
+ /*m[10] = m10;*/
+ m[11] = m14;
+ m[12] = m03;
+ m[13] = m07;
+ m[14] = m11;
+ /*m[15] = m15;*/
+}
+
+void matrix_invert(float *m)
+{
+ float m00, m01, m02, m03;
+ float m04, m05, m06, m07;
+ float m08, m09, m10, m11;
+ float m12, m13, m14, m15;
+ float W00, W04, W08, W12;
+ float W01, W05, W09, W13;
+ float W02, W06, W10, W14;
+ float W03, W07, W11, W15;
+ float det, invdet;
+
+ m00 = m[0];
+ m04 = m[4];
+ m08 = m[8];
+ m12 = m[12];
+ m01 = m[1];
+ m05 = m[5];
+ m09 = m[9];
+ m13 = m[13];
+ m02 = m[2];
+ m06 = m[6];
+ m10 = m[10];
+ m14 = m[14];
+ m03 = m[3];
+ m07 = m[7];
+ m11 = m[11];
+ m15 = m[15];
+
+ if (m03 == 0.0f && m07 == 0.0f && m11 == 0.0f && m15 == 1.0f) {
+ W00 = m05 * m10 - m09 * m06;
+ W04 = -(m01 * m10 - m09 * m02);
+ W08 = m01 * m06 - m05 * m02;
+
+ det = m00 * W00 + m04 * W04 + m08 * W08;
+
+ if (det == 0.0f) {
+ return;
+ }
+ invdet = 1.0f / det;
+
+ W01 = -(m04 * m10 - m08 * m06);
+ W05 = m00 * m10 - m08 * m02;
+ W09 = -(m00 * m06 - m04 * m02);
+
+ W02 = m04 * m09 - m08 * m05;
+ W06 = -(m00 * m09 - m08 * m01);
+ W10 = m00 * m05 - m04 * m01;
+
+ W03 = -(W00 * m12 + W01 * m13 + W02 * m14);
+ W07 = -(W04 * m12 + W05 * m13 + W06 * m14);
+ W11 = -(W08 * m12 + W09 * m13 + W10 * m14);
+
+ /* M^-1[ij] = invdet * M[ji] */
+ m[0] = W00 * invdet;
+ m[4] = W01 * invdet;
+ m[8] = W02 * invdet;
+ m[12] = W03 * invdet;
+
+ m[1] = W04 * invdet;
+ m[5] = W05 * invdet;
+ m[9] = W06 * invdet;
+ m[13] = W07 * invdet;
+
+ m[2] = W08 * invdet;
+ m[6] = W09 * invdet;
+ m[10] = W10 * invdet;
+ m[14] = W11 * invdet;
+
+ m[3] = 0.0f;
+ m[7] = 0.0f;
+ m[11] = 0.0f;
+ m[15] = 1.0f;
+ } else {
+ W00 = (m05 * (m10 * m15 - m14 * m11)) + (m09 * (m14 * m07 - m06 * m15)) + (m13 * (m06 * m11 - m10 * m07));
+ W01 = (m09 * (m14 * m03 - m02 * m15)) + (m13 * (m02 * m11 - m10 * m03)) + (m01 * (m10 * m15 - m14 * m11));
+ W02 = (m13 * (m02 * m07 - m06 * m03)) + (m01 * (m06 * m15 - m14 * m07)) + (m05 * (m14 * m03 - m02 * m15));
+ W03 = (m01 * (m06 * m11 - m10 * m07)) + (m05 * (m10 * m03 - m02 * m11)) + (m09 * (m02 * m07 - m06 * m03));
+ W04 = (m06 * (m11 * m12 - m15 * m08)) + (m10 * (m15 * m04 - m07 * m12)) + (m14 * (m07 * m08 - m11 * m04));
+ W05 = (m10 * (m15 * m00 - m03 * m12)) + (m14 * (m03 * m08 - m11 * m00)) + (m02 * (m11 * m12 - m15 * m08));
+ W06 = (m14 * (m03 * m04 - m07 * m00)) + (m02 * (m07 * m12 - m15 * m04)) + (m06 * (m15 * m00 - m03 * m12));
+ W07 = (m02 * (m07 * m08 - m11 * m04)) + (m06 * (m11 * m00 - m03 * m08)) + (m10 * (m03 * m04 - m07 * m00));
+ W08 = (m07 * (m08 * m13 - m12 * m09)) + (m11 * (m12 * m05 - m04 * m13)) + (m15 * (m04 * m09 - m08 * m05));
+ W09 = (m11 * (m12 * m01 - m00 * m13)) + (m15 * (m00 * m09 - m08 * m01)) + (m03 * (m08 * m13 - m12 * m09));
+ W10 = (m15 * (m00 * m05 - m04 * m01)) + (m03 * (m04 * m13 - m12 * m05)) + (m07 * (m12 * m01 - m00 * m13));
+ W11 = (m03 * (m04 * m09 - m08 * m05)) + (m07 * (m08 * m01 - m00 * m09)) + (m11 * (m00 * m05 - m04 * m01));
+ W12 = (m04 * (m09 * m14 - m13 * m10)) + (m08 * (m13 * m06 - m05 * m14)) + (m12 * (m05 * m10 - m09 * m06));
+ W13 = (m08 * (m13 * m02 - m01 * m14)) + (m12 * (m01 * m10 - m09 * m02)) + (m00 * (m09 * m14 - m13 * m10));
+ W14 = (m12 * (m01 * m06 - m05 * m02)) + (m00 * (m05 * m14 - m13 * m06)) + (m04 * (m13 * m02 - m01 * m14));
+ W15 = (m00 * (m05 * m10 - m09 * m06)) + (m04 * (m09 * m02 - m01 * m10)) + (m08 * (m01 * m06 - m05 * m02));
+
+ det = W00 * m00 - W01 * m04 + W02 * m08 - W03 * m12;
+
+ if (det == 0.0f) {
+ return;
+ }
+ invdet = 1.0f / det;
+
+ m[0] = W00 * invdet;
+ m[1] = -W01 * invdet;
+ m[2] = W02 * invdet;
+ m[3] = -W03 * invdet;
+ m[4] = -W04 * invdet;
+ m[5] = W05 * invdet;
+ m[6] = -W06 * invdet;
+ m[7] = W07 * invdet;
+ m[8] = W08 * invdet;
+ m[9] = -W09 * invdet;
+ m[10] = W10 * invdet;
+ m[11] = -W11 * invdet;
+ m[12] = -W12 * invdet;
+ m[13] = W13 * invdet;
+ m[14] = -W14 * invdet;
+ m[15] = W15 * invdet;
+ }
+}
+
+void matrix_proj_perspective(float *mat, float fovy, float aspect, float znear, float zfar)
+{
+ float a, b, c, d, f;
+
+ memset(mat, 0x0, sizeof(float) * 16);
+
+ f = (float) (cos(2.0f * 3.14f * (fovy / 2.0f) / 360.0f) / sin(2.0f * 3.14f * (fovy / 2.0f) / 360.0f));
+ a = f / aspect; /* a = f/aspect */
+ b = f; /* b = f */
+ c = (zfar + znear) / (znear - zfar); /* c = (far+near)/(near-far) */
+ d = (2.0f * zfar * znear) / (znear - zfar); /* d = (2*far*near)/(near-far) */
+
+ mat[0] = a;
+ mat[5] = b;
+ mat[10] = c;
+ mat[11] = -1.0f;
+ mat[14] = d;
+}
+
+/* lpR = lpP * lpQ */
+void quaternion_mult(float *lpR, float *lpP, float *lpQ)
+{
+ float pw, px, py, pz;
+ float qw, qx, qy, qz;
+
+ pw = lpP[0];
+ px = lpP[1];
+ py = lpP[2];
+ pz = lpP[3];
+ qw = lpQ[0];
+ qx = lpQ[1];
+ qy = lpQ[2];
+ qz = lpQ[3];
+
+ lpR[0] = pw * qw - px * qx - py * qy - pz * qz;
+ lpR[1] = pw * qx + px * qw + py * qz - pz * qy;
+ lpR[2] = pw * qy - px * qz + py * qw + pz * qx;
+ lpR[3] = pw * qz + px * qy - py * qx + pz * qw;
+}
+
+void quaternion_to_matrix(float *lpM, float *lpQ)
+{
+ float qw, qx, qy, qz;
+ float x2, y2, z2;
+ float xy, yz, zx;
+ float wx, wy, wz;
+
+ qw = lpQ[0];
+ qx = lpQ[1];
+ qy = lpQ[2];
+ qz = lpQ[3];
+
+ x2 = 2.0f * qx * qx;
+ y2 = 2.0f * qy * qy;
+ z2 = 2.0f * qz * qz;
+
+ xy = 2.0f * qx * qy;
+ yz = 2.0f * qy * qz;
+ zx = 2.0f * qz * qx;
+
+ wx = 2.0f * qw * qx;
+ wy = 2.0f * qw * qy;
+ wz = 2.0f * qw * qz;
+
+ lpM[0] = 1.0f - y2 - z2;
+ lpM[4] = xy - wz;
+ lpM[8] = zx + wy;
+ lpM[12] = 0.0f;
+
+ lpM[1] = xy + wz;
+ lpM[5] = 1.0f - z2 - x2;
+ lpM[9] = yz - wx;
+ lpM[13] = 0.0f;
+
+ lpM[2] = zx - wy;
+ lpM[6] = yz + wx;
+ lpM[10] = 1.0f - x2 - y2;
+ lpM[14] = 0.0f;
+
+ lpM[3] = lpM[7] = lpM[11] = 0.0f;
+ lpM[15] = 1.0f;
+}
+
+void quaternion_rotate(float *lpQ, float rad, float ax, float ay, float az)
+{
+ float hrad = 0.5f * rad;
+ float s = sinf(hrad);
+
+ lpQ[0] = cosf(hrad); /* w */
+ lpQ[1] = s * ax; /* x */
+ lpQ[2] = s * ay; /* y */
+ lpQ[3] = s * az; /* z */
+}
+
+void quaternion_identity(float *lpQ)
+{
+ lpQ[0] = 1.0f; /* w */
+ lpQ[1] = 0.0f; /* x */
+ lpQ[2] = 0.0f; /* y */
+ lpQ[3] = 0.0f; /* z */
+}
+
+void quaternion_copy(float *lpTo, float *lpFrom)
+{
+ lpTo[0] = lpFrom[0]; /* w */
+ lpTo[1] = lpFrom[1]; /* x */
+ lpTo[2] = lpFrom[2]; /* y */
+ lpTo[3] = lpFrom[3]; /* z */
+}
+
+float vec3_normalize(float *v)
+{
+ float len, invLen;
+
+ len = vec3_length(v);
+ if (len == 0.0f)
+ return 0.0f;
+
+ invLen = 1.0f / len;
+
+ v[0] *= invLen;
+ v[1] *= invLen;
+ v[2] *= invLen;
+
+ return len;
+}
--- /dev/null
+/**
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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 <EGL/egl.h>
+#include <EGL/eglext.h>
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+#include <cstring>
+#include "SingleoLog.h"
+#include "singleo_error.h"
+
+#include "singleo_util_matrix.h"
+#include "singleo_util_render_2d.h"
+#include "singleo_util_shader.h"
+#include "singleo_util_winsys.h"
+
+static char vs_fill[] = " \n\
+ \n\
+attribute vec4 a_Vertex; \n\
+uniform mat4 u_PMVMatrix; \n\
+void main(void) \n\
+{ \n\
+ gl_Position = u_PMVMatrix * a_Vertex; \n\
+} ";
+
+static char fs_fill[] = " \n\
+ \n\
+precision mediump float; \n\
+uniform vec4 u_Color; \n\
+ \n\
+void main(void) \n\
+{ \n\
+ gl_FragColor = u_Color; \n\
+} ";
+
+static char vs_tex[] = " \n\
+attribute vec4 a_Vertex; \n\
+attribute vec2 a_TexCoord; \n\
+varying vec2 v_TexCoord; \n\
+uniform mat4 u_PMVMatrix; \n\
+ \n\
+void main(void) \n\
+{ \n\
+ gl_Position = u_PMVMatrix * a_Vertex; \n\
+ v_TexCoord = a_TexCoord; \n\
+} \n";
+
+static char fs_tex[] = " \n\
+precision mediump float; \n\
+varying vec2 v_TexCoord; \n\
+uniform sampler2D u_sampler; \n\
+uniform vec4 u_Color; \n\
+ \n\
+void main(void) \n\
+{ \n\
+ gl_FragColor = texture2D(u_sampler, v_TexCoord); \n\
+ gl_FragColor *= u_Color; \n\
+} \n";
+
+static char fs_extex[] = " \n\
+#extension GL_NV_EGL_stream_consumer_external: enable \n\
+#extension GL_OES_EGL_image_external : enable \n\
+precision mediump float; \n\
+varying vec2 v_TexCoord; \n\
+uniform samplerExternalOES u_sampler; \n\
+uniform vec4 u_Color; \n\
+ \n\
+void main(void) \n\
+{ \n\
+ gl_FragColor = texture2D(u_sampler, v_TexCoord); \n\
+ gl_FragColor *= u_Color; \n\
+} \n";
+
+static char fs_cmap_jet[] = " \n\
+precision mediump float; \n\
+varying vec2 v_TexCoord; \n\
+uniform sampler2D u_sampler; \n\
+uniform vec4 u_Color; \n\
+ \n\
+float cmap_jet_red(float x) \n\
+{ \n\
+ if (x < 0.7) { \n\
+ return 4.0 * x - 1.5; \n\
+ } else { \n\
+ return -4.0 * x + 4.5; \n\
+ } \n\
+} \n\
+ \n\
+float cmap_jet_green(float x) \n\
+{ \n\
+ if (x < 0.5) { \n\
+ return 4.0 * x - 0.5; \n\
+ } else { \n\
+ return -4.0 * x + 3.5; \n\
+ } \n\
+} \n\
+ \n\
+float cmap_jet_blue(float x) \n\
+{ \n\
+ if (x < 0.3) { \n\
+ return 4.0 * x + 0.5; \n\
+ } else { \n\
+ return -4.0 * x + 2.5; \n\
+ } \n\
+} \n\
+ \n\
+vec4 colormap_jet(float x) \n\
+{ \n\
+ float r = clamp(cmap_jet_red(x), 0.0, 1.0); \n\
+ float g = clamp(cmap_jet_green(x), 0.0, 1.0); \n\
+ float b = clamp(cmap_jet_blue(x), 0.0, 1.0); \n\
+ return vec4(r, g, b, 1.0); \n\
+} \n\
+ \n\
+void main(void) \n\
+{ \n\
+ vec4 src_col = texture2D(u_sampler, v_TexCoord); \n\
+ gl_FragColor = colormap_jet(src_col.r); \n\
+ gl_FragColor *= u_Color; \n\
+} \n";
+
+static char vs_tex_yuyv[] = " \n\
+attribute vec4 a_Vertex; \n\
+attribute vec2 a_TexCoord; \n\
+varying vec2 v_TexCoord; \n\
+varying vec2 v_TexCoordPix; \n\
+uniform mat4 u_PMVMatrix; \n\
+uniform vec2 u_TexDim; \n\
+ \n\
+void main(void) \n\
+{ \n\
+ gl_Position = u_PMVMatrix * a_Vertex; \n\
+ v_TexCoord = a_TexCoord; \n\
+ v_TexCoordPix = a_TexCoord * u_TexDim; \n\
+} \n";
+
+static char fs_tex_yuyv[] = " \n\
+precision mediump float; \n\
+varying vec2 v_TexCoord; \n\
+varying vec2 v_TexCoordPix; \n\
+uniform sampler2D u_sampler; \n\
+uniform vec4 u_Color; \n\
+ \n\
+void main(void) \n\
+{ \n\
+ vec2 evenodd = mod(v_TexCoordPix, 2.0); \n\
+ vec3 yuv, rgb; \n\
+ vec4 texcol = texture2D(u_sampler, v_TexCoord); \n\
+ if (evenodd.x < 1.0) { \n\
+ yuv.r = texcol.r; /* Y */ \n\
+ yuv.g = texcol.g - 0.5; /* U */ \n\
+ yuv.b = texcol.a - 0.5; /* V */ \n\
+ } else { \n\
+ yuv.r = texcol.b; /* Y */ \n\
+ yuv.g = texcol.g - 0.5; /* U */ \n\
+ yuv.b = texcol.a - 0.5; /* V */ \n\
+ } \n\
+ \n\
+ rgb = mat3 ( 1, 1, 1, \n\
+ 0, -0.34413, 1.772, \n\
+ 1.402, -0.71414, 0) * yuv; \n\
+ gl_FragColor = vec4(rgb, 1.0); \n\
+ gl_FragColor *= u_Color; \n\
+} \n";
+
+#define SHADER_NUM 5
+static char *s_shader[SHADER_NUM * 2] = { vs_fill, fs_fill, vs_tex, fs_tex, vs_tex,
+ fs_extex, vs_tex, fs_cmap_jet, vs_tex_yuyv, fs_tex_yuyv };
+
+static shader_obj_t s_sobj[SHADER_NUM];
+static int s_loc_mtx[SHADER_NUM];
+static int s_loc_color[SHADER_NUM];
+static int s_loc_texdim[SHADER_NUM];
+
+static EGLDisplay s_dpy;
+static EGLSurface s_sfc;
+static EGLContext s_ctx;
+
+GLuint create_2d_texture(void *imgbuf, int width, int height)
+{
+ GLuint texid;
+
+ glGenTextures(1, &texid);
+ glBindTexture(GL_TEXTURE_2D, texid);
+
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
+
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, imgbuf);
+
+ return texid;
+}
+
+static EGLConfig find_egl_config(int r, int g, int b, int a, int d, int s, int ms, int sfc_type, int ver)
+{
+ EGLint num_conf, i;
+ EGLBoolean ret;
+ EGLConfig conf = 0, *conf_array = NULL;
+
+ EGLint config_attribs[] = { EGL_RED_SIZE,
+ 8,
+ EGL_GREEN_SIZE,
+ 8,
+ EGL_BLUE_SIZE,
+ 8,
+ EGL_ALPHA_SIZE,
+ 8,
+ EGL_DEPTH_SIZE,
+ EGL_DONT_CARE,
+ EGL_STENCIL_SIZE,
+ EGL_DONT_CARE,
+ EGL_SAMPLES,
+ EGL_DONT_CARE,
+ EGL_SURFACE_TYPE,
+ EGL_WINDOW_BIT,
+ EGL_RENDERABLE_TYPE,
+ EGL_OPENGL_ES2_BIT,
+ EGL_NONE };
+
+ config_attribs[1] = r;
+ config_attribs[3] = g;
+ config_attribs[5] = b;
+ config_attribs[7] = a;
+ config_attribs[9] = d;
+ config_attribs[11] = s;
+ config_attribs[13] = ms;
+ config_attribs[15] = sfc_type;
+
+ switch (ver) {
+ case 1:
+ case 2:
+ config_attribs[17] = EGL_OPENGL_ES2_BIT;
+ break;
+ default:
+ SINGLEO_LOGE("Invalid version");
+ goto exit;
+ }
+
+ ret = eglChooseConfig(s_dpy, config_attribs, NULL, 0, &num_conf);
+ if (ret != EGL_TRUE || num_conf == 0) {
+ SINGLEO_LOGE("Failed to call eglChooseConfig");
+ goto exit;
+ }
+
+ conf_array = (EGLConfig *) calloc(num_conf, sizeof(EGLConfig));
+ if (conf_array == NULL) {
+ SINGLEO_LOGE("EGLConfig is NULL");
+ goto exit;
+ }
+
+ ret = eglChooseConfig(s_dpy, config_attribs, conf_array, num_conf, &num_conf);
+ if (ret != EGL_TRUE) {
+ SINGLEO_LOGE("Failed to call eglChooseConfig");
+ goto exit;
+ }
+
+ for (i = 0; i < num_conf; i++) {
+ EGLint id, rsize, gsize, bsize, asize;
+
+ eglGetConfigAttrib(s_dpy, conf_array[i], EGL_CONFIG_ID, &id);
+ eglGetConfigAttrib(s_dpy, conf_array[i], EGL_RED_SIZE, &rsize);
+ eglGetConfigAttrib(s_dpy, conf_array[i], EGL_GREEN_SIZE, &gsize);
+ eglGetConfigAttrib(s_dpy, conf_array[i], EGL_BLUE_SIZE, &bsize);
+ eglGetConfigAttrib(s_dpy, conf_array[i], EGL_ALPHA_SIZE, &asize);
+
+ if (rsize == r && gsize == g && bsize == b && asize == a) {
+ conf = conf_array[i];
+ break;
+ }
+ }
+
+ if (i == num_conf) {
+ SINGLEO_LOGE("Index is out of range");
+ goto exit;
+ }
+
+exit:
+ free(conf_array);
+
+ return conf;
+}
+
+int egl_init_with_platform_window_surface(int gles_version, int depth_size, int stencil_size, int sample_num, int win_w,
+ int win_h)
+{
+ void *native_dpy, *native_win;
+ EGLint major, minor;
+ EGLConfig config;
+ EGLBoolean ret;
+ EGLint context_attribs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE };
+ EGLint sfc_attr[] = { EGL_NONE };
+
+ native_dpy = winsys_init_native_display();
+ if ((native_dpy != EGL_DEFAULT_DISPLAY) && (native_dpy == NULL)) {
+ SINGLEO_LOGE("native_dpy is not valid");
+ return SINGLEO_ERROR_EPERM;
+ }
+
+ s_dpy = eglGetDisplay(native_dpy);
+ if (s_dpy == EGL_NO_DISPLAY) {
+ SINGLEO_LOGE("s_dpy is EGL_NO_DISPLAY");
+ return SINGLEO_ERROR_EPERM;
+ }
+
+ ret = eglInitialize(s_dpy, &major, &minor);
+ if (ret != EGL_TRUE) {
+ SINGLEO_LOGE("Failed to initialize egl");
+ return SINGLEO_ERROR_EPERM;
+ }
+
+ eglBindAPI(EGL_OPENGL_ES_API);
+
+ config = find_egl_config(8, 8, 8, 8, depth_size, stencil_size, sample_num, EGL_WINDOW_BIT, gles_version);
+ if (config == NULL) {
+ SINGLEO_LOGE("Failed to find egl configuration");
+ return SINGLEO_ERROR_EPERM;
+ }
+
+ native_win = winsys_init_native_window(s_dpy, win_w, win_h);
+ if (native_win == NULL) {
+ SINGLEO_LOGE("window is NULL");
+ return SINGLEO_ERROR_EPERM;
+ }
+
+ s_sfc = eglCreateWindowSurface(s_dpy, config, (NativeWindowType) native_win, sfc_attr);
+ if (s_sfc == EGL_NO_SURFACE) {
+ SINGLEO_LOGE("s_sfc is EGL_NO_SURFACE");
+ return SINGLEO_ERROR_EPERM;
+ }
+
+ switch (gles_version) {
+ case 1:
+ context_attribs[1] = 1;
+ break;
+ case 2:
+ context_attribs[1] = 2;
+ break;
+ case 3:
+ context_attribs[1] = 3;
+ break;
+ default:
+ SINGLEO_LOGE("Invalid gles version");
+ return SINGLEO_ERROR_EPERM;
+ }
+
+ s_ctx = eglCreateContext(s_dpy, config, EGL_NO_CONTEXT, context_attribs);
+ if (s_ctx == EGL_NO_CONTEXT) {
+ SINGLEO_LOGE("s_ctx is EGL_NO_CONTEXT");
+ return SINGLEO_ERROR_EPERM;
+ }
+
+ ret = eglMakeCurrent(s_dpy, s_sfc, s_sfc, s_ctx);
+ if (ret != EGL_TRUE) {
+ SINGLEO_LOGE("Failed to call eglMakeCurrent()");
+ return SINGLEO_ERROR_EPERM;
+ }
+
+ return SINGLEO_ERROR_NONE;
+}
+
+int egl_swap()
+{
+ EGLBoolean ret;
+
+ ret = eglSwapBuffers(s_dpy, s_sfc);
+ if (ret != EGL_TRUE) {
+ SINGLEO_LOGE("Failed to call eglSwapBuffers()");
+ return SINGLEO_ERROR_EPERM;
+ }
+
+ return SINGLEO_ERROR_NONE;
+}
+
+static float varray[] = { 0.0, 0.0, 0.0, 1.0, 1.0, 0.0, 1.0, 1.0 };
+
+static float tarray[] = { 0.0, 0.0, 0.0, 1.0, 1.0, 0.0, 1.0, 1.0 };
+
+static float tarray2[] = { 0.0, 1.0, 0.0, 0.0, 1.0, 1.0, 1.0, 0.0 };
+
+static float s_matprj[16];
+static void set_projection_matrix(int w, int h)
+{
+ float mat_proj[] = {
+ 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -1.0f, 1.0f, 0.0f, 1.0f
+ };
+
+ mat_proj[0] = 2.0f / (float) w;
+ mat_proj[5] = -2.0f / (float) h;
+
+ memcpy(s_matprj, mat_proj, 16 * sizeof(float));
+}
+
+int init_2d_renderer(int w, int h)
+{
+ int i;
+
+ for (i = 0; i < SHADER_NUM; i++) {
+ if (generate_shader(&s_sobj[i], s_shader[2 * i], s_shader[2 * i + 1]) < 0) {
+ SINGLEO_LOGE("%s(%d)", __FILE__, __LINE__);
+ return SINGLEO_ERROR_EPERM;
+ }
+
+ s_loc_mtx[i] = glGetUniformLocation(s_sobj[i].program, "u_PMVMatrix");
+ s_loc_color[i] = glGetUniformLocation(s_sobj[i].program, "u_Color");
+ s_loc_texdim[i] = glGetUniformLocation(s_sobj[i].program, "u_TexDim");
+ }
+
+ set_projection_matrix(w, h);
+
+ return SINGLEO_ERROR_NONE;
+}
+
+typedef struct _texparam {
+ int textype;
+ int texid;
+ int x, y, w, h;
+ int texw, texh;
+ int upsidedown;
+ float color[4];
+ float rot;
+ float px, py;
+ int blendfunc_en;
+ unsigned int blendfunc[4];
+ float *user_texcoord;
+} texparam_t;
+
+static void draw_2d_texture_in(texparam_t *tparam)
+{
+ int ttype = tparam->textype;
+ int texid = tparam->texid;
+ float x = tparam->x;
+ float y = tparam->y;
+ float w = tparam->w;
+ float h = tparam->h;
+ float rot = tparam->rot;
+ shader_obj_t *sobj = &s_sobj[ttype];
+ float matrix[16];
+ float *uv = tarray;
+
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+
+ glUseProgram(sobj->program);
+ glUniform1i(sobj->loc_tex, 0);
+
+ switch (ttype) {
+ case 0: /* fill */
+ break;
+ case 1: /* tex */
+ case 4: /* tex_yuyv */
+ glBindTexture(GL_TEXTURE_2D, texid);
+ uv = tparam->upsidedown ? tarray2 : tarray;
+ break;
+ case 2: /* tex_extex */
+ glBindTexture(GL_TEXTURE_EXTERNAL_OES, texid);
+ uv = tparam->upsidedown ? tarray : tarray2;
+ break;
+ default:
+ break;
+ }
+
+ if (tparam->user_texcoord)
+ uv = tparam->user_texcoord;
+
+ if (sobj->loc_uv >= 0) {
+ glEnableVertexAttribArray(sobj->loc_uv);
+ glVertexAttribPointer(sobj->loc_uv, 2, GL_FLOAT, GL_FALSE, 0, uv);
+ }
+
+ glEnable(GL_BLEND);
+
+ if (tparam->blendfunc_en) {
+ glBlendFuncSeparate(tparam->blendfunc[0], tparam->blendfunc[1], tparam->blendfunc[2], tparam->blendfunc[3]);
+ } else {
+ glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+ }
+
+ if (matrix_identity(matrix) != SINGLEO_ERROR_NONE)
+ SINGLEO_LOGE("Failed to call matrix_identity");
+ if (matrix_translate(matrix, x, y, 0.0f) != SINGLEO_ERROR_NONE)
+ SINGLEO_LOGE("Failed to call matrix_translate");
+
+ if (rot != 0) {
+ float px = tparam->px;
+ float py = tparam->py;
+ if (matrix_translate(matrix, px, py, 0.0f) != SINGLEO_ERROR_NONE)
+ SINGLEO_LOGE("Failed to call matrix_translate");
+
+ if (matrix_rotate(matrix, rot, 0.0f, 0.0f, 1.0f) != SINGLEO_ERROR_NONE)
+ SINGLEO_LOGE("Failed to call matrix_rotate");
+ if (matrix_translate(matrix, -px, -py, 0.0f) != SINGLEO_ERROR_NONE)
+ SINGLEO_LOGE("Failed to call matrix_translate");
+ }
+ if (matrix_scale(matrix, w, h, 1.0f) != SINGLEO_ERROR_NONE)
+ SINGLEO_LOGE("Failed to call matrix_scale");
+ if (matrix_mult(matrix, s_matprj, matrix) != SINGLEO_ERROR_NONE)
+ SINGLEO_LOGE("Failed to call matrix_mult");
+
+ glUniformMatrix4fv(s_loc_mtx[ttype], 1, GL_FALSE, matrix);
+ glUniform4fv(s_loc_color[ttype], 1, tparam->color);
+
+ if (s_loc_texdim[ttype] >= 0) {
+ float texdim[2];
+ texdim[0] = tparam->texw;
+ texdim[1] = tparam->texh;
+ glUniform2fv(s_loc_texdim[ttype], 1, texdim);
+ }
+
+ if (sobj->loc_vtx >= 0) {
+ glEnableVertexAttribArray(sobj->loc_vtx);
+ glVertexAttribPointer(sobj->loc_vtx, 2, GL_FLOAT, GL_FALSE, 0, varray);
+ }
+
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+
+ glDisable(GL_BLEND);
+}
+
+int load_texture(cv::Mat &source, int *lpTexID, int *lpWidth, int *lpHeight)
+{
+ GLuint texid;
+ int width = source.cols;
+ int height = source.rows;
+
+ texid = create_2d_texture(source.data, source.cols, source.rows);
+
+ if (lpTexID)
+ *lpTexID = texid;
+ if (lpWidth)
+ *lpWidth = width;
+ if (lpHeight)
+ *lpHeight = height;
+
+ return SINGLEO_ERROR_NONE;
+}
+
+int draw_2d_texture(texture_2d_t *tex, int x, int y, int w, int h, int upsidedown)
+{
+ texparam_t tparam = { 0 };
+
+ if (tex == NULL) {
+ SINGLEO_LOGE("tex is NULL");
+ return SINGLEO_ERROR_EPERM;
+ }
+
+ tparam.x = x;
+ tparam.y = y;
+ tparam.w = w;
+ tparam.h = h;
+ tparam.texid = tex->texid;
+ tparam.textype = 1;
+ tparam.texw = tex->width;
+ tparam.texh = tex->height;
+ tparam.color[0] = 1.0f;
+ tparam.color[1] = 1.0f;
+ tparam.color[2] = 1.0f;
+ tparam.color[3] = 1.0f;
+ tparam.upsidedown = upsidedown;
+
+ if (tex->format == pixfmt_fourcc('Y', 'U', 'Y', 'V'))
+ tparam.textype = 4;
+
+ draw_2d_texture_in(&tparam);
+
+ return SINGLEO_ERROR_NONE;
+}
--- /dev/null
+/**
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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 "singleo_util_shader.h"
+#include "SingleoLog.h"
+
+GLuint compile_shader_text(GLenum shaderType, const char *text)
+{
+ GLuint shader;
+ GLint stat;
+
+ shader = glCreateShader(shaderType);
+ glShaderSource(shader, 1, (const char **) &text, NULL);
+ glCompileShader(shader);
+
+ glGetShaderiv(shader, GL_COMPILE_STATUS, &stat);
+ if (!stat) {
+ GLsizei len;
+ char *lpBuf;
+
+ glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &len);
+ lpBuf = (char *) malloc(len);
+
+ glGetShaderInfoLog(shader, len, &len, lpBuf);
+ SINGLEO_LOGE("Error: problem compiling shader.");
+ SINGLEO_LOGE("-----------------------------------");
+ SINGLEO_LOGE("%s", lpBuf);
+ SINGLEO_LOGE("-----------------------------------");
+
+ free(lpBuf);
+
+ return 0;
+ }
+
+ return shader;
+}
+
+GLuint link_shaders(GLuint vertShader, GLuint fragShader)
+{
+ GLuint program = glCreateProgram();
+
+ if (fragShader)
+ glAttachShader(program, fragShader);
+ if (vertShader)
+ glAttachShader(program, vertShader);
+
+ glLinkProgram(program);
+
+ {
+ GLint stat;
+ glGetProgramiv(program, GL_LINK_STATUS, &stat);
+ if (!stat) {
+ GLsizei len;
+ char *lpBuf;
+
+ glGetProgramiv(program, GL_INFO_LOG_LENGTH, &len);
+ lpBuf = (char *) malloc(len);
+
+ glGetProgramInfoLog(program, len, &len, lpBuf);
+ SINGLEO_LOGE("Error: problem linking shader.");
+ SINGLEO_LOGE("-----------------------------------");
+ SINGLEO_LOGE("%s", lpBuf);
+ SINGLEO_LOGE("-----------------------------------");
+
+ free(lpBuf);
+
+ return 0;
+ }
+ }
+
+ return program;
+}
+
+int generate_shader(shader_obj_t *sobj, char *str_vs, char *str_fs)
+{
+ GLuint fs, vs, program;
+
+ vs = compile_shader_text(GL_VERTEX_SHADER, str_vs);
+ fs = compile_shader_text(GL_FRAGMENT_SHADER, str_fs);
+ if (vs == 0 || fs == 0) {
+ SINGLEO_LOGE("Failed to compile shader.");
+ return -1;
+ }
+
+ program = link_shaders(vs, fs);
+ if (program == 0) {
+ SINGLEO_LOGE("Failed to link shaders.");
+ return -1;
+ }
+
+ glDeleteShader(vs);
+ glDeleteShader(fs);
+
+ sobj->program = program;
+ sobj->loc_vtx = glGetAttribLocation(program, "a_Vertex");
+ sobj->loc_nrm = glGetAttribLocation(program, "a_Normal");
+ sobj->loc_clr = glGetAttribLocation(program, "a_Color");
+ sobj->loc_uv = glGetAttribLocation(program, "a_TexCoord");
+ sobj->loc_tex = glGetUniformLocation(program, "u_sampler");
+ sobj->loc_mtx = glGetUniformLocation(program, "u_PMVMatrix");
+ sobj->loc_mtx_nrm = glGetUniformLocation(program, "u_NrmMatrix");
+
+ return 0;
+}
--- /dev/null
+/**
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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 <grpcpp/grpcpp.h>
+
+#include <opencv2/core.hpp>
+#include <opencv2/imgcodecs.hpp>
+#include <opencv2/imgproc/imgproc.hpp>
+#include <opencv2/opencv.hpp>
+
+#include "SingleoLog.h"
+#include "singleo_error.h"
+#include "singleo_util_visualizer_2d.h"
+#include "singleo_util_visualizer_rd.grpc.pb.h"
+
+static int win_w = 1600;
+static int win_h = 900;
+static bool initialized = false;
+
+class ImageClientImpl
+{
+public:
+ ImageClientImpl(std::shared_ptr<grpc::Channel> channel) : stub_(NLImageService::NewStub(channel))
+ {}
+
+ void DrawImage(cv::Mat &source)
+ {
+ cv::cvtColor(source, source, cv::COLOR_RGBA2BGR);
+
+ std::vector<int> qualityType;
+ std::vector<uchar> buff;
+ qualityType.push_back(cv::IMWRITE_JPEG_QUALITY);
+ qualityType.push_back(90);
+ cv::imencode(".jpg", source, buff, qualityType);
+
+ NLImageDrawRequest *request = new NLImageDrawRequest;
+ NLImage tmp;
+ unsigned long length = buff.size();
+
+ std::string str(buff.begin(), buff.end());
+ std::string NLstring(str);
+
+ tmp.set_length(length);
+ tmp.set_data(NLstring);
+
+ request->mutable_image()->set_data(tmp.data());
+ request->mutable_image()->set_length(tmp.length());
+
+ ::Empty reply;
+
+ grpc::ClientContext context;
+ grpc::Status status = stub_->DrawImage(&context, *request, &reply);
+ }
+
+private:
+ std::unique_ptr<NLImageService::Stub> stub_;
+};
+
+static int create_window_surface()
+{
+ int err = SINGLEO_ERROR_NONE;
+ err = egl_init_with_platform_window_surface(2, 8, 0, 0, win_w, win_h);
+ if (SINGLEO_ERROR_NONE != err) {
+ SINGLEO_LOGE("egl_init_with_platform_window_surface: %i", err);
+ return SINGLEO_ERROR_EPERM;
+ }
+ err = init_2d_renderer(win_w, win_h);
+ if (SINGLEO_ERROR_NONE != err) {
+ SINGLEO_LOGE("init_2d_renderer: %i", err);
+ return SINGLEO_ERROR_EPERM;
+ }
+ glClearColor(0.f, 0.f, 0.f, 1.0f);
+ glClear(GL_COLOR_BUFFER_BIT);
+ glViewport(0, 0, win_w, win_h);
+
+ return SINGLEO_ERROR_NONE;
+}
+
+int singleo_util_visualizer_2d(cv::Mat &source, const char *url)
+{
+ int texid;
+ int texw, texh;
+ int err = SINGLEO_ERROR_NONE;
+ texture_2d_t captex = { 0 };
+
+ if (url != NULL) { // remote display
+ ImageClientImpl imageChannel(grpc::CreateChannel(url, grpc::InsecureChannelCredentials()));
+ imageChannel.DrawImage(source);
+
+ return SINGLEO_ERROR_NONE;
+ }
+
+ // target display
+ if (!initialized) {
+ if (create_window_surface() != SINGLEO_ERROR_NONE) {
+ return SINGLEO_ERROR_EPERM;
+ }
+ initialized = true;
+ }
+
+ err = load_texture(source, &texid, &texw, &texh);
+ if (SINGLEO_ERROR_NONE != err) {
+ SINGLEO_LOGE("load_texture: %i", err);
+ return SINGLEO_ERROR_EPERM;
+ }
+
+ captex.texid = texid;
+ captex.width = texw;
+ captex.height = texh;
+ captex.format = pixfmt_fourcc('R', 'G', 'B', 'A');
+
+ float scale = (float) win_h / (float) texh;
+
+ err = draw_2d_texture(&captex, (win_w - scale * texw) * 0.5f, 0, scale * texw, scale * texh, 0);
+ if (SINGLEO_ERROR_NONE != err) {
+ SINGLEO_LOGE("draw_2d_texture_ex: %i", err);
+ goto out;
+ }
+
+ err = egl_swap();
+ if (SINGLEO_ERROR_NONE != err) {
+ SINGLEO_LOGE("egl_swap: %i", err);
+ }
+
+out:
+ glDeleteTextures(1, reinterpret_cast<GLuint *>(&texid));
+ return err;
+}
--- /dev/null
+/**
+ * Copyright(c) 2022 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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 "SingleoLog.h"
+#include "singleo_util_winsys.h"
+#include "wayland-client.h"
+#include "wayland-egl.h"
+#include <signal.h>
+#include <string.h>
+#include <sys/mman.h>
+
+#define UNUSED(x) (void) (x)
+
+struct Display s_display;
+struct Window s_window;
+
+static void handle_ping(void *data, struct wl_shell_surface *wlShellSurface, uint32_t serial)
+{
+ UNUSED(data);
+
+ wl_shell_surface_pong(wlShellSurface, serial);
+}
+
+static void handle_configure(void *data, struct wl_shell_surface *shell_surface, uint32_t edges, int32_t width,
+ int32_t height)
+{
+ struct Window *window = (struct Window *) data;
+ UNUSED(data);
+ UNUSED(shell_surface);
+ UNUSED(edges);
+
+ if (window->wlEGLNativeWindow) {
+ wl_egl_window_resize(window->wlEGLNativeWindow, width, height, 0, 0);
+ }
+
+ window->geometry.width = width;
+ window->geometry.height = height;
+}
+
+static const struct wl_shell_surface_listener shell_surface_listener = { handle_ping, handle_configure, NULL };
+
+static void registry_handle_global(void *data, struct wl_registry *registry, uint32_t name, const char *interface,
+ uint32_t version)
+{
+ struct Display *d = (struct Display *) data;
+ UNUSED(version);
+
+ if (strcmp(interface, "wl_compositor") == 0) {
+ d->wlCompositor = (wl_compositor *) wl_registry_bind(registry, name, &wl_compositor_interface, 1);
+ } else if (strcmp(interface, "wl_shell") == 0) {
+ d->wlShell = (wl_shell *) wl_registry_bind(registry, name, &wl_shell_interface, 1);
+ }
+}
+
+static void registry_handle_global_remove(void *data, struct wl_registry *registry, uint32_t name)
+{
+ UNUSED(data);
+ UNUSED(registry);
+ UNUSED(name);
+}
+
+static const struct wl_registry_listener registry_listener = { registry_handle_global, registry_handle_global_remove };
+
+void *winsys_init_native_display(void)
+{
+ memset(&s_display, 0, sizeof(s_display));
+
+ s_display.wlDisplay = wl_display_connect(NULL);
+ if (s_display.wlDisplay == NULL) {
+ SINGLEO_LOGE("%s(%d)", __FILE__, __LINE__);
+ return NULL;
+ }
+
+ s_display.wlRegistry = wl_display_get_registry(s_display.wlDisplay);
+ if (s_display.wlRegistry == NULL) {
+ SINGLEO_LOGE("%s(%d)", __FILE__, __LINE__);
+ return NULL;
+ }
+
+ wl_registry_add_listener(s_display.wlRegistry, ®istry_listener, &s_display);
+
+ wl_display_dispatch(s_display.wlDisplay);
+
+ return s_display.wlDisplay;
+}
+
+void *winsys_init_native_window(void *dpy, int win_w, int win_h)
+{
+ UNUSED(dpy);
+ memset(&s_window, 0, sizeof(s_window));
+
+ if (!s_display.wlCompositor || !s_display.wlShell) {
+ SINGLEO_LOGE("window compositor or shell is NULL");
+ return NULL;
+ }
+
+ s_window.wlSurface = wl_compositor_create_surface(s_display.wlCompositor);
+ if (s_window.wlSurface == NULL) {
+ SINGLEO_LOGE("window surface is NULL");
+ return NULL;
+ }
+
+ s_window.wlShellSurface = wl_shell_get_shell_surface(s_display.wlShell, s_window.wlSurface);
+ if (s_window.wlShellSurface == NULL) {
+ SINGLEO_LOGE("window shell surface is NULL");
+ return NULL;
+ }
+
+ wl_shell_surface_add_listener(s_window.wlShellSurface, &shell_surface_listener, &s_window);
+
+ s_window.window_size.width = win_w;
+ s_window.window_size.height = win_h;
+ s_window.display = &s_display;
+
+ s_window.wlEGLNativeWindow = wl_egl_window_create(s_window.wlSurface, win_w, win_h);
+ if (s_window.wlEGLNativeWindow == NULL) {
+ SINGLEO_LOGE("window is NULL");
+ return NULL;
+ }
+
+ return s_window.wlEGLNativeWindow;
+}