aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZong Wei <wei.zong@intel.com>2018-11-23 10:54:02 +0800
committerGitHub <noreply@github.com>2018-11-23 10:54:02 +0800
commitbd416ed4c25d02803eed1ad71ffbaf6915fe92fe (patch)
treea210b12bba2c58ae8edb1ec6741270baedc91853
parent5982c14b8dd63e16cbf41c48ee18845fabc76e07 (diff)
parentf4413ad0cb070d94b4b168bc8d3011b879464b6d (diff)
downloadlibxcam-upstream-master-backup.tar.gz
Merge pull request #593 from zongwave/osg_renderupstream-master-backup
render: add OSG based render to show texture on window * build & install OSG library: $ git clone https://github.com/openscenegraph/OpenSceneGraph.git $ cd OpenSceneGraph/ $ mkdir build && cd build $ cmake \ -DCMAKE_BUILD_TYPE=Release \ -DCMAKE_INSTALL_PREFIX=/usr \ -DOPENGL_PROFILE=GLES2 \ -DOPENGL_gl_LIBRARY=${LIB_MESA_EGL_DIR}/libGLESv2.so \ -DOSG_WINDOWING_SYSTEM=X11 \ -D_OPENTHREADS_ATOMIC_USE_GCC_BUILTINS_EXITCODE=1 \ -DLIB_POSTFIX="" \ -DOSG_CPP_EXCEPTIONS_AVAILABLE=ON \ -DCMAKE_DISABLE_FIND_PACKAGE_CURL=1 \ -DCMAKE_DISABLE_FIND_PACKAGE_FFmpeg=1 \ -DOSG_NOTIFY_DISABLED=ON \ -DOSG_GL_FIXED_FUNCTION_AVAILABLE=OFF \ -DOSG_USE_QT=OFF \ ../ # NOTE: Fill in the ${LIB_MESA_EGL_DIR} - e.g.)/usr/lib/x86_64-linux-gnu/mesa-egl $ make -j8 $ sudo make install * test command line: $ ./test-render-surround-view --module soft --input0 video0.yuv --input1 video1.yuv --input2 video2.yuv --input3 video3.yuv --output output.mp4 --in-w 1280 --in-h 800 --out-w 1920 --out-h 640 --loop 1 Signed-off-by: zongwave <wei.zong@intel.com>
-rw-r--r--configure.ac16
-rw-r--r--modules/Makefile.am7
-rw-r--r--modules/render/Makefile.am56
-rw-r--r--modules/render/render_osg_camera_manipulator.cpp172
-rw-r--r--modules/render/render_osg_camera_manipulator.h123
-rw-r--r--modules/render/render_osg_model.cpp337
-rw-r--r--modules/render/render_osg_model.h123
-rw-r--r--modules/render/render_osg_shader.h93
-rw-r--r--modules/render/render_osg_viewer.cpp121
-rw-r--r--modules/render/render_osg_viewer.h66
-rw-r--r--tests/Makefile.am32
-rw-r--r--tests/test-render-surround-view.cpp595
12 files changed, 1739 insertions, 2 deletions
diff --git a/configure.ac b/configure.ac
index e17c36b..83b35b3 100644
--- a/configure.ac
+++ b/configure.ac
@@ -89,6 +89,10 @@ AC_ARG_ENABLE(capi,
[enable libxcam-capi library, @<:@default=yes@:>@]),
[], [enable_capi="yes"])
+AC_ARG_ENABLE(osg,
+ AS_HELP_STRING([--enable-osg],
+ [enable open scene graph library, @<:@default=no@:>@]),
+ [], [enable_osg="no"])
# documentation
AC_ARG_ENABLE(docs,
[AC_HELP_STRING([--enable-docs],
@@ -144,6 +148,12 @@ if test "$enable_vulkan" = "yes"; then
PKG_CHECK_MODULES(LIBVULKAN, [vulkan], [HAVE_VULKAN=1], [HAVE_VULKAN=0])
fi
+# check open sence graph
+HAVE_OSG=0
+if test "$enable_osg" = "yes"; then
+ PKG_CHECK_MODULES(LIBOSG, [openscenegraph-osg], [HAVE_OSG=1], [HAVE_OSG=0])
+fi
+
if test "$enable_libcl" = "yes" && test "$HAVE_LIBCL" -eq 0; then
PKG_CHECK_MODULES(LIBCL, [OpenCL], [HAVE_LIBCL=1], [HAVE_LIBCL=0])
fi
@@ -371,6 +381,9 @@ AC_DEFINE_UNQUOTED([HAVE_VULKAN], $HAVE_VULKAN,
[have vulkan])
AM_CONDITIONAL([HAVE_VULKAN], [test "$HAVE_VULKAN" -eq 1])
+AC_DEFINE_UNQUOTED([HAVE_OSG], $HAVE_OSG,
+ [have open scene graph])
+AM_CONDITIONAL([HAVE_OSG], [test "$HAVE_OSG" -eq 1])
AC_DEFINE_UNQUOTED([HAVE_OPENCV], $HAVE_OPENCV,
[have opencv])
@@ -408,6 +421,7 @@ AC_CONFIG_FILES([Makefile
modules/ocl/Makefile
modules/gles/Makefile
modules/vulkan/Makefile
+ modules/render/Makefile
wrapper/Makefile
wrapper/gstreamer/Makefile
wrapper/gstreamer/interface/Makefile
@@ -434,6 +448,7 @@ if test "$HAVE_LIBCL" -eq 1; then have_libcl="yes"; else have_libcl="no"; fi
if test "$HAVE_GLES" -eq 1; then have_gles="yes"; else have_gles="no"; fi
if test "$HAVE_VULKAN" -eq 1; then have_vulkan="yes"; else have_vulkan="no"; fi
if test "$HAVE_OPENCV" -eq 1; then have_opencv="yes"; else have_opencv="no"; fi
+if test "$HAVE_OSG" -eq 1; then have_osg="yes"; else have_osg="no"; fi
if test "$ENABLE_DVS" -eq 1; then enable_dvs="yes"; else enable_dvs="no"; fi
echo "
@@ -450,6 +465,7 @@ echo "
have Vulkan lib : $have_vulkan
have OpenCL lib : $have_libcl
have OpenCV lib : $have_opencv
+ have Open Scene Graph lib : $have_osg
enable 3a lib : $enable_3alib
enable smart analysis lib : $enable_smartlib
enable dvs : $enable_dvs
diff --git a/modules/Makefile.am b/modules/Makefile.am
index 4bfa99a..04986d5 100644
--- a/modules/Makefile.am
+++ b/modules/Makefile.am
@@ -22,5 +22,10 @@ else
VULKAN_DIR =
endif
+if HAVE_OSG
+RENDER_DIR = render
+else
+RENDER_DIR =
+endif
-SUBDIRS = soft $(ISP_DIR) $(OCL_DIR) $(GLES_DIR) $(VULKAN_DIR)
+SUBDIRS = soft $(ISP_DIR) $(OCL_DIR) $(GLES_DIR) $(VULKAN_DIR) $(RENDER_DIR)
diff --git a/modules/render/Makefile.am b/modules/render/Makefile.am
new file mode 100644
index 0000000..e102192
--- /dev/null
+++ b/modules/render/Makefile.am
@@ -0,0 +1,56 @@
+lib_LTLIBRARIES = libxcam_render.la
+
+XCAM_RENDER_CXXFLAGS = \
+ $(LIBOSG_CFLAGS) \
+ -I$(top_srcdir)/xcore \
+ -I$(top_srcdir)/modules \
+ $(NULL)
+
+XCAM_RENDER_LIBS = \
+ $(losgGA) \
+ -losgDB \
+ -losgUtil \
+ -losgFX \
+ -losgText \
+ -losgViewer \
+ -losg \
+ $(NULL)
+
+xcam_render_sources = \
+ render_osg_camera_manipulator.cpp \
+ render_osg_model.cpp \
+ render_osg_viewer.cpp \
+ $(NULL)
+
+libxcam_render_la_SOURCES = \
+ $(xcam_render_sources) \
+ $(NULL)
+
+libxcam_render_la_CXXFLAGS = \
+ $(XCAM_RENDER_CXXFLAGS) \
+ $(XCAM_CXXFLAGS) \
+ $(NULL)
+
+libxcam_render_la_LIBADD = \
+ $(top_builddir)/xcore/libxcam_core.la \
+ $(XCAM_RENDER_LIBS) \
+ $(NULL)
+
+libxcam_render_la_LDFLAGS = \
+ $(XCAM_LT_LDFLAGS) \
+ $(PTHREAD_LDFLAGS) \
+ $(NULL)
+
+libxcam_renderincludedir = $(includedir)/xcam/render
+
+nobase_libxcam_renderinclude_HEADERS = \
+ render_osg_camera_manipulator.h \
+ render_osg_model.h \
+ render_osg_viewer.h \
+ render_osg_shader.h \
+ $(NULL)
+
+noinst_HEADERS = \
+ $(NULL)
+
+libxcam_render_la_LIBTOOLFLAGS = --tag=disable-static
diff --git a/modules/render/render_osg_camera_manipulator.cpp b/modules/render/render_osg_camera_manipulator.cpp
new file mode 100644
index 0000000..3dca0f1
--- /dev/null
+++ b/modules/render/render_osg_camera_manipulator.cpp
@@ -0,0 +1,172 @@
+/*
+ * render_osg_camera_manipulator.cpp - supports 3D interactive manipulators
+ *
+ * Copyright (c) 2018 Intel Corporation
+ *
+ * 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.
+ *
+ * Author: Zong Wei <wei.zong@intel.com>
+ */
+
+#include "render_osg_camera_manipulator.h"
+
+namespace XCam {
+
+RenderOsgCameraManipulator::RenderOsgCameraManipulator ()
+ : osgGA::StandardManipulator::StandardManipulator ()
+ , mAngle (osg::PI)
+ , mLookAtOffset (0.0f)
+ , mMaxLookAtOffset (osg::PI_4)
+ , mLength (4.0f)
+ , mWidth (3.0f)
+ , mHeight (1.6f)
+ , mMaxHeight (4.0f)
+ , mMinHeight (0.6)
+ , mEyePosScale (1.0f)
+ , mUp (osg::Vec3d(0.0f, 0.0f, 1.0f))
+{
+ setAllowThrow (false);
+ setAutoComputeHomePosition (false);
+}
+
+RenderOsgCameraManipulator::~RenderOsgCameraManipulator ()
+{
+}
+
+osg::Matrixd
+RenderOsgCameraManipulator::getInverseMatrix () const
+{
+ osg::Vec3d eyePos;
+ getEyePosition (eyePos);
+ osg::Vec3d lookAtPos;
+ getLookAtPosition (lookAtPos);
+ return osg::Matrixd::lookAt (eyePos, lookAtPos, mUp);
+}
+
+osg::Matrixd
+RenderOsgCameraManipulator::getMatrix () const
+{
+ osg::Matrixd matrix = getInverseMatrix ();
+ return osg::Matrixd::inverse (matrix);
+}
+
+void
+RenderOsgCameraManipulator::home (double /*currentTime*/)
+{
+ mAngle = osg::PI;
+ mLookAtOffset = 0.0f;
+ mEyePosScale = 1.0f;
+}
+
+void
+RenderOsgCameraManipulator::rotate (float deltaAngle)
+{
+ if (deltaAngle > 0.) {
+ if (mLookAtOffset < mMaxLookAtOffset) {
+ mLookAtOffset = std::min (mLookAtOffset + deltaAngle, mMaxLookAtOffset);
+ } else {
+ mAngle += deltaAngle;
+ }
+ } else {
+ if (mLookAtOffset > -mMaxLookAtOffset) {
+ mLookAtOffset = std::max (mLookAtOffset + deltaAngle, -mMaxLookAtOffset);
+ } else {
+ mAngle += deltaAngle;
+ }
+ }
+ if (mAngle > 2 * osg::PI) {
+ mAngle -= 2 * osg::PI;
+ } else if (mAngle < 0.0f) {
+ mAngle += 2 * osg::PI;
+ }
+}
+
+void
+RenderOsgCameraManipulator::modifyHeight (float delta)
+{
+ if (delta > 0.0) {
+ mHeight = std::min (mHeight + delta, mMaxHeight);
+ } else {
+ mHeight = std::max (mHeight + delta, mMinHeight);
+ }
+}
+
+void
+RenderOsgCameraManipulator::getEyePosition (osg::Vec3d &eyePos) const
+{
+ float indentFactor = 1.0f - (0.1f * ((mHeight - mMinHeight) / (mMaxHeight - mMinHeight)));
+ eyePos[0] = cos (mAngle) * mLength * indentFactor;
+ eyePos[1] = sin (mAngle) * mWidth * indentFactor;
+ eyePos[2] = mHeight;
+ eyePos *= mEyePosScale;
+}
+
+void
+RenderOsgCameraManipulator::getLookAtPosition (osg::Vec3d &lookAtPos) const
+{
+ float lookAtAngle = mAngle + mLookAtOffset;
+ lookAtPos[0] = cos (lookAtAngle) * mLength * 0.5f;
+ lookAtPos[1] = sin (lookAtAngle) * mWidth * 0.5f;
+ lookAtPos[2] = mHeight * 0.25f;
+}
+
+bool
+RenderOsgCameraManipulator::handleKeyDown (const osgGA::GUIEventAdapter &ea, osgGA::GUIActionAdapter &us)
+{
+ (void)us;
+ bool eventHandled = false;
+ int key = ea.getKey ();
+ if (key == osgGA::GUIEventAdapter::KEY_Space) {
+ home (ea.getTime ());
+
+ eventHandled = true;
+ } else if (key == osgGA::GUIEventAdapter::KEY_Left) {
+ rotate (-0.1);
+ eventHandled = true;
+ } else if (key == osgGA::GUIEventAdapter::KEY_Right) {
+ rotate (0.1);
+ eventHandled = true;
+ }
+
+ return eventHandled;
+}
+
+bool
+RenderOsgCameraManipulator::handleMouseWheel (const osgGA::GUIEventAdapter &ea, osgGA::GUIActionAdapter &us)
+{
+ (void)us;
+ bool eventHandled = false;
+ osgGA::GUIEventAdapter::ScrollingMotion sm = ea.getScrollingMotion();
+
+ if (sm == osgGA::GUIEventAdapter::SCROLL_DOWN || sm == osgGA::GUIEventAdapter::SCROLL_RIGHT) {
+ rotate (0.1);
+ eventHandled = true;
+ } else if (osgGA::GUIEventAdapter::SCROLL_UP || sm == osgGA::GUIEventAdapter::SCROLL_LEFT) {
+ rotate (-0.1);
+ eventHandled = true;
+ }
+
+ return eventHandled;
+}
+
+bool
+RenderOsgCameraManipulator::performMovementLeftMouseButton (const double eventTimeDelta, const double dx, const double dy)
+{
+ (void)eventTimeDelta;
+
+ rotate (-2.0 * dx);
+ modifyHeight (-dy);
+ return true;
+}
+
+} // namespace XCam
diff --git a/modules/render/render_osg_camera_manipulator.h b/modules/render/render_osg_camera_manipulator.h
new file mode 100644
index 0000000..0653039
--- /dev/null
+++ b/modules/render/render_osg_camera_manipulator.h
@@ -0,0 +1,123 @@
+/*
+ * render_osg_camera_manipulator.h - supports 3D interactive manipulators
+ *
+ * Copyright (c) 2018 Intel Corporation
+ *
+ * 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.
+ *
+ * Author: Zong Wei <wei.zong@intel.com>
+ */
+
+#ifndef XCAM_OSG_CAMERA_MANIPULATOR_H
+#define XCAM_OSG_CAMERA_MANIPULATOR_H
+
+#include <osgGA/StandardManipulator>
+
+namespace XCam {
+
+class RenderOsgCameraManipulator
+ : public osgGA::StandardManipulator
+{
+public:
+
+ explicit RenderOsgCameraManipulator ();
+
+ virtual ~RenderOsgCameraManipulator ();
+
+ virtual void setByMatrix (const osg::Matrixd &matrix)
+ {
+ (void)matrix;
+ }
+
+ virtual void setByInverseMatrix (const osg::Matrixd &matrix)
+ {
+ (void)matrix;
+ }
+
+ virtual osg::Matrixd getMatrix () const;
+
+ virtual osg::Matrixd getInverseMatrix () const;
+
+ virtual void home (double currentTime);
+
+ virtual void setTransformation (const osg::Vec3d &eye, const osg::Quat &rotation)
+ {
+ (void)eye;
+ (void)rotation;
+ }
+
+ virtual void setTransformation (const osg::Vec3d &eye, const osg::Vec3d &center, const osg::Vec3d &up)
+ {
+ (void)eye;
+ (void)center;
+ (void)up;
+ }
+
+ virtual void getTransformation (osg::Vec3d &eye, osg::Quat &rotation) const
+ {
+ (void)eye;
+ (void)rotation;
+ }
+
+ virtual void getTransformation (osg::Vec3d &eye, osg::Vec3d &center, osg::Vec3d &up) const
+ {
+ (void)eye;
+ (void)center;
+ (void)up;
+ }
+
+ void setInitialValues (float angle, float length, float width, float height)
+ {
+ mAngle = angle;
+ mLength = length;
+ mWidth = width;
+ mHeight = height;
+ mMinHeight = height / 2.0f;
+
+ mUp = osg::Vec3d(0.0f, 0.0f, 1.0f);
+ }
+
+private:
+ RenderOsgCameraManipulator (RenderOsgCameraManipulator const &other);
+
+ RenderOsgCameraManipulator &operator= (RenderOsgCameraManipulator const &other);
+
+ virtual bool handleKeyDown (const osgGA::GUIEventAdapter &ea, osgGA::GUIActionAdapter &us);
+
+ virtual bool handleMouseWheel (const osgGA::GUIEventAdapter &ea, osgGA::GUIActionAdapter &us);
+
+ virtual bool performMovementLeftMouseButton (const double eventTimeDelta, const double dx, const double dy);
+
+ void rotate (float deltaAngle);
+
+ void modifyHeight (float delta);
+
+ void getEyePosition (osg::Vec3d &eye) const;
+
+ void getLookAtPosition (osg::Vec3d &center) const;
+
+ float mAngle;
+ float mLookAtOffset;
+ float mMaxLookAtOffset;
+ float mLength;
+ float mWidth;
+ float mHeight;
+ float mMaxHeight;
+ float mMinHeight;
+ float mEyePosScale;
+ osg::Vec3d mUp;
+};
+
+} // namespace XCam
+
+#endif // XCAM_OSG_CAMERA_MANIPULATOR_H
diff --git a/modules/render/render_osg_model.cpp b/modules/render/render_osg_model.cpp
new file mode 100644
index 0000000..2e3e7f3
--- /dev/null
+++ b/modules/render/render_osg_model.cpp
@@ -0,0 +1,337 @@
+/*
+ * render_osg_model.cpp - represents renderable things by model
+ *
+ * Copyright (c) 2018 Intel Corporation
+ *
+ * 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.
+ *
+ * Author: Zong Wei <wei.zong@intel.com>
+ */
+
+#include "render_osg_model.h"
+
+#include <iostream>
+#include <string>
+
+#include <osg/MatrixTransform>
+#include <osg/Texture2D>
+#include <osgDB/ReadFile>
+
+namespace XCam {
+
+RenderOsgModel::RenderOsgModel (const char *name, uint32_t width, uint32_t height)
+ : _name (NULL)
+ , _model (NULL)
+ , _geode (NULL)
+ , _program (NULL)
+ , _texture (NULL)
+{
+ XCAM_LOG_DEBUG ("RenderOsgModel width(%d), height(%d) ", width, height);
+ XCAM_ASSERT (name);
+ if (name)
+ _name = strndup (name, XCAM_MAX_STR_SIZE);
+
+ _model = new osg::Group ();
+ _geode = new osg::Geode ();
+
+ _texture = create_texture (width, height);
+ if (_texture.get ()) {
+ add_texture (_texture);
+ }
+}
+
+RenderOsgModel::RenderOsgModel (const char *name, bool from_file)
+ : _name (NULL)
+ , _model (NULL)
+ , _geode (NULL)
+ , _program (NULL)
+ , _texture (NULL)
+{
+ XCAM_LOG_DEBUG ("RenderOsgModel model name (%s) ", name);
+ XCAM_ASSERT (name);
+ if (name)
+ _name = strndup (name, XCAM_MAX_STR_SIZE);
+
+ _model = new osg::Group ();
+ _geode = new osg::Geode ();
+
+ if (from_file) {
+ osg::ref_ptr<osg::Node> node = create_model_from_file (name);
+ _geode->addChild (node);
+ }
+}
+
+RenderOsgModel::~RenderOsgModel ()
+{
+ if (_name)
+ xcam_free (_name);
+}
+
+osg::Node*
+RenderOsgModel::create_model_from_file (const char *name)
+{
+ XCAM_LOG_DEBUG ("Invailide node name %s", name);
+ if (name == NULL) {
+ return NULL;
+ }
+
+ osg::ref_ptr<osg::Node> node = osgDB::readNodeFile (name);
+ if (NULL == node.get ()) {
+ XCAM_LOG_ERROR ("Read node file FAILD!!! node name %s", name);
+ }
+
+ return node.release();
+}
+
+void
+RenderOsgModel::append_model (SmartPtr<RenderOsgModel> &child_model)
+{
+ osg::ref_ptr<osg::Group> model = get_model ();
+
+ if (NULL == model.get () || NULL == child_model.ptr ()) {
+ XCAM_LOG_ERROR ("Append child model ERROR!! NULL model !!");
+ }
+
+ model->addChild (child_model->get_model ());
+}
+
+void
+RenderOsgModel::append_geode (SmartPtr<RenderOsgModel> &child_model)
+{
+ osg::ref_ptr<osg::Group> model = get_model ();
+
+ if (NULL == model.get () || NULL == child_model.ptr ()) {
+ XCAM_LOG_ERROR ("Append child geode ERROR!! NULL model !!");
+ }
+
+ model->addChild (child_model->get_geode ());
+}
+
+XCamReturn
+RenderOsgModel::setup_shader_program (
+ const char *name,
+ osg::Shader::Type type,
+ const char *source_text)
+{
+ XCAM_LOG_DEBUG ("setup shader program name(%s), type(%d)", name, type);
+ XCamReturn result = XCAM_RETURN_NO_ERROR;
+
+ if (NULL == _program.get ()) {
+ _program = new osg::Program ();
+ _program->setName (name);
+ }
+
+ _program->addShader (new osg::Shader (type, source_text));
+
+ _model->getOrCreateStateSet ()->setAttributeAndModes (_program, osg::StateAttribute::ON);
+ _model->getOrCreateStateSet ()->setMode (GL_DEPTH_TEST, osg::StateAttribute::ON);
+
+ return result;
+}
+
+XCamReturn
+RenderOsgModel::setup_vertex_model (
+ BowlModel::VertexMap &vertices,
+ BowlModel::PointMap &points,
+ BowlModel::IndexVector &indices,
+ float a,
+ float b,
+ float c)
+{
+ XCamReturn result = XCAM_RETURN_NO_ERROR;
+
+ osg::ref_ptr<osg::Group> model = get_model ();
+ osg::ref_ptr<osg::Geode> geode = get_geode ();
+ osg::ref_ptr<osg::Geometry> geometry = new osg::Geometry ();
+
+ geode->addDrawable (geometry);
+ geometry->setUseVertexBufferObjects (true);
+
+ osg::ref_ptr<osg::Vec3Array> vertex_array = new osg::Vec3Array ();
+ osg::ref_ptr<osg::Vec2Array> tex_coord_array = new osg::Vec2Array ();
+ osg::ref_ptr<osg::DrawElementsUInt> index_array = new osg::DrawElementsUInt (GL_TRIANGLE_STRIP, 0);
+
+ osg::ref_ptr<osg::Vec3Array> normal_array = new osg::Vec3Array ();
+ osg::ref_ptr<osg::Vec4Array> color_array = new osg::Vec4Array ();
+
+ normal_array->push_back (osg::Vec3 (0, -1, 0));
+ geometry->setNormalArray (normal_array);
+ geometry->setNormalBinding (osg::Geometry::BIND_OVERALL);
+
+ color_array->push_back (osg::Vec4 (1.0, 0.0, 0.0, 1.0));
+ geometry->setColorArray (color_array);
+ geometry->setColorBinding (osg::Geometry::BIND_OVERALL);
+
+ for (uint32_t idx = 0; idx < vertices.size (); idx++) {
+ vertex_array->push_back (
+ osg::Vec3f (vertices[idx].x * a,
+ vertices[idx].y * b,
+ vertices[idx].z * c));
+ }
+
+ for (uint32_t idx = 0; idx < points.size (); idx++) {
+ tex_coord_array->push_back (osg::Vec2f (points[idx].x, points[idx].y));
+ }
+
+ for (uint32_t idx = 0; idx < indices.size (); idx++) {
+ index_array->push_back (indices[idx]);
+ }
+
+ geometry->setVertexArray (vertex_array.get ());
+
+ if (points.size () > 0) {
+ geometry->setTexCoordArray (0, tex_coord_array.get ());
+ }
+
+ if (indices.size () > 0) {
+ geometry->addPrimitiveSet (index_array.get ());
+ } else {
+ geometry->addPrimitiveSet (new osg::DrawArrays (GL_TRIANGLE_FAN, 0, 4));
+ }
+
+ model->addChild (geode);
+
+ return result;
+}
+
+XCamReturn
+RenderOsgModel::setup_model_matrix (
+ float translation_x,
+ float translation_y,
+ float translation_z,
+ float rotation_x,
+ float rotation_y,
+ float rotation_z,
+ float rotation_degrees)
+{
+ XCamReturn result = XCAM_RETURN_NO_ERROR;
+
+ osg::ref_ptr<osg::Group> model = get_model ();
+ osg::ref_ptr<osg::Geode> geode = get_geode ();
+
+ const osg::Vec3f axis(rotation_x, rotation_y, rotation_z);
+ osg::ref_ptr<osg::MatrixTransform> mat = new osg::MatrixTransform ();
+ mat->setMatrix (osg::Matrix::scale (osg::Vec3 (1.0, 1.0, 1.0)) *
+ osg::Matrix::rotate ((rotation_degrees / 180.f) * osg::PI_2, axis) *
+ osg::Matrix::translate (osg::Vec3 (translation_x, translation_y, translation_z)));
+
+ mat->addChild (geode);
+ model->addChild (mat);
+
+ return result;
+}
+
+XCamReturn
+RenderOsgModel::update_texture (SmartPtr<VideoBuffer> &buffer)
+{
+ XCamReturn result = XCAM_RETURN_NO_ERROR;
+
+ XCAM_LOG_DEBUG ("RenderOsgModel::update_texture ");
+
+ if (NULL == _texture.get ()) {
+ return XCAM_RETURN_ERROR_PARAM;
+ }
+
+ {
+ SmartLock locker (_mutex);
+
+ VideoBufferInfo info = buffer->get_video_info ();
+ uint32_t image_width = info.width;
+ uint32_t image_height = info.height;
+
+ osg::ref_ptr<osg::Image> image_y = new osg::Image ();
+ osg::ref_ptr<osg::Image> image_uv = new osg::Image ();
+
+ uint8_t* image_buffer = buffer->map ();
+
+ uint8_t* src_y = image_buffer;
+ uint8_t* src_uv = image_buffer + image_width * image_height;
+
+ image_y->setImage (image_width, image_height, 1,
+ GL_LUMINANCE, GL_LUMINANCE, GL_UNSIGNED_BYTE,
+ src_y, osg::Image::NO_DELETE);
+
+ image_uv->setImage (image_width / 2, image_height / 2, 1,
+ GL_LUMINANCE, GL_RG, GL_UNSIGNED_BYTE,
+ src_uv, osg::Image::NO_DELETE);
+
+ _texture->_texture_y->setImage (image_y);
+ _texture->_texture_uv->setImage (image_uv);
+
+ buffer->unmap ();
+ }
+
+ return result;
+}
+
+NV12Texture*
+RenderOsgModel::create_texture (uint32_t width, uint32_t height)
+{
+ osg::ref_ptr<NV12Texture> nv12 = new NV12Texture (width, height);
+
+ nv12->_texture_y = new osg::Texture2D ();
+ nv12->_texture_y->setImage (new osg::Image ());
+
+ nv12->_texture_y->setInternalFormat (GL_LUMINANCE);
+ nv12->_texture_y->setResizeNonPowerOfTwoHint (false);
+ nv12->_texture_y->setNumMipmapLevels (0);
+ nv12->_texture_y->setFilter (osg::Texture::MIN_FILTER, osg::Texture::NEAREST);
+ nv12->_texture_y->setFilter (osg::Texture::MAG_FILTER, osg::Texture::NEAREST);
+ nv12->_texture_y->setWrap (osg::Texture::WRAP_S, osg::Texture::CLAMP);
+ nv12->_texture_y->setWrap (osg::Texture::WRAP_T, osg::Texture::CLAMP);
+
+ nv12->_texture_y->setTextureWidth (width);
+ nv12->_texture_y->setTextureHeight (height);
+
+ nv12->_texture_uv = new osg::Texture2D ();
+ nv12->_texture_uv->setImage (new osg::Image ());
+
+ nv12->_texture_uv->setInternalFormat (GL_RG);
+ nv12->_texture_uv->setResizeNonPowerOfTwoHint (false);
+ nv12->_texture_uv->setNumMipmapLevels (0);
+ nv12->_texture_uv->setFilter (osg::Texture::MIN_FILTER, osg::Texture::NEAREST);
+ nv12->_texture_uv->setFilter (osg::Texture::MAG_FILTER, osg::Texture::NEAREST);
+ nv12->_texture_uv->setWrap (osg::Texture::WRAP_S, osg::Texture::CLAMP);
+ nv12->_texture_uv->setWrap (osg::Texture::WRAP_T, osg::Texture::CLAMP);
+
+ nv12->_texture_uv->setTextureWidth (width / 2);
+ nv12->_texture_uv->setTextureHeight (height / 2);
+
+ return nv12.release ();
+}
+
+XCamReturn
+RenderOsgModel::add_texture (osg::ref_ptr<NV12Texture> &texture)
+{
+ XCamReturn result = XCAM_RETURN_NO_ERROR;
+
+ osg::ref_ptr<osg::Group> model = get_model ();
+
+ if (NULL == model.get () || NULL == _texture.get ()) {
+ return XCAM_RETURN_ERROR_PARAM;
+ }
+
+ model->getOrCreateStateSet()->setTextureAttribute(0, texture->_texture_y.get ());
+ texture->_uniform_y = new osg::Uniform (osg::Uniform::SAMPLER_2D, "textureY");
+ texture->_uniform_y->set (0);
+ model->getOrCreateStateSet ()->addUniform (texture->_uniform_y.get ());
+
+ model->getOrCreateStateSet ()->setTextureAttribute (1, texture->_texture_uv.get ());
+ texture->_uniform_uv = new osg::Uniform (osg::Uniform::SAMPLER_2D, "textureUV");
+ texture->_uniform_uv->set (1);
+ model->getOrCreateStateSet ()->addUniform (texture->_uniform_uv.get ());
+
+ return result;
+}
+
+} // namespace XCam
diff --git a/modules/render/render_osg_model.h b/modules/render/render_osg_model.h
new file mode 100644
index 0000000..09cba8c
--- /dev/null
+++ b/modules/render/render_osg_model.h
@@ -0,0 +1,123 @@
+/*
+ * render_osg_model.h - represents renderable things by object
+ *
+ * Copyright (c) 2018 Intel Corporation
+ *
+ * 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.
+ *
+ * Author: Zong Wei <wei.zong@intel.com>
+ */
+
+#ifndef XCAM_OSG_RENDER_MODEL_H
+#define XCAM_OSG_RENDER_MODEL_H
+
+#include <osg/Texture2D>
+#include <osg/Group>
+
+#include <interface/data_types.h>
+#include <interface/stitcher.h>
+#include <xcam_mutex.h>
+
+namespace XCam {
+
+class NV12Texture : public osg::Referenced
+{
+public:
+ explicit NV12Texture (uint32_t width, uint32_t height)
+ {
+ _image_width = width;
+ _image_height = height;
+ }
+
+public:
+ uint32_t _image_width;
+ uint32_t _image_height;
+
+ osg::ref_ptr<osg::Texture2D> _texture_y;
+ osg::ref_ptr<osg::Texture2D> _texture_uv;
+
+ osg::ref_ptr<osg::Uniform> _uniform_y;
+ osg::ref_ptr<osg::Uniform> _uniform_uv;
+};
+
+class RenderOsgModel {
+public:
+
+ explicit RenderOsgModel (const char *name, uint32_t width, uint32_t height);
+ explicit RenderOsgModel (const char *name, bool from_file = true);
+
+ virtual ~RenderOsgModel ();
+
+ const char *get_name () const {
+ return _name;
+ }
+
+ osg::Node* create_model_from_file (const char *name);
+
+ osg::Group* get_model () const {
+ return _model;
+ }
+
+ void append_model (SmartPtr<RenderOsgModel> &model);
+
+ void append_geode (SmartPtr<RenderOsgModel> &model);
+
+
+ osg::Geode* get_geode () const {
+ return _geode;
+ }
+
+ XCamReturn setup_shader_program (
+ const char *name,
+ osg::Shader::Type type,
+ const char *source_text);
+
+ XCamReturn setup_vertex_model (
+ BowlModel::VertexMap &vertices,
+ BowlModel::PointMap &points,
+ BowlModel::IndexVector &indices,
+ float a = 1.0f,
+ float b = 1.0f,
+ float c = 1.0f);
+
+ XCamReturn setup_model_matrix (
+ float translation_x,
+ float translation_y,
+ float translation_z,
+ float rotation_x,
+ float rotation_y,
+ float rotation_z,
+ float rotation_degrees);
+
+ XCamReturn update_texture (SmartPtr<VideoBuffer> &buffer);
+
+private:
+
+ NV12Texture* create_texture (uint32_t width, uint32_t height);
+ XCamReturn add_texture (osg::ref_ptr<NV12Texture> &texture);
+
+private:
+
+ char *_name;
+
+ osg::ref_ptr<osg::Group> _model;
+ osg::ref_ptr<osg::Geode> _geode;
+ osg::ref_ptr<osg::Program> _program;
+ osg::ref_ptr<NV12Texture> _texture;
+
+ Mutex _mutex;
+};
+
+} // namespace XCam
+
+#endif // XCAM_OSG_RENDER_MODEL_H
diff --git a/modules/render/render_osg_shader.h b/modules/render/render_osg_shader.h
new file mode 100644
index 0000000..b2dd52e
--- /dev/null
+++ b/modules/render/render_osg_shader.h
@@ -0,0 +1,93 @@
+/*
+ * render_osg_shader.h - common gl shaders
+ *
+ * Copyright (c) 2018 Intel Corporation
+ *
+ * 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.
+ *
+ * Author: Zong Wei <wei.zong@intel.com>
+ */
+
+#ifndef XCAM_OSG_SHADER_H
+#define XCAM_OSG_SHADER_H
+
+namespace XCam {
+
+static const char VtxShaderProjectNV12Texture[] = ""
+ "precision highp float; \n"
+ "attribute vec4 osg_Vertex; \n"
+ "attribute vec2 osg_MultiTexCoord0; \n"
+ "attribute vec4 osg_Color; \n"
+ "uniform mat4 osg_ModelViewProjectionMatrix; \n"
+ "uniform mat4 osg_ModelViewMatrix; \n"
+ "uniform mat4 osg_ViewMatrixInverse; \n"
+ "varying vec2 texcoord; \n"
+ "varying vec4 color; \n"
+ "void main(void) \n"
+ "{ \n"
+ " texcoord = osg_MultiTexCoord0; \n"
+ " gl_Position = osg_ModelViewProjectionMatrix * osg_Vertex; \n"
+ " color = osg_Color; \n"
+ "} \n";
+
+static const char FrgShaderProjectNV12Texture[] = ""
+ "precision highp float; \n"
+ "uniform sampler2D textureY; \n"
+ "uniform sampler2D textureUV; \n"
+ "varying vec2 texcoord; \n"
+ "varying vec4 color; \n"
+ "vec4 getRGBColorNV12(sampler2D u_textureY, sampler2D u_textureUV, vec2 tex) \n"
+ "{ \n"
+ " vec4 resultcolor = vec4 (0.0, 0.0, 0.0, 1.0); \n"
+ " float y, u, v; \n"
+ " y = texture2D(u_textureY, vec2(tex.s, tex.t)).r; \n"
+ " vec2 colorUV = texture2D(u_textureUV, vec2(tex.s, tex.t)).rg; \n"
+ " u = colorUV.x-0.5; \n"
+ " v = colorUV.y-0.5; \n"
+ " y = 1.1643*(y-0.0625); \n"
+ " resultcolor.r = (y+1.5958*(v)); \n"
+ " resultcolor.g = (y-0.39173*(u)-0.81290*(v)); \n"
+ " resultcolor.b = (y+2.017*(u)); \n"
+ " resultcolor.a = 1.0; \n"
+ " return resultcolor; \n"
+ "} \n"
+ "void main() \n"
+ "{ \n"
+ " vec4 textureColor = getRGBColorNV12(textureY, textureUV, texcoord); \n"
+ " gl_FragColor = textureColor; \n"
+ "} \n";
+
+const char VtxShaderSimpleTexture[] = ""
+ "precision highp float; \n"
+ "attribute vec4 osg_Vertex; \n"
+ "attribute vec4 osg_Color; \n"
+ "uniform mat4 osg_ModelViewProjectionMatrix; \n"
+ "varying vec4 color; \n"
+ "void main(void) \n"
+ "{ \n"
+ " gl_Position = osg_ModelViewProjectionMatrix * osg_Vertex; \n"
+ " color = osg_Color; \n"
+ "} \n";
+
+const char FrgShaderSimpleTexture[] = ""
+ "precision highp float; \n"
+ "varying vec4 color; \n"
+ "void main() \n"
+ "{ \n"
+ " gl_FragColor = color; \n"
+ "} \n";
+
+
+} // namespace XCam
+
+#endif // XCAM_OSG_SHADER_H
diff --git a/modules/render/render_osg_viewer.cpp b/modules/render/render_osg_viewer.cpp
new file mode 100644
index 0000000..42f625d
--- /dev/null
+++ b/modules/render/render_osg_viewer.cpp
@@ -0,0 +1,121 @@
+/*
+ * render_osg_viewer.cpp - renders a single view on to a single scene
+ *
+ * Copyright (c) 2018 Intel Corporation
+ *
+ * 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.
+ *
+ * Author: Zong Wei <wei.zong@intel.com>
+ */
+
+#include "render_osg_viewer.h"
+#include "render_osg_model.h"
+#include "render_osg_camera_manipulator.h"
+
+#include <string>
+
+namespace XCam {
+
+RenderOsgViewer::RenderOsgViewer ()
+ : _viewer (NULL)
+ , _model_groups (NULL)
+ , _initialized (false)
+{
+ _viewer = new osgViewer::Viewer ();
+
+ if (!_initialized) {
+ initialize ();
+ }
+}
+
+RenderOsgViewer::~RenderOsgViewer ()
+{
+ _viewer->setDone (true);
+}
+
+XCamReturn
+RenderOsgViewer::initialize ()
+{
+ XCamReturn result = XCAM_RETURN_NO_ERROR;
+
+ osg::GraphicsContext::WindowingSystemInterface* wsi = osg::GraphicsContext::getWindowingSystemInterface();
+ uint32_t win_width = 1920;
+ uint32_t win_height = 1080;
+ if (wsi) {
+ wsi->getScreenResolution (osg::GraphicsContext::ScreenIdentifier (0), win_width, win_height);
+ }
+
+ _viewer->setThreadingModel (osgViewer::Viewer::SingleThreaded);
+
+ _viewer->setLightingMode (osg::View::SKY_LIGHT);
+ _viewer->getLight()->setAmbient (osg::Vec4f(0.f, 0.f, 0.f, 1.f));
+ _viewer->getLight()->setDiffuse (osg::Vec4d(0.4f, 0.4f, 0.4f, 1.f));
+ _viewer->getLight()->setSpecular (osg::Vec4d(0.5f, 0.5f, 0.5f, 1.f));
+
+ osg::ref_ptr<osgViewer::StatsHandler> stats_handler = new osgViewer::StatsHandler ();
+ _viewer->addEventHandler (stats_handler);
+
+ _viewer->setUpViewInWindow (0, 0, win_width, win_height);
+
+ osg::ref_ptr<RenderOsgCameraManipulator> vp_manipulator = new RenderOsgCameraManipulator ();
+ vp_manipulator->setInitialValues (osg::PI, 6.0f, 4.0f, 2.6f);
+ _viewer->setCameraManipulator (vp_manipulator);
+ _viewer->getCamera ()->setClearMask (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+ _viewer->getCamera ()->setComputeNearFarMode (osg::Camera::DO_NOT_COMPUTE_NEAR_FAR);
+ _viewer->getCamera ()->setClearColor (osg::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
+ _viewer->getCamera ()->setViewport (0, 0, win_width, win_height);
+
+ _initialized = true;
+
+ return result;
+}
+
+void
+RenderOsgViewer::set_camera_manipulator (osg::ref_ptr<osgGA::StandardManipulator> &manipulator)
+{
+ _viewer->setCameraManipulator (manipulator);
+}
+
+void
+RenderOsgViewer::add_model (SmartPtr<RenderOsgModel> &model)
+{
+ if (!model.ptr ()) {
+ return;
+ }
+
+ if (!_model_groups.ptr ()) {
+ _model_groups = model;
+ } else {
+ _model_groups->append_model (model);
+ }
+}
+
+void
+RenderOsgViewer::validate_model_groups ()
+{
+ if (!_model_groups.ptr ()) {
+ return;
+ }
+ _viewer->setSceneData (_model_groups->get_model ());
+}
+
+void
+RenderOsgViewer::start_render ()
+{
+ if (!_viewer->done ())
+ {
+ _viewer->frame ();
+ }
+}
+
+} // namespace XCam
diff --git a/modules/render/render_osg_viewer.h b/modules/render/render_osg_viewer.h
new file mode 100644
index 0000000..bf2d1da
--- /dev/null
+++ b/modules/render/render_osg_viewer.h
@@ -0,0 +1,66 @@
+/*
+ * render_osg_viewer.h - renders a single view on to a single scene
+ *
+ * Copyright (c) 2018 Intel Corporation
+ *
+ * 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.
+ *
+ * Author: Zong Wei <wei.zong@intel.com>
+ */
+
+#ifndef XCAM_OSG_RENDER_VIEWER_H
+#define XCAM_OSG_RENDER_VIEWER_H
+
+#include <osgViewer/Viewer>
+#include <osgViewer/ViewerEventHandlers>
+#include <osgGA/StandardManipulator>
+
+#include <interface/data_types.h>
+#include <interface/stitcher.h>
+#include <xcam_mutex.h>
+
+namespace XCam {
+
+class RenderOsgModel;
+
+class RenderOsgViewer {
+public:
+
+ explicit RenderOsgViewer ();
+
+ virtual ~RenderOsgViewer ();
+
+ osgViewer::Viewer *get_viewer () {
+ return _viewer;
+ }
+
+ void set_camera_manipulator (osg::ref_ptr<osgGA::StandardManipulator> &manipulator);
+
+ void add_model (SmartPtr<RenderOsgModel> &model);
+
+ void validate_model_groups ();
+
+ void start_render ();
+
+private:
+ XCamReturn initialize ();
+
+private:
+ osg::ref_ptr<osgViewer::Viewer> _viewer;
+ SmartPtr<RenderOsgModel> _model_groups;
+ bool _initialized;
+};
+
+} // namespace XCam
+
+#endif // XCAM_OSG_RENDER_VIEWER_H
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 35f4579..3f538ff 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -24,6 +24,12 @@ noinst_PROGRAMS = \
test-surround-view \
$(NULL)
+if HAVE_OSG
+noinst_PROGRAMS += \
+ test-render-surround-view \
+ $(NULL)
+endif
+
if ENABLE_IA_AIQ
noinst_PROGRAMS += \
test-poll-thread \
@@ -166,7 +172,31 @@ test_surround_view_LDADD = \
$(top_builddir)/modules/soft/libxcam_soft.la \
$(TEST_BASE_LA) \
$(NULL)
+
if HAVE_GLES
test_surround_view_LDADD += \
+ $(top_builddir)/modules/gles/libxcam_gles.la \
+ $(NULL)
+endif
+
+if HAVE_OSG
+test_render_surround_view_SOURCES = test-render-surround-view.cpp
+test_render_surround_view_CXXFLAGS = $(TEST_BASE_CXXFLAGS)
+test_render_surround_view_LDADD = \
+ $(top_builddir)/modules/soft/libxcam_soft.la \
+ $(top_builddir)/modules/render/libxcam_render.la \
+ $(TEST_BASE_LA) \
+ -losgGA \
+ -losgDB \
+ -losgUtil \
+ -losgFX \
+ -losgText \
+ -losgViewer \
+ -losg \
+ $(NULL)
+if HAVE_GLES
+test_render_surround_view_LDADD += \
$(top_builddir)/modules/gles/libxcam_gles.la
-endif \ No newline at end of file
+endif
+
+endif
diff --git a/tests/test-render-surround-view.cpp b/tests/test-render-surround-view.cpp
new file mode 100644
index 0000000..335e289
--- /dev/null
+++ b/tests/test-render-surround-view.cpp
@@ -0,0 +1,595 @@
+/*
+ * test-render-surround-view.cpp - test render surround view
+ *
+ * Copyright (c) 2018 Intel Corporation
+ *
+ * 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.
+ *
+ * Author: Zong Wei <wei.zong@intel.com>
+ */
+
+#include "test_common.h"
+#include "test_stream.h"
+#include <interface/geo_mapper.h>
+#include <interface/stitcher.h>
+#include <calibration_parser.h>
+#include <soft/soft_video_buf_allocator.h>
+#if HAVE_GLES
+#include <gles/gl_video_buffer.h>
+#include <gles/egl/egl_base.h>
+#endif
+
+#include <render/render_osg_viewer.h>
+#include <render/render_osg_model.h>
+#include <render/render_osg_shader.h>
+
+using namespace XCam;
+
+enum SVModule {
+ SVModuleNone = 0,
+ SVModuleSoft,
+ SVModuleGLES
+};
+
+#define MODEL_NAME "SmallSuv.osgb"
+
+static const char VtxShaderCar[] = ""
+ "precision highp float; \n"
+ "uniform mat4 osg_ModelViewProjectionMatrix; \n"
+ "uniform mat4 osg_ModelViewMatrix; \n"
+ "uniform mat3 osg_NormalMatrix; \n"
+ "attribute vec3 osg_Normal; \n"
+ "attribute vec4 osg_Color; \n"
+ "attribute vec4 osg_Vertex; \n"
+ "varying vec4 v_color; \n"
+ "varying float diffuseLight; \n"
+ "varying float specLight; \n"
+ "attribute vec2 osg_MultiTexCoord0; \n"
+ "varying vec2 texCoord0; \n"
+ "void main() \n"
+ "{ \n"
+ " vec4 light = vec4(0.0,100.0, 100.0, 1.0); \n"
+ " vec4 lightColorSpec = vec4(1.0, 1.0, 1.0, 1.0); \n"
+ " vec4 lightColorDiffuse = vec4(1.0, 1.0, 1.0, 1.0); \n"
+ " vec4 lightColorAmbient = vec4(0.3, 0.3, .3, 1.0); \n"
+ " vec4 carColorAmbient = vec4(0.0, 0.0, 1.0, 1.0); \n"
+ " vec4 carColorDiffuse = vec4(0.0, 0.0, 1.0, 1.0); \n"
+ " vec4 carColorSpec = vec4(1.0, 1.0, 1.0, 1.0); \n"
+ " vec3 tnorm = normalize(osg_NormalMatrix * osg_Normal); \n"
+ " vec4 eye = osg_ModelViewMatrix * osg_Vertex; \n"
+ " vec3 s = normalize(vec3(light - eye)); \n"
+ " vec3 v = normalize(-eye.xyz); \n"
+ " vec3 r = reflect(-s, tnorm); \n"
+ " diffuseLight = max(0.0, dot( s, tnorm)); \n"
+ " specLight = 0.0; \n"
+ " if(diffuseLight > 0.0) \n"
+ " { \n"
+ " specLight = pow(max(0.0, dot(r,v)), 10.0); \n"
+ " } \n"
+ " texCoord0 = osg_MultiTexCoord0; \n"
+ " v_color = (specLight * lightColorSpec * carColorSpec) + (carColorDiffuse * lightColorDiffuse * diffuseLight) + lightColorAmbient * carColorAmbient; \n"
+ " gl_Position = osg_ModelViewProjectionMatrix * osg_Vertex; \n"
+ "} \n";
+
+static const char FrgShaderCar[] = ""
+ "precision highp float; \n"
+ "varying vec4 v_color; \n"
+ "varying float diffuseLight; \n"
+ "varying float specLight; \n"
+ "uniform sampler2D textureWheel; \n"
+ "varying vec2 texCoord0; \n"
+ "void main() \n"
+ "{ \n"
+ " vec4 lightColorSpec = vec4(1.0, 1.0, 1.0, 1.0); \n"
+ " vec4 lightColorDiffuse = vec4(1.0, 1.0, 1.0, 1.0); \n"
+ " vec4 lightColorAmbient = vec4(0.3, 0.3, .3, 1.0); \n"
+ " vec4 base = texture2D(textureWheel, texCoord0.st); \n"
+ " gl_FragColor = (specLight * lightColorSpec * base) + (base * lightColorDiffuse * diffuseLight) + lightColorAmbient * base ; \n"
+ "} \n";
+
+class SVStream
+ : public Stream
+{
+public:
+ explicit SVStream (const char *file_name = NULL, uint32_t width = 0, uint32_t height = 0);
+ virtual ~SVStream () {}
+
+ void set_module (SVModule module) {
+ XCAM_ASSERT (module != SVModuleNone);
+ _module = module;
+ }
+
+ virtual XCamReturn create_buf_pool (const VideoBufferInfo &info, uint32_t count);
+
+private:
+ XCAM_DEAD_COPY (SVStream);
+
+private:
+ SVModule _module;
+ SmartPtr<GeoMapper> _mapper;
+};
+typedef std::vector<SmartPtr<SVStream>> SVStreams;
+
+SVStream::SVStream (const char *file_name, uint32_t width, uint32_t height)
+ : Stream (file_name, width, height)
+ , _module (SVModuleNone)
+{
+}
+
+XCamReturn
+SVStream::create_buf_pool (const VideoBufferInfo &info, uint32_t count)
+{
+ XCAM_FAIL_RETURN (
+ ERROR, _module != SVModuleNone, XCAM_RETURN_ERROR_PARAM,
+ "invalid module, please set module first");
+
+ SmartPtr<BufferPool> pool;
+ if (_module == SVModuleSoft) {
+ pool = new SoftVideoBufAllocator (info);
+ } else if (_module == SVModuleGLES) {
+#if HAVE_GLES
+ pool = new GLVideoBufferPool (info);
+#endif
+ }
+ XCAM_ASSERT (pool.ptr ());
+
+ if (!pool->reserve (count)) {
+ XCAM_LOG_ERROR ("create buffer pool failed");
+ return XCAM_RETURN_ERROR_MEM;
+ }
+
+ set_buf_pool (pool);
+ return XCAM_RETURN_NO_ERROR;
+}
+
+static SmartPtr<Stitcher>
+create_stitcher (SVModule module)
+{
+ SmartPtr<Stitcher> stitcher;
+
+ if (module == SVModuleSoft) {
+ stitcher = Stitcher::create_soft_stitcher ();
+ } else if (module == SVModuleGLES) {
+#if HAVE_GLES
+ stitcher = Stitcher::create_gl_stitcher ();
+#endif
+ }
+ XCAM_ASSERT (stitcher.ptr ());
+
+ return stitcher;
+}
+
+static int
+parse_camera_info (const char *path, uint32_t idx, CameraInfo &info, uint32_t camera_count)
+{
+ static const char *instrinsic_names[] = {
+ "intrinsic_camera_front.txt", "intrinsic_camera_right.txt",
+ "intrinsic_camera_rear.txt", "intrinsic_camera_left.txt"
+ };
+ static const char *exstrinsic_names[] = {
+ "extrinsic_camera_front.txt", "extrinsic_camera_right.txt",
+ "extrinsic_camera_rear.txt", "extrinsic_camera_left.txt"
+ };
+ static const float viewpoints_range[] = {64.0f, 160.0f, 64.0f, 160.0f};
+
+ char intrinsic_path[XCAM_TEST_MAX_STR_SIZE] = {'\0'};
+ char extrinsic_path[XCAM_TEST_MAX_STR_SIZE] = {'\0'};
+ snprintf (intrinsic_path, XCAM_TEST_MAX_STR_SIZE, "%s/%s", path, instrinsic_names[idx]);
+ snprintf (extrinsic_path, XCAM_TEST_MAX_STR_SIZE, "%s/%s", path, exstrinsic_names[idx]);
+
+ CalibrationParser parser;
+ CHECK (
+ parser.parse_intrinsic_file (intrinsic_path, info.calibration.intrinsic),
+ "parse intrinsic params (%s)failed.", intrinsic_path);
+
+ CHECK (
+ parser.parse_extrinsic_file (extrinsic_path, info.calibration.extrinsic),
+ "parse extrinsic params (%s)failed.", extrinsic_path);
+ info.calibration.extrinsic.trans_x += TEST_CAMERA_POSITION_OFFSET_X;
+
+ info.angle_range = viewpoints_range[idx];
+ info.round_angle_start = (idx * 360.0f / camera_count) - info.angle_range / 2.0f;
+ return 0;
+}
+
+void
+get_bowl_model (
+ const SmartPtr<Stitcher> &stitcher,
+ BowlModel::VertexMap &vertices,
+ BowlModel::PointMap &points,
+ BowlModel::IndexVector &indices,
+ float &a,
+ float &b,
+ float &c,
+ float resRatio,
+ uint32_t image_width,
+ uint32_t image_height)
+{
+ uint32_t res_width = image_width * resRatio;
+ uint32_t res_height = image_height * resRatio;
+
+ BowlDataConfig bowl = stitcher->get_bowl_config();
+ bowl.angle_start = 0.0f;
+ bowl.angle_end = 360.0f;
+
+ a = bowl.a;
+ b = bowl.b;
+ c = bowl.c;
+
+ BowlModel bowl_model(bowl, image_width, image_height);
+
+ bowl_model.get_bowlview_vertex_model(
+ vertices,
+ points,
+ indices,
+ res_width,
+ res_height);
+}
+
+static SmartPtr<RenderOsgModel>
+create_surround_view_model (
+ const SmartPtr<Stitcher> &stitcher,
+ uint32_t texture_width,
+ uint32_t texture_height)
+{
+ SmartPtr<RenderOsgModel> svm_model = new RenderOsgModel ("svm model", texture_width, texture_height);
+
+ svm_model->setup_shader_program ("SVM", osg::Shader::VERTEX, VtxShaderProjectNV12Texture);
+ svm_model->setup_shader_program ("SVM", osg::Shader::FRAGMENT, FrgShaderProjectNV12Texture);
+
+ BowlModel::VertexMap vertices;
+ BowlModel::PointMap points;
+ BowlModel::IndexVector indices;
+
+ float a = 0;
+ float b = 0;
+ float c = 0;
+ float res_ratio = 0.3;
+ float scaling = 1000.0f;
+
+ get_bowl_model (stitcher, vertices, points, indices,
+ a, b, c, res_ratio, texture_width, texture_height );
+
+ svm_model->setup_vertex_model (vertices, points, indices, a / scaling, b / scaling, c / scaling);
+
+ return svm_model;
+}
+
+static SmartPtr<RenderOsgModel>
+create_car_model ()
+{
+ std::string car_model_path = FISHEYE_CONFIG_PATH + std::string(MODEL_NAME);
+
+ const char *env_path = std::getenv (FISHEYE_CONFIG_ENV_VAR);
+ if (env_path) {
+ car_model_path.clear ();
+ car_model_path = std::string (env_path) + std::string (MODEL_NAME);
+ }
+
+ SmartPtr<RenderOsgModel> car_model = new RenderOsgModel (car_model_path.c_str(), true);
+
+ car_model->setup_shader_program ("Car", osg::Shader::VERTEX, VtxShaderCar);
+ car_model->setup_shader_program ("Car", osg::Shader::FRAGMENT, FrgShaderCar);
+
+ float translation_x = -0.3f;
+ float translation_y = 0.0f;
+ float translation_z = 0.0f;
+ float rotation_x = 0.0f;
+ float rotation_y = 0.0f;
+ float rotation_z = 1.0f;
+ float rotation_degrees = -180.0;
+
+ car_model->setup_model_matrix (
+ translation_x,
+ translation_y,
+ translation_z,
+ rotation_x,
+ rotation_y,
+ rotation_z,
+ rotation_degrees);
+
+ return car_model;
+}
+
+static int
+run_stitcher (
+ const SmartPtr<Stitcher> &stitcher,
+ const SmartPtr<RenderOsgViewer> &render, const SmartPtr<RenderOsgModel> &model,
+ const SVStreams &ins, const SVStreams &outs, bool save_output)
+{
+ XCamReturn ret = XCAM_RETURN_NO_ERROR;
+
+ Mutex mutex;
+
+ VideoBufferList in_buffers;
+ for (uint32_t i = 0; i < ins.size (); ++i) {
+ CHECK (ins[i]->rewind (), "rewind buffer from file(%s) failed", ins[i]->get_file_name ());
+ }
+
+ do {
+ in_buffers.clear ();
+
+ for (uint32_t i = 0; i < ins.size (); ++i) {
+ ret = ins[i]->read_buf();
+ if (ret == XCAM_RETURN_BYPASS)
+ break;
+ CHECK (ret, "read buffer from file(%s) failed.", ins[i]->get_file_name ());
+ in_buffers.push_back (ins[i]->get_buf ());
+ }
+ if (ret == XCAM_RETURN_BYPASS) {
+ XCAM_LOG_DEBUG ("XCAM_RETURN_BYPASS \n");
+ break;
+ }
+
+ {
+ SmartLock locker (mutex);
+ CHECK (
+ stitcher->stitch_buffers (in_buffers, outs[0]->get_buf ()),
+ "stitch buffer failed.");
+
+ if (save_output) {
+ outs[0]->write_buf ();
+ }
+ }
+
+ model->update_texture (outs[0]->get_buf ());
+ render->start_render ();
+
+ FPS_CALCULATION (surround - view, XCAM_OBJ_DUR_FRAME_NUM);
+ } while (true);
+
+ return 0;
+}
+
+static void usage(const char* arg0)
+{
+ printf ("Usage:\n"
+ "%s --module MODULE --input0 input.nv12 --input1 input1.nv12 --input2 input2.nv12 ...\n"
+ "\t--module processing module, selected from: soft, gles\n"
+ "\t-- read calibration files from exported path $FISHEYE_CONFIG_PATH\n"
+ "\t--input0 input image(NV12)\n"
+ "\t--input1 input image(NV12)\n"
+ "\t--input2 input image(NV12)\n"
+ "\t--input3 input image(NV12)\n"
+ "\t--output output image(NV12/MP4)\n"
+ "\t--in-w optional, input width, default: 1280\n"
+ "\t--in-h optional, input height, default: 800\n"
+ "\t--out-w optional, output width, default: 1920\n"
+ "\t--out-h optional, output height, default: 640\n"
+ "\t--scale-mode optional, scaling mode for geometric mapping,\n"
+ "\t select from [singleconst/dualconst/dualcurve], default: singleconst\n"
+ "\t--save optional, save file or not, select from [true/false], default: true\n"
+ "\t--loop optional, how many loops need to run, default: 1\n"
+ "\t--help usage\n",
+ arg0);
+}
+
+int main (int argc, char *argv[])
+{
+ uint32_t input_width = 1280;
+ uint32_t input_height = 800;
+ uint32_t output_width = 1920;
+ uint32_t output_height = 640;
+
+ SVStreams ins;
+ SVStreams outs;
+
+ bool save_output = true;
+
+ SVModule module = SVModuleSoft;
+ GeoMapScaleMode scale_mode = ScaleSingleConst;
+
+ int loop = 1;
+
+ const struct option long_opts[] = {
+ {"module", required_argument, NULL, 'm'},
+ {"input0", required_argument, NULL, 'i'},
+ {"input1", required_argument, NULL, 'j'},
+ {"input2", required_argument, NULL, 'k'},
+ {"input3", required_argument, NULL, 'l'},
+ {"output", required_argument, NULL, 'o'},
+ {"in-w", required_argument, NULL, 'w'},
+ {"in-h", required_argument, NULL, 'h'},
+ {"out-w", required_argument, NULL, 'W'},
+ {"out-h", required_argument, NULL, 'H'},
+ {"scale-mode", required_argument, NULL, 'S'},
+ {"save", required_argument, NULL, 's'},
+ {"loop", required_argument, NULL, 'L'},
+ {"help", no_argument, NULL, 'e'},
+ {NULL, 0, NULL, 0},
+ };
+
+ int opt = -1;
+ while ((opt = getopt_long(argc, argv, "", long_opts, NULL)) != -1) {
+ switch (opt) {
+ case 'm':
+ XCAM_ASSERT (optarg);
+ if (!strcasecmp (optarg, "soft")) {
+ module = SVModuleSoft;
+ }
+ break;
+ case 'i':
+ XCAM_ASSERT (optarg);
+ PUSH_STREAM (SVStream, ins, optarg);
+ break;
+ case 'j':
+ XCAM_ASSERT (optarg);
+ PUSH_STREAM (SVStream, ins, optarg);
+ break;
+ case 'k':
+ XCAM_ASSERT (optarg);
+ PUSH_STREAM (SVStream, ins, optarg);
+ break;
+ case 'l':
+ XCAM_ASSERT (optarg);
+ PUSH_STREAM (SVStream, ins, optarg);
+ break;
+ case 'o':
+ XCAM_ASSERT (optarg);
+ PUSH_STREAM (SVStream, outs, optarg);
+ break;
+ case 'w':
+ input_width = atoi(optarg);
+ break;
+ case 'h':
+ input_height = atoi(optarg);
+ break;
+ case 'W':
+ output_width = atoi(optarg);
+ break;
+ case 'H':
+ output_height = atoi(optarg);
+ break;
+ case 'S':
+ XCAM_ASSERT (optarg);
+ if (!strcasecmp (optarg, "singleconst"))
+ scale_mode = ScaleSingleConst;
+ else if (!strcasecmp (optarg, "dualconst"))
+ scale_mode = ScaleDualConst;
+ else if (!strcasecmp (optarg, "dualcurve"))
+ scale_mode = ScaleDualCurve;
+ else {
+ XCAM_LOG_ERROR ("GeoMapScaleMode unknown mode: %s", optarg);
+ usage (argv[0]);
+ return -1;
+ }
+ break;
+ case 's':
+ save_output = (strcasecmp (optarg, "false") == 0 ? false : true);
+ break;
+ case 'L':
+ loop = atoi(optarg);
+ break;
+ default:
+ XCAM_LOG_ERROR ("getopt_long return unknown value: %c", opt);
+ usage (argv[0]);
+ return -1;
+ }
+ }
+
+ if (optind < argc || argc < 2) {
+ XCAM_LOG_ERROR ("unknown option %s", argv[optind]);
+ usage (argv[0]);
+ return -1;
+ }
+
+ CHECK_EXP (ins.size () == 4, "surrond view needs 4 input streams");
+ for (uint32_t i = 0; i < ins.size (); ++i) {
+ CHECK_EXP (ins[i].ptr (), "input stream is NULL, index:%d", i);
+ CHECK_EXP (strlen (ins[i]->get_file_name ()), "input file name was not set, index:%d", i);
+ }
+
+ CHECK_EXP (outs.size () == 1 && outs[0].ptr (), "surrond view needs 1 output stream");
+ CHECK_EXP (strlen (outs[0]->get_file_name ()), "output file name was not set");
+
+ for (uint32_t i = 0; i < ins.size (); ++i) {
+ printf ("input%d file:\t\t%s\n", i, ins[i]->get_file_name ());
+ }
+ printf ("output file:\t\t%s\n", outs[0]->get_file_name ());
+ printf ("input width:\t\t%d\n", input_width);
+ printf ("input height:\t\t%d\n", input_height);
+ printf ("output width:\t\t%d\n", output_width);
+ printf ("output height:\t\t%d\n", output_height);
+ printf ("scaling mode:\t\t%s\n", (scale_mode == ScaleSingleConst) ? "singleconst" :
+ ((scale_mode == ScaleDualConst) ? "dualconst" : "dualcurve"));
+ printf ("save output:\t\t%s\n", save_output ? "true" : "false");
+ printf ("loop count:\t\t%d\n", loop);
+
+ if (module == SVModuleGLES) {
+#if !HAVE_GLES
+ XCAM_LOG_ERROR ("GLES module unsupported");
+ return -1;
+#endif
+ }
+
+#if HAVE_GLES
+ SmartPtr<EGLBase> egl;
+ if (module == SVModuleGLES) {
+ egl = new EGLBase ();
+ XCAM_ASSERT (egl.ptr ());
+ XCAM_FAIL_RETURN (ERROR, egl->init (), -1, "init EGL failed");
+ }
+#endif
+
+ VideoBufferInfo in_info;
+ in_info.init (V4L2_PIX_FMT_NV12, input_width, input_height);
+ for (uint32_t i = 0; i < ins.size (); ++i) {
+ ins[i]->set_module (module);
+ ins[i]->set_buf_size (input_width, input_height);
+ CHECK (ins[i]->create_buf_pool (in_info, 6), "create buffer pool failed");
+ CHECK (ins[i]->open_reader ("rb"), "open input file(%s) failed", ins[i]->get_file_name ());
+ }
+
+ outs[0]->set_buf_size (output_width, output_height);
+ if (save_output) {
+ CHECK (outs[0]->estimate_file_format (),
+ "%s: estimate file format failed", outs[0]->get_file_name ());
+ CHECK (outs[0]->open_writer ("wb"), "open output file(%s) failed", outs[0]->get_file_name ());
+ }
+
+ SmartPtr<Stitcher> stitcher = create_stitcher (module);
+ XCAM_ASSERT (stitcher.ptr ());
+
+ CameraInfo cam_info[4];
+ std::string fisheye_config_path = FISHEYE_CONFIG_PATH;
+ const char *env = std::getenv (FISHEYE_CONFIG_ENV_VAR);
+ if (env)
+ fisheye_config_path.assign (env, strlen (env));
+ XCAM_LOG_INFO ("calibration config path:%s", fisheye_config_path.c_str ());
+
+ uint32_t camera_count = ins.size ();
+ for (uint32_t i = 0; i < camera_count; ++i) {
+ if (parse_camera_info (fisheye_config_path.c_str (), i, cam_info[i], camera_count) != 0) {
+ XCAM_LOG_ERROR ("parse fisheye dewarp info(idx:%d) failed.", i);
+ return -1;
+ }
+ }
+
+ PointFloat3 bowl_coord_offset;
+ centralize_bowl_coord_from_cameras (
+ cam_info[0].calibration.extrinsic, cam_info[1].calibration.extrinsic,
+ cam_info[2].calibration.extrinsic, cam_info[3].calibration.extrinsic,
+ bowl_coord_offset);
+
+ stitcher->set_camera_num (camera_count);
+ for (uint32_t i = 0; i < camera_count; ++i) {
+ stitcher->set_camera_info (i, cam_info[i]);
+ }
+
+ BowlDataConfig bowl;
+ bowl.wall_height = 3000.0f;
+ bowl.ground_length = 2000.0f;
+ bowl.angle_start = 0.0f;
+ bowl.angle_end = 360.0f;
+ stitcher->set_bowl_config (bowl);
+ stitcher->set_output_size (output_width, output_height);
+ stitcher->set_scale_mode (scale_mode);
+
+ SmartPtr<RenderOsgViewer> render = new RenderOsgViewer ();
+
+ SmartPtr<RenderOsgModel> svm_model = create_surround_view_model (stitcher, output_width, output_height);
+ render->add_model (svm_model);
+
+ SmartPtr<RenderOsgModel> car_model = create_car_model ();
+ render->add_model (car_model);
+
+ render->validate_model_groups ();
+
+ while (loop--) {
+ CHECK_EXP (
+ run_stitcher (stitcher, render, svm_model, ins, outs, save_output) == 0,
+ "run stitcher failed");
+ }
+
+ return 0;
+}