diff --git a/samples/java/jniviewer/.classpath b/samples/java/jniviewer/.classpath
new file mode 100644
index 0000000000..51769745b2
--- /dev/null
+++ b/samples/java/jniviewer/.classpath
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
diff --git a/samples/java/jniviewer/.externalToolBuilders/C++ Builder.launch b/samples/java/jniviewer/.externalToolBuilders/C++ Builder.launch
new file mode 100644
index 0000000000..cbe7a127ce
--- /dev/null
+++ b/samples/java/jniviewer/.externalToolBuilders/C++ Builder.launch
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/samples/java/jniviewer/.gitignore b/samples/java/jniviewer/.gitignore
new file mode 100644
index 0000000000..890072f0ac
--- /dev/null
+++ b/samples/java/jniviewer/.gitignore
@@ -0,0 +1,4 @@
+/assets
+/bin
+/gen
+/libs
diff --git a/samples/java/jniviewer/.project b/samples/java/jniviewer/.project
new file mode 100644
index 0000000000..c258add62f
--- /dev/null
+++ b/samples/java/jniviewer/.project
@@ -0,0 +1,43 @@
+
+
+ occtJniActivity
+
+
+
+
+
+ com.android.ide.eclipse.adt.ResourceManagerBuilder
+
+
+
+
+ com.android.ide.eclipse.adt.PreCompilerBuilder
+
+
+
+
+ org.eclipse.ui.externaltools.ExternalToolBuilder
+ auto,full,incremental,
+
+
+ LaunchConfigHandle
+ <project>/.externalToolBuilders/C++ Builder.launch
+
+
+
+
+ org.eclipse.jdt.core.javabuilder
+
+
+
+
+ com.android.ide.eclipse.adt.ApkBuilder
+
+
+
+
+
+ com.android.ide.eclipse.adt.AndroidNature
+ org.eclipse.jdt.core.javanature
+
+
diff --git a/samples/java/jniviewer/.settings/org.eclipse.jdt.core.prefs b/samples/java/jniviewer/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000000..b080d2ddc8
--- /dev/null
+++ b/samples/java/jniviewer/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,4 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
+org.eclipse.jdt.core.compiler.compliance=1.6
+org.eclipse.jdt.core.compiler.source=1.6
diff --git a/samples/java/jniviewer/AndroidManifest.xml b/samples/java/jniviewer/AndroidManifest.xml
new file mode 100644
index 0000000000..c0cbbbbfe8
--- /dev/null
+++ b/samples/java/jniviewer/AndroidManifest.xml
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/samples/java/jniviewer/ReadMe.md b/samples/java/jniviewer/ReadMe.md
new file mode 100644
index 0000000000..c1dd21d7f9
--- /dev/null
+++ b/samples/java/jniviewer/ReadMe.md
@@ -0,0 +1,58 @@
+OCCT JniViewer sample for Android {#samples_java_android_occt}
+==================
+
+This sample demonstrates simple way of using OCCT libraries in Android application written using Java.
+
+The connection between Java and OCCT (C++) level is provided by proxy library, libTKJniSample.so, written in C++ with exported JNI methods of Java class OcctJniRenderer.
+The proxy library contains single C++ class OcctJni_Viewer encapsulating OCCT viewer and providing functionality to manipulate this viewer
+and to import OCCT shapes from several supported formats of CAD files (IGES, STEP, BREP).
+
+This sample demonstrates indirect method of wrapping C++ to Java using manually created proxy library.
+Alternative method is available, wrapping individual OCCT classes to Java equivalents so that their full API is available to Java user
+and the code can be programmed on Java level similarly to C++ one.
+See description of OCCT Java Wrapper in Advanced Samples and Tools on OCCT web site at
+http://www.opencascade.org/support/products/advsamples
+
+Run Eclipse from ADT (Android Developer Tools) for building the sample. To import sample project perform
+~~~~
+ File -> Import... -> Android -> Existing Android code into Workspace
+~~~~
+and specify this directory. The project re-build will be started immediately right after importation if "Build automatically" option is turned on (default in Eclipse).
+Proxy library compilation and packaging is performed by NDK build script, called by "C++ Builder" configured within Eclipse project.
+The path to "ndk-build" tool from Android NDK (Native Development Kit) should be specified in Eclipse project properties:
+~~~~
+ Project -> Properties -> Builders -> C++ Builder -> Edit -> Location
+~~~~
+
+Now paths to OCCT C++ libraries and additional components should be specified in "jni/Android.mk" file:
+~~~~
+OCCT_ROOT := $(LOCAL_PATH)/../../../..
+
+FREETYPE_INC := $(OCCT_ROOT)/../freetype/include/freetype2
+FREETYPE_LIBS := $(OCCT_ROOT)/../freetype/libs
+
+FREEIMAGE_INC := $(OCCT_ROOT)/../FreeImage/include
+FREEIMAGE_LIBS := $(OCCT_ROOT)/../FreeImage/libs
+
+OCCT_INC := $(OCCT_ROOT)/inc
+OCCT_LIBS := $(OCCT_ROOT)/and/libs
+~~~~
+The list of extra components (Freetype, FreeImage) depends on OCCT configuration.
+Variable $(TARGET_ARCH_ABI) is used within this script to refer to active architecture.
+E.g. for 32-bit ARM build (see variable *APP_ABI* in "jni/Application.mk")
+the folder *OCCT_LIBS* should contain sub-folder "armeabi-v7a" with OCCT libraries.
+
+FreeImage is optional and does not required for this sample, however you should include all extra libraries used for OCCT building
+and load the explicitly from Java code within OcctJniActivity::loadNatives() method, including toolkits from OCCT itself in proper order:
+~~~~
+ if (!loadLibVerbose ("TKernel", aLoaded, aFailed)
+ || !loadLibVerbose ("TKMath", aLoaded, aFailed)
+ || !loadLibVerbose ("TKG2d", aLoaded, aFailed)
+~~~~
+Note that C++ STL library is not part of Android system.
+Thus application must package this library as well as extra component.
+"gnustl_shared" STL implementation is expected within this sample.
+
+After successful build, the application can be packaged to Android:
+- Deploy and run application on connected device or emulator directly from Eclipse using adb interface by menu items "Run" and "Debug". This would sign package with debug certificate.
+- Prepare signed end-user package using wizard File -> Export -> Android -> Export Android Application.
diff --git a/samples/java/jniviewer/jni/Android.mk b/samples/java/jniviewer/jni/Android.mk
new file mode 100644
index 0000000000..912d5e3be3
--- /dev/null
+++ b/samples/java/jniviewer/jni/Android.mk
@@ -0,0 +1,215 @@
+LOCAL_PATH:= $(call my-dir)
+
+STL_INC := $(NDK_ROOT)/sources/cxx-stl/gnu-libstdc++/$(NDK_TOOLCHAIN_VERSION)/include $(NDK_ROOT)/sources/cxx-stl/gnu-libstdc++/$(NDK_TOOLCHAIN_VERSION)/libs/$(TARGET_ARCH_ABI)/include
+#STL_LIB := $(NDK_ROOT)/sources/cxx-stl/gnu-libstdc++/$(NDK_TOOLCHAIN_VERSION)/libs/$(TARGET_ARCH_ABI)/libgnustl_static.a
+STL_LIB := $(NDK_ROOT)/sources/cxx-stl/gnu-libstdc++/$(NDK_TOOLCHAIN_VERSION)/libs/$(TARGET_ARCH_ABI)/libgnustl_shared.so
+
+OCCT_ROOT := $(LOCAL_PATH)/../../../..
+
+FREETYPE_INC := $(OCCT_ROOT)/../freetype/include/freetype2
+FREETYPE_LIBS := $(OCCT_ROOT)/../freetype/libs
+
+FREEIMAGE_INC := $(OCCT_ROOT)/../FreeImage/include
+FREEIMAGE_LIBS := $(OCCT_ROOT)/../FreeImage/libs
+
+OCCT_INC := $(OCCT_ROOT)/inc
+OCCT_LIBS := $(OCCT_ROOT)/and/libs
+
+ASSETDIR := $(LOCAL_PATH)/../assets
+
+$(ASSETDIR)/Shaders: $(ASSETDIR)
+ -mkdir -p $(ASSETDIR)
+ -mkdir -p $(ASSETDIR)/Shaders
+ cp -f -r $(OCCT_ROOT)/src/Shaders/*.* $(ASSETDIR)/Shaders
+
+$(ASSETDIR)/SHMessage: $(ASSETDIR)
+ -mkdir -p $(ASSETDIR)
+ -mkdir -p $(ASSETDIR)/SHMessage
+ cp -f -r $(OCCT_ROOT)/src/SHMessage/*.* $(ASSETDIR)/SHMessage
+
+$(ASSETDIR)/XSMessage: $(ASSETDIR)
+ -mkdir -p $(ASSETDIR)
+ -mkdir -p $(ASSETDIR)/XSMessage
+ cp -f -r $(OCCT_ROOT)/src/XSMessage/*.* $(ASSETDIR)/XSMessage
+
+$(ASSETDIR)/TObj: $(ASSETDIR)
+ -mkdir -p $(ASSETDIR)
+ -mkdir -p $(ASSETDIR)/TObj
+ cp -f -r $(OCCT_ROOT)/src/TObj/*.msg $(ASSETDIR)/TObj
+
+$(ASSETDIR)/UnitsAPI: $(ASSETDIR)
+ -mkdir -p $(ASSETDIR)
+ -mkdir -p $(ASSETDIR)/UnitsAPI
+ cp -f -r $(OCCT_ROOT)/src/UnitsAPI/*.dat $(ASSETDIR)/UnitsAPI
+
+pre_all: $(ASSETDIR)/Shaders $(ASSETDIR)/SHMessage $(ASSETDIR)/XSMessage $(ASSETDIR)/TObj $(ASSETDIR)/UnitsAPI
+
+jniall: pre_all all
+
+# STL libs
+include $(CLEAR_VARS)
+LOCAL_MODULE := SharedStl
+LOCAL_EXPORT_C_INCLUDES := $(STL_INC)
+LOCAL_SRC_FILES := $(STL_LIB)
+include $(PREBUILT_SHARED_LIBRARY)
+
+# 3rd-parties used in OCCT
+include $(CLEAR_VARS)
+LOCAL_MODULE := FreeType
+LOCAL_EXPORT_C_INCLUDES := $(FREETYPE_INC)
+LOCAL_SRC_FILES := $(FREETYPE_LIBS)/$(TARGET_ARCH_ABI)/libfreetype.so
+include $(PREBUILT_SHARED_LIBRARY)
+
+#include $(CLEAR_VARS)
+#LOCAL_MODULE := FreeImage
+#LOCAL_EXPORT_C_INCLUDES := $(FREEIMAGE_INC)
+#LOCAL_SRC_FILES := $(FREEIMAGE_LIBS)/$(TARGET_ARCH_ABI)/libfreeimage.so
+#include $(PREBUILT_SHARED_LIBRARY)
+
+# OCCT core
+include $(CLEAR_VARS)
+LOCAL_MODULE := OcctTKernel
+LOCAL_EXPORT_C_INCLUDES := $(OCCT_INC)
+LOCAL_SRC_FILES := $(OCCT_LIBS)/$(TARGET_ARCH_ABI)/libTKernel.so
+include $(PREBUILT_SHARED_LIBRARY)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := OcctTKMath
+LOCAL_SRC_FILES := $(OCCT_LIBS)/$(TARGET_ARCH_ABI)/libTKMath.so
+include $(PREBUILT_SHARED_LIBRARY)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := OcctTKG2d
+LOCAL_SRC_FILES := $(OCCT_LIBS)/$(TARGET_ARCH_ABI)/libTKG2d.so
+include $(PREBUILT_SHARED_LIBRARY)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := OcctTKG3d
+LOCAL_SRC_FILES := $(OCCT_LIBS)/$(TARGET_ARCH_ABI)/libTKG3d.so
+include $(PREBUILT_SHARED_LIBRARY)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := OcctTKGeomBase
+LOCAL_SRC_FILES := $(OCCT_LIBS)/$(TARGET_ARCH_ABI)/libTKGeomBase.so
+include $(PREBUILT_SHARED_LIBRARY)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := OcctTKBRep
+LOCAL_SRC_FILES := $(OCCT_LIBS)/$(TARGET_ARCH_ABI)/libTKBRep.so
+include $(PREBUILT_SHARED_LIBRARY)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := OcctTKGeomAlgo
+LOCAL_SRC_FILES := $(OCCT_LIBS)/$(TARGET_ARCH_ABI)/libTKGeomAlgo.so
+include $(PREBUILT_SHARED_LIBRARY)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := OcctTKTopAlgo
+LOCAL_SRC_FILES := $(OCCT_LIBS)/$(TARGET_ARCH_ABI)/libTKTopAlgo.so
+include $(PREBUILT_SHARED_LIBRARY)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := OcctTKShHealing
+LOCAL_SRC_FILES := $(OCCT_LIBS)/$(TARGET_ARCH_ABI)/libTKShHealing.so
+include $(PREBUILT_SHARED_LIBRARY)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := OcctTKMesh
+LOCAL_SRC_FILES := $(OCCT_LIBS)/$(TARGET_ARCH_ABI)/libTKMesh.so
+include $(PREBUILT_SHARED_LIBRARY)
+
+# OCCT Exchange
+include $(CLEAR_VARS)
+LOCAL_MODULE := OcctTKPrim
+LOCAL_SRC_FILES := $(OCCT_LIBS)/$(TARGET_ARCH_ABI)/libTKPrim.so
+include $(PREBUILT_SHARED_LIBRARY)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := OcctTKBO
+LOCAL_SRC_FILES := $(OCCT_LIBS)/$(TARGET_ARCH_ABI)/libTKBO.so
+include $(PREBUILT_SHARED_LIBRARY)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := OcctTKBool
+LOCAL_SRC_FILES := $(OCCT_LIBS)/$(TARGET_ARCH_ABI)/libTKBool.so
+include $(PREBUILT_SHARED_LIBRARY)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := OcctTKFillet
+LOCAL_SRC_FILES := $(OCCT_LIBS)/$(TARGET_ARCH_ABI)/libTKFillet.so
+include $(PREBUILT_SHARED_LIBRARY)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := OcctTKOffset
+LOCAL_SRC_FILES := $(OCCT_LIBS)/$(TARGET_ARCH_ABI)/libTKOffset.so
+include $(PREBUILT_SHARED_LIBRARY)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := OcctTKXSBase
+LOCAL_SRC_FILES := $(OCCT_LIBS)/$(TARGET_ARCH_ABI)/libTKXSBase.so
+include $(PREBUILT_SHARED_LIBRARY)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := OcctTKIGES
+LOCAL_SRC_FILES := $(OCCT_LIBS)/$(TARGET_ARCH_ABI)/libTKIGES.so
+include $(PREBUILT_SHARED_LIBRARY)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := OcctTKSTEPBase
+LOCAL_SRC_FILES := $(OCCT_LIBS)/$(TARGET_ARCH_ABI)/libTKSTEPBase.so
+include $(PREBUILT_SHARED_LIBRARY)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := OcctTKSTEPAttr
+LOCAL_SRC_FILES := $(OCCT_LIBS)/$(TARGET_ARCH_ABI)/libTKSTEPAttr.so
+include $(PREBUILT_SHARED_LIBRARY)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := OcctTKSTEP209
+LOCAL_SRC_FILES := $(OCCT_LIBS)/$(TARGET_ARCH_ABI)/libTKSTEP209.so
+include $(PREBUILT_SHARED_LIBRARY)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := OcctTKSTEP
+LOCAL_SRC_FILES := $(OCCT_LIBS)/$(TARGET_ARCH_ABI)/libTKSTEP.so
+include $(PREBUILT_SHARED_LIBRARY)
+
+# OCCT visualization
+include $(CLEAR_VARS)
+LOCAL_MODULE := OcctTKService
+LOCAL_SRC_FILES := $(OCCT_LIBS)/$(TARGET_ARCH_ABI)/libTKService.so
+include $(PREBUILT_SHARED_LIBRARY)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := OcctTKHLR
+LOCAL_SRC_FILES := $(OCCT_LIBS)/$(TARGET_ARCH_ABI)/libTKHLR.so
+include $(PREBUILT_SHARED_LIBRARY)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := OcctTKV3d
+LOCAL_SRC_FILES := $(OCCT_LIBS)/$(TARGET_ARCH_ABI)/libTKV3d.so
+include $(PREBUILT_SHARED_LIBRARY)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := OcctTKOpenGl
+LOCAL_SRC_FILES := $(OCCT_LIBS)/$(TARGET_ARCH_ABI)/libTKOpenGl.so
+include $(PREBUILT_SHARED_LIBRARY)
+
+# our sample
+include $(CLEAR_VARS)
+LOCAL_MODULE := libTKJniSample
+LOCAL_C_INCLUDES := $(STL_INC)
+#LOCAL_STATIC_LIBRARIES := $(STL_LIB) does not work
+LOCAL_CFLAGS := -Wall
+LOCAL_CPP_EXTENSION := .cxx .cpp
+LOCAL_CPP_FEATURES := rtti exceptions
+LOCAL_SRC_FILES := OcctJni_Viewer.cxx OcctJni_Window.cxx OcctJni_MsgPrinter.cxx
+LOCAL_SHARED_LIBRARIES := OcctTKernel OcctTKMath OcctTKG2d OcctTKG3d OcctTKGeomBase OcctTKBRep OcctTKGeomAlgo OcctTKTopAlgo OcctTKShHealing OcctTKMesh OcctTKPrim
+LOCAL_SHARED_LIBRARIES += OcctTKIGES OcctTKSTEP OcctTKXSBase
+LOCAL_SHARED_LIBRARIES += OcctTKService OcctTKHLR OcctTKV3d OcctTKOpenGl
+LOCAL_SHARED_LIBRARIES += SharedStl
+LOCAL_LDLIBS := -llog -lGLESv2 -lEGL
+
+#LOCAL_LDLIBS += $(STL_LIB)
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/samples/java/jniviewer/jni/Application.mk b/samples/java/jniviewer/jni/Application.mk
new file mode 100644
index 0000000000..1d6b63382a
--- /dev/null
+++ b/samples/java/jniviewer/jni/Application.mk
@@ -0,0 +1,8 @@
+NDK_TOOLCHAIN_VERSION := 4.8
+APP_PLATFORM := android-15
+
+APP_ABI := armeabi-v7a
+#APP_ABI := all
+
+#APP_STL := gnustl_static
+#APP_STL := stlport_static
diff --git a/samples/java/jniviewer/jni/OcctJni_MsgPrinter.cxx b/samples/java/jniviewer/jni/OcctJni_MsgPrinter.cxx
new file mode 100644
index 0000000000..8eef25f58c
--- /dev/null
+++ b/samples/java/jniviewer/jni/OcctJni_MsgPrinter.cxx
@@ -0,0 +1,102 @@
+// Copyright (c) 2014 OPEN CASCADE SAS
+//
+// This file is part of Open CASCADE Technology software library.
+//
+// This library is free software; you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License version 2.1 as published
+// by the Free Software Foundation, with special exception defined in the file
+// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
+// distribution for complete text of the license and disclaimer of any warranty.
+//
+// Alternatively, this file may be used under the terms of Open CASCADE
+// commercial license or contractual agreement.
+
+#include
+
+#include
+#include
+
+#include
+
+IMPLEMENT_STANDARD_HANDLE (OcctJni_MsgPrinter, Message_Printer)
+IMPLEMENT_STANDARD_RTTIEXT(OcctJni_MsgPrinter, Message_Printer)
+
+// =======================================================================
+// function : OcctJni_MsgPrinter
+// purpose :
+// =======================================================================
+OcctJni_MsgPrinter::OcctJni_MsgPrinter (JNIEnv* theJEnv,
+ jobject theJObj)
+: myJEnv (theJEnv),
+ myJObj (theJEnv->NewGlobalRef (theJObj)),
+ myJMet (NULL)
+{
+ jclass aJClass = theJEnv->GetObjectClass (theJObj);
+ myJMet = theJEnv->GetMethodID (aJClass, "postMessage", "(Ljava/lang/String;)V");
+ if (myJMet == NULL)
+ {
+ __android_log_write (ANDROID_LOG_FATAL, "jniSample", "Broken initialization of OcctJni_MsgPrinter!");
+ }
+}
+
+// =======================================================================
+// function : ~OcctJni_MsgPrinter
+// purpose :
+// =======================================================================
+OcctJni_MsgPrinter::~OcctJni_MsgPrinter()
+{
+ //myJEnv->DeleteGlobalRef (myJObj);
+}
+
+// =======================================================================
+// function : Send
+// purpose :
+// =======================================================================
+void OcctJni_MsgPrinter::Send (const TCollection_ExtendedString& theString,
+ const Message_Gravity theGravity,
+ const Standard_Boolean theToPutEndl) const
+{
+ if (theGravity >= myTraceLevel)
+ {
+ const TCollection_AsciiString aStr (theString);
+ OcctJni_MsgPrinter::Send (aStr, theGravity, theToPutEndl);
+ }
+}
+
+// =======================================================================
+// function : Send
+// purpose :
+// =======================================================================
+void OcctJni_MsgPrinter::Send (const TCollection_AsciiString& theString,
+ const Message_Gravity theGravity,
+ const Standard_Boolean theToPutEndl) const
+{
+ if (theGravity < myTraceLevel)
+ {
+ return;
+ }
+
+ ///__android_log_write (ANDROID_LOG_DEBUG, "OcctJni_MsgPrinter", (TCollection_AsciiString(" @@ ") + theString).ToCString());
+ if (myJMet == NULL)
+ {
+ return;
+ }
+
+ jstring aJStr = myJEnv->NewStringUTF ((theString + "\n").ToCString());
+ myJEnv->CallObjectMethod (myJObj, myJMet, aJStr);
+ myJEnv->DeleteLocalRef (aJStr);
+}
+
+// =======================================================================
+// function : Send
+// purpose :
+// =======================================================================
+void OcctJni_MsgPrinter::Send (const Standard_CString& theString,
+ const Message_Gravity theGravity,
+ const Standard_Boolean theToPutEndl) const
+{
+ if (theGravity >= myTraceLevel)
+ {
+ OcctJni_MsgPrinter::Send (TCollection_AsciiString (theString), theGravity, theToPutEndl);
+ }
+}
diff --git a/samples/java/jniviewer/jni/OcctJni_MsgPrinter.hxx b/samples/java/jniviewer/jni/OcctJni_MsgPrinter.hxx
new file mode 100644
index 0000000000..0735033b4d
--- /dev/null
+++ b/samples/java/jniviewer/jni/OcctJni_MsgPrinter.hxx
@@ -0,0 +1,62 @@
+// Copyright (c) 2014 OPEN CASCADE SAS
+//
+// This file is part of Open CASCADE Technology software library.
+//
+// This library is free software; you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License version 2.1 as published
+// by the Free Software Foundation, with special exception defined in the file
+// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
+// distribution for complete text of the license and disclaimer of any warranty.
+//
+// Alternatively, this file may be used under the terms of Open CASCADE
+// commercial license or contractual agreement.
+
+#ifndef OcctJni_MsgPrinter_H
+#define OcctJni_MsgPrinter_H
+
+#include
+
+#include
+
+// Class providing connection between messenger interfaces in C++ and Java layers.
+class OcctJni_MsgPrinter : public Message_Printer
+{
+public:
+
+ //! Default constructor
+ OcctJni_MsgPrinter (JNIEnv* theJEnv,
+ jobject theJObj);
+
+ //! Destructor.
+ ~OcctJni_MsgPrinter();
+
+ //! Redirection to TCollection_AsciiString method
+ virtual void Send (const TCollection_ExtendedString& theString,
+ const Message_Gravity theGravity,
+ const Standard_Boolean theToPutEndl) const;
+
+ //! Redirection to TCollection_AsciiString method
+ virtual void Send (const Standard_CString& theString,
+ const Message_Gravity theGravity,
+ const Standard_Boolean theToPutEndl) const;
+
+ //! Main printing method
+ virtual void Send (const TCollection_AsciiString& theString,
+ const Message_Gravity theGravity,
+ const Standard_Boolean theToPutEndl) const;
+
+private:
+
+ JNIEnv* myJEnv;
+ jobject myJObj;
+ jmethodID myJMet;
+
+public:
+
+ DEFINE_STANDARD_RTTI(OcctJni_MsgPrinter)
+
+};
+
+DEFINE_STANDARD_HANDLE(OcctJni_MsgPrinter, Message_Printer)
+
+#endif // OcctJni_MsgPrinter_H
diff --git a/samples/java/jniviewer/jni/OcctJni_Viewer.cxx b/samples/java/jniviewer/jni/OcctJni_Viewer.cxx
new file mode 100644
index 0000000000..750f030e91
--- /dev/null
+++ b/samples/java/jniviewer/jni/OcctJni_Viewer.cxx
@@ -0,0 +1,810 @@
+// Copyright (c) 2014 OPEN CASCADE SAS
+//
+// This file is part of Open CASCADE Technology software library.
+//
+// This library is free software; you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License version 2.1 as published
+// by the Free Software Foundation, with special exception defined in the file
+// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
+// distribution for complete text of the license and disclaimer of any warranty.
+//
+// Alternatively, this file may be used under the terms of Open CASCADE
+// commercial license or contractual agreement.
+
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+
+#include
+#include
+#include
+
+#include
+
+#include
+#include
+
+#include
+
+//! @return true if file exists
+static bool isFileExist (const TCollection_AsciiString& thePath)
+{
+ struct stat64 aStatBuffer;
+ return stat64 (thePath.ToCString(), &aStatBuffer) == 0;
+}
+
+//! Cut-off the last split character from the path and everything after it.
+static TCollection_AsciiString getParentDir (const TCollection_AsciiString& thePath)
+{
+ TCollection_AsciiString aPath = thePath;
+ char* aSplitter = (char* )aPath.ToCString();
+ for (char* anIter = aSplitter; *anIter != '\0'; ++anIter)
+ {
+ if (*anIter == '\\'
+ || *anIter == '/')
+ {
+ aSplitter = anIter;
+ }
+ }
+ *aSplitter = '\0'; // cut off file name or trailing folder
+ return TCollection_AsciiString (aPath.ToCString());
+}
+
+//! Set environment variable theVarName indicating location of resource
+//! file theFile so as to correspond to actual location of this file.
+//!
+//! The resource file is searched in directory where Test.Draw.dll is located,
+//! and if not found - also in subdirectory ../res from there.
+//! If file is found, environment variable is set for C subsystem.
+//! Otherwise, environment is not changed.
+//!
+//! If theToAddFileName is true, complete file name is set as value of the variable,
+//! if theToAddFileName is false, only path is set.
+Standard_Boolean setResourceEnv (const TCollection_AsciiString& theVarName,
+ const TCollection_AsciiString& theRoot,
+ const TCollection_AsciiString& theFile,
+ const Standard_Boolean theToAddFileName)
+{
+ // use location of current assembly to figure out possible location of resource
+ TCollection_AsciiString aBaseDir = theRoot;
+
+ // check the same directory where binary is located
+ if (!isFileExist (aBaseDir + "/" + theFile))
+ {
+ // check subdirectory ../res
+ aBaseDir = getParentDir (aBaseDir) + "/res";
+ if (!isFileExist (aBaseDir + "/" + theFile))
+ {
+ return Standard_False;
+ }
+ }
+
+ // set C library environment
+ if (theToAddFileName)
+ {
+ aBaseDir = aBaseDir + "/" + theFile;
+ }
+
+ OSD_Environment anEnv (theVarName, aBaseDir);
+ anEnv.Build();
+ return Standard_True;
+}
+
+// =======================================================================
+// function : OcctJni_Viewer
+// purpose :
+// =======================================================================
+OcctJni_Viewer::OcctJni_Viewer()
+{
+ // prepare necessary environment
+ TCollection_AsciiString aResRoot = "/data/data/com.opencascade.jnisample/files";
+
+ setResourceEnv ("CSF_TObjMessage", aResRoot + "/TObj", "TObj.msg", Standard_False);
+ setResourceEnv ("CSF_UnitsLexicon", aResRoot + "/UnitsAPI", "Lexi_Expr.dat", Standard_True);
+ setResourceEnv ("CSF_UnitsDefinition", aResRoot + "/UnitsAPI", "Units.dat", Standard_True);
+ setResourceEnv ("CSF_ShadersDirectory", aResRoot + "/Shaders", "Declarations.glsl", Standard_False);
+ setResourceEnv ("CSF_XSMessage", aResRoot + "/XSMessage", "XSTEP.us", Standard_False);
+ setResourceEnv ("CSF_SHMessage", aResRoot + "/XSMessage", "SHAPE.us", Standard_False);
+ //setResourceEnv ("CSF_PluginDefaults", "Plugin", Standard_False);
+
+ // make sure OCCT loads the dictionary
+ //UnitsAPI::SetLocalSystem (UnitsAPI_SI);
+
+ // load messages for TObj
+ Message_MsgFile::LoadFromEnv ("CSF_TObjMessage", "TObj", "msg");
+}
+
+// =======================================================================
+// function : init
+// purpose :
+// =======================================================================
+bool OcctJni_Viewer::init()
+{
+ EGLint aCfgId = 0;
+ int aWidth = 0, aHeight = 0;
+ EGLDisplay anEglDisplay = eglGetCurrentDisplay();
+ EGLContext anEglContext = eglGetCurrentContext();
+ EGLSurface anEglSurf = eglGetCurrentSurface (EGL_DRAW);
+ if (anEglDisplay == EGL_NO_DISPLAY
+ || anEglContext == EGL_NO_CONTEXT
+ || anEglSurf == EGL_NO_SURFACE)
+ {
+ Message::DefaultMessenger()->Send ("Error: No active EGL context!", Message_Fail);
+ release();
+ return false;
+ }
+
+ eglQuerySurface (anEglDisplay, anEglSurf, EGL_WIDTH, &aWidth);
+ eglQuerySurface (anEglDisplay, anEglSurf, EGL_HEIGHT, &aHeight);
+ eglQuerySurface (anEglDisplay, anEglSurf, EGL_CONFIG_ID, &aCfgId);
+ const EGLint aConfigAttribs[] = { EGL_CONFIG_ID, aCfgId, EGL_NONE };
+ EGLint aNbConfigs = 0;
+ void* anEglConfig = NULL;
+ if (eglChooseConfig (anEglDisplay, aConfigAttribs, &anEglConfig, 1, &aNbConfigs) != EGL_TRUE)
+ {
+ Message::DefaultMessenger()->Send ("Error: EGL does not provide compatible configurations!", Message_Fail);
+ release();
+ return false;
+ }
+
+ TCollection_AsciiString anEglInfo = TCollection_AsciiString()
+ + "\n EGLVersion: " + eglQueryString (anEglDisplay, EGL_VERSION)
+ + "\n EGLVendor: " + eglQueryString (anEglDisplay, EGL_VENDOR)
+ + "\n EGLClient APIs: " + eglQueryString (anEglDisplay, EGL_CLIENT_APIS)
+ + "\n GLvendor: " + (const char* )glGetString (GL_VENDOR)
+ + "\n GLdevice: " + (const char* )glGetString (GL_RENDERER)
+ + "\n GLversion: " + (const char* )glGetString (GL_VERSION) + " [GLSL: " + (const char* )glGetString (GL_SHADING_LANGUAGE_VERSION) + "]";
+ ::Message::DefaultMessenger()->Send (anEglInfo, Message_Info);
+
+ if (!myViewer.IsNull())
+ {
+ Handle(OpenGl_GraphicDriver) aDriver = Handle(OpenGl_GraphicDriver)::DownCast (myViewer->Driver());
+ Handle(OcctJni_Window) aWindow = Handle(OcctJni_Window)::DownCast (myView->Window());
+ if (!aDriver->InitEglContext (anEglDisplay, anEglContext, anEglConfig))
+ {
+ Message::DefaultMessenger()->Send ("Error: OpenGl_GraphicDriver can not be initialized!", Message_Fail);
+ release();
+ return false;
+ }
+
+ aWindow->SetSize (aWidth, aHeight);
+ myView->SetWindow (aWindow, (Aspect_RenderingContext )anEglContext, NULL, NULL);
+ return true;
+ }
+
+ Handle(OpenGl_GraphicDriver) aDriver = new OpenGl_GraphicDriver (NULL, Standard_False);
+ aDriver->ChangeOptions().buffersNoSwap = Standard_True;
+//aDriver->ChangeOptions().glslWarnings = Standard_True; /// for debug only!
+ if (!aDriver->InitEglContext (anEglDisplay, anEglContext, anEglConfig))
+ {
+ Message::DefaultMessenger()->Send ("Error: OpenGl_GraphicDriver can not be initialized!", Message_Fail);
+ release();
+ return false;
+ }
+
+ // create viewer
+ myViewer = new V3d_Viewer (aDriver, TCollection_ExtendedString("Viewer").ToExtString(), "", 1000.0,
+ V3d_XposYnegZpos, Quantity_NOC_BLACK, V3d_ZBUFFER, V3d_GOURAUD, V3d_WAIT,
+ Standard_True, Standard_False);
+ myViewer->SetDefaultLights();
+ myViewer->SetLightOn();
+
+ // create AIS context
+ myContext = new AIS_InteractiveContext (myViewer);
+ //myContext->SetDisplayMode (AIS_WireFrame);
+ myContext->SetDisplayMode (AIS_Shaded);
+
+ Handle(OcctJni_Window) aWindow = new OcctJni_Window (aWidth, aHeight);
+ myView = myViewer->CreateView();
+
+ myView->SetWindow (aWindow, (Aspect_RenderingContext )anEglContext, NULL, NULL);
+ myView->TriedronDisplay (Aspect_TOTP_RIGHT_LOWER, Quantity_NOC_WHITE, 0.08, V3d_ZBUFFER);
+
+ initContent();
+ return true;
+}
+
+// =======================================================================
+// function : release
+// purpose :
+// =======================================================================
+void OcctJni_Viewer::release()
+{
+ myContext.Nullify();
+ myView.Nullify();
+ myViewer.Nullify();
+}
+
+// =======================================================================
+// function : resize
+// purpose :
+// =======================================================================
+void OcctJni_Viewer::resize (int theWidth,
+ int theHeight)
+{
+ if (myContext.IsNull())
+ {
+ Message::DefaultMessenger()->Send ("Resize failed - view is unavailable", Message_Fail);
+ return;
+ }
+
+ Handle(OpenGl_GraphicDriver) aDriver = Handle(OpenGl_GraphicDriver)::DownCast (myViewer->Driver());
+ Handle(OcctJni_Window) aWindow = Handle(OcctJni_Window)::DownCast (myView->Window());
+ aWindow->SetSize (theWidth, theHeight);
+ //myView->MustBeResized(); // can be used instead of SetWindow() when EGLsurface has not been changed
+
+ EGLContext anEglContext = eglGetCurrentContext();
+ myView->SetWindow (aWindow, (Aspect_RenderingContext )anEglContext, NULL, NULL);
+ //saveSnapshot ("/sdcard/Download/tt.png", theWidth, theHeight);
+}
+
+// =======================================================================
+// function : initContent
+// purpose :
+// =======================================================================
+void OcctJni_Viewer::initContent()
+{
+ myContext->RemoveAll (Standard_False);
+
+ OSD_Timer aTimer;
+ aTimer.Start();
+ if (!myShape.IsNull())
+ {
+ Handle(AIS_Shape) aShapePrs = new AIS_Shape (myShape);
+ myContext->Display (aShapePrs, Standard_False);
+ }
+ else
+ {
+ BRepPrimAPI_MakeBox aBuilder (1.0, 2.0, 3.0);
+ Handle(AIS_Shape) aShapePrs = new AIS_Shape (aBuilder.Shape());
+ myContext->Display (aShapePrs, Standard_False);
+ }
+ myView->FitAll();
+
+ aTimer.Stop();
+ Message::DefaultMessenger()->Send (TCollection_AsciiString() + "Presentation computed in " + aTimer.ElapsedTime() + " seconds", Message_Info);
+}
+
+//! Load shape from IGES file
+static TopoDS_Shape loadIGES (const TCollection_AsciiString& thePath)
+{
+ TopoDS_Shape aShape;
+ IGESControl_Reader aReader;
+ IFSelect_ReturnStatus aReadStatus = IFSelect_RetFail;
+ try
+ {
+ aReadStatus = aReader.ReadFile (thePath.ToCString());
+ }
+ catch (Standard_Failure)
+ {
+ Message::DefaultMessenger()->Send ("Error: IGES reader, computation error", Message_Fail);
+ return aShape;
+ }
+
+ if (aReadStatus != IFSelect_RetDone)
+ {
+ Message::DefaultMessenger()->Send ("Error: IGES reader, bad file format", Message_Fail);
+ return aShape;
+ }
+
+ // now perform the translation
+ aReader.TransferRoots();
+ if (aReader.NbShapes() <= 0)
+ {
+ Handle(XSControl_WorkSession) aWorkSession = new XSControl_WorkSession();
+ aWorkSession->SelectNorm ("IGES");
+ aReader.SetWS (aWorkSession, Standard_True);
+ aReader.SetReadVisible (Standard_False);
+ aReader.TransferRoots();
+ }
+ if (aReader.NbShapes() <= 0)
+ {
+ Message::DefaultMessenger()->Send ("Error: IGES reader, no shapes has been found", Message_Fail);
+ return aShape;
+ }
+ return aReader.OneShape();
+ /*TopoDS_Shape anImportedShape = aReader.OneShape();
+
+ // apply sewing on the imported shape
+ BRepBuilderAPI_Sewing aTool (0.0);
+ aTool.SetNonManifoldMode (Standard_False);
+ aTool.SetFloatingEdgesMode(Standard_True);
+ aTool.Load (anImportedShape);
+ aTool.Perform();
+ TopoDS_Shape aSewedShape = aTool.SewedShape();
+
+ if (aSewedShape.IsNull())
+ {
+ Message::DefaultMessenger()->Send ("Error: Sewing result is empty", Message_Fail);
+ return aShape;
+ }
+ if (aSewedShape.IsSame(anImportedShape))
+ {
+ aShape = anImportedShape;
+ }
+ else
+ {
+ // apply shape healing
+ ShapeFix_Shape aShapeFixer(aSewedShape);
+ aShapeFixer.FixSolidMode() = 1;
+ aShapeFixer.FixFreeShellMode() = 1;
+ aShapeFixer.FixFreeFaceMode() = 1;
+ aShapeFixer.FixFreeWireMode() = 0;
+ aShapeFixer.FixSameParameterMode() = 0;
+ aShapeFixer.FixVertexPositionMode() = 0;
+ aShape = aShapeFixer.Perform() ? aShapeFixer.Shape() : aSewedShape;
+ }
+ return aShape;*/
+}
+
+//! Load shape from STEP file
+static TopoDS_Shape loadSTEP (const TCollection_AsciiString& thePath)
+{
+ STEPControl_Reader aReader;
+ IFSelect_ReturnStatus aReadStatus = IFSelect_RetFail;
+ try
+ {
+ aReadStatus = aReader.ReadFile (thePath.ToCString());
+ }
+ catch (Standard_Failure)
+ {
+ Message::DefaultMessenger()->Send ("Error: STEP reader, computation error", Message_Fail);
+ return TopoDS_Shape();
+ }
+
+ if (aReadStatus != IFSelect_RetDone)
+ {
+ Message::DefaultMessenger()->Send ("Error: STEP reader, bad file format", Message_Fail);
+ return TopoDS_Shape();
+ }
+ else if (aReader.NbRootsForTransfer() <= 0)
+ {
+ Message::DefaultMessenger()->Send ("Error: STEP reader, shape is empty", Message_Fail);
+ return TopoDS_Shape();
+ }
+
+ // now perform the translation
+ aReader.TransferRoots();
+ return aReader.OneShape();
+}
+
+// =======================================================================
+// function : open
+// purpose :
+// =======================================================================
+bool OcctJni_Viewer::open (const TCollection_AsciiString& thePath)
+{
+ myShape.Nullify();
+ if (!myContext.IsNull())
+ {
+ myContext->RemoveAll (Standard_False);
+ }
+ if (thePath.IsEmpty())
+ {
+ return false;
+ }
+
+ OSD_Timer aTimer;
+ aTimer.Start();
+ TCollection_AsciiString aFormatStr;
+ const Standard_Integer aLen = thePath.Length();
+ if (aLen >= 5
+ && thePath.Value (aLen - 4) == '.')
+ {
+ aFormatStr = thePath.SubString (aLen - 3, aLen);
+ }
+ else if (aLen >= 4
+ && thePath.Value (aLen - 3) == '.')
+ {
+ aFormatStr = thePath.SubString (aLen - 2, aLen);
+ }
+ else if (aLen >= 3
+ && thePath.Value (aLen - 2) == '.')
+ {
+ aFormatStr = thePath.SubString (aLen - 1, aLen);
+ }
+ aFormatStr.LowerCase();
+
+ TopoDS_Shape aShape;
+ if (aFormatStr == "stp"
+ || aFormatStr == "step")
+ {
+ aShape = loadSTEP (thePath);
+ }
+ else if (aFormatStr == "igs"
+ || aFormatStr == "iges")
+ {
+ aShape = loadIGES (thePath);
+ }
+ else
+ // if (aFormatStr == "brep"
+ // || aFormatStr == "rle")
+ {
+ BRep_Builder aBuilder;
+ if (!BRepTools::Read (aShape, thePath.ToCString(), aBuilder))
+ {
+ Message::DefaultMessenger()->Send (TCollection_AsciiString() + "Error: file '" + thePath + "' can not be opened!", Message_Info);
+ return false;
+ }
+ }
+ if (aShape.IsNull())
+ {
+ return false;
+ }
+ aTimer.Stop();
+ Message::DefaultMessenger()->Send (TCollection_AsciiString() + "File '" + thePath + "' loaded in " + aTimer.ElapsedTime() + " seconds", Message_Info);
+
+ myShape = aShape;
+ if (myContext.IsNull())
+ {
+ return true;
+ }
+
+ aTimer.Reset();
+ aTimer.Start();
+
+ Handle(AIS_Shape) aShapePrs = new AIS_Shape (aShape);
+ myContext->Display (aShapePrs, Standard_False);
+ myView->FitAll();
+
+ aTimer.Stop();
+ Message::DefaultMessenger()->Send (TCollection_AsciiString() + "Presentation computed in " + aTimer.ElapsedTime() + " seconds", Message_Info);
+ return true;
+}
+
+// =======================================================================
+// function : saveSnapshot
+// purpose :
+// =======================================================================
+bool OcctJni_Viewer::saveSnapshot (const TCollection_AsciiString& thePath,
+ int theWidth,
+ int theHeight)
+{
+ if (myContext.IsNull()
+ || thePath.IsEmpty())
+ {
+ Message::DefaultMessenger()->Send ("Image dump failed - view is unavailable", Message_Fail);
+ return false;
+ }
+
+ if (theWidth < 1
+ || theHeight < 1)
+ {
+ myView->Window()->Size (theWidth, theHeight);
+ }
+ if (theWidth < 1
+ || theHeight < 1)
+ {
+ Message::DefaultMessenger()->Send ("Image dump failed - view is unavailable", Message_Fail);
+ return false;
+ }
+
+ Image_AlienPixMap anAlienImage;
+ if (!anAlienImage.InitTrash (Image_PixMap::ImgBGRA, theWidth, theHeight))
+ {
+ Message::DefaultMessenger()->Send (TCollection_AsciiString() + "RGBA image " + theWidth + "x" + theHeight + " allocation failed", Message_Fail);
+ return false;
+ }
+
+ // OpenGL ES does not support fetching data in BGRA format
+ // while FreeImage does not support RGBA format.
+ Image_PixMap anImage;
+ anImage.InitWrapper (Image_PixMap::ImgRGBA,
+ anAlienImage.ChangeData(),
+ anAlienImage.SizeX(),
+ anAlienImage.SizeY(),
+ anAlienImage.SizeRowBytes());
+ if (!myView->ToPixMap (anImage, theWidth, theHeight, Graphic3d_BT_RGBA))
+ {
+ Message::DefaultMessenger()->Send (TCollection_AsciiString() + "View dump to the image " + theWidth + "x" + theHeight + " failed", Message_Fail);
+ }
+
+ for (Standard_Size aRow = 0; aRow < anAlienImage.SizeY(); ++aRow)
+ {
+ for (Standard_Size aCol = 0; aCol < anAlienImage.SizeX(); ++aCol)
+ {
+ Image_ColorRGBA& aPixel = anAlienImage.ChangeValue (aRow, aCol);
+ std::swap (aPixel.r(), aPixel.b());
+ //aPixel.a() = 1.0;
+ }
+ }
+
+ if (!anAlienImage.Save (thePath))
+ {
+ Message::DefaultMessenger()->Send (TCollection_AsciiString() + "Image saving to path '" + thePath + "' failed", Message_Fail);
+ return false;
+ }
+ Message::DefaultMessenger()->Send (TCollection_AsciiString() + "View " + theWidth + "x" + theHeight + " dumped to image '" + thePath + "'", Message_Info);
+ return true;
+}
+
+// =======================================================================
+// function : redraw
+// purpose :
+// =======================================================================
+void OcctJni_Viewer::redraw()
+{
+ if (myView.IsNull())
+ {
+ return;
+ }
+
+ myView->Redraw();
+}
+
+// =======================================================================
+// function : fitAll
+// purpose :
+// =======================================================================
+void OcctJni_Viewer::fitAll()
+{
+ if (myView.IsNull())
+ {
+ return;
+ }
+
+ myView->FitAll();
+}
+
+// =======================================================================
+// function : startRotation
+// purpose :
+// =======================================================================
+void OcctJni_Viewer::startRotation (int theStartX,
+ int theStartY)
+{
+ if (myView.IsNull())
+ {
+ return;
+ }
+
+ myView->StartRotation (theStartX, theStartY, 0.45);
+}
+
+// =======================================================================
+// function : onRotation
+// purpose :
+// =======================================================================
+void OcctJni_Viewer::onRotation (int theX,
+ int theY)
+{
+ if (myView.IsNull())
+ {
+ return;
+ }
+
+ myView->Rotation (theX, theY);
+}
+
+// =======================================================================
+// function : onPanning
+// purpose :
+// =======================================================================
+void OcctJni_Viewer::onPanning (int theDX,
+ int theDY)
+{
+ if (myView.IsNull())
+ {
+ return;
+ }
+
+ myView->Pan (theDX, theDY);
+}
+
+// =======================================================================
+// function : onClick
+// purpose :
+// =======================================================================
+void OcctJni_Viewer::onClick (int theX,
+ int theY)
+{
+ if (myView.IsNull())
+ {
+ return;
+ }
+
+ myContext->MoveTo (theX, theY, myView, Standard_False);
+ myContext->Select (Standard_True);
+}
+
+// =======================================================================
+// function : stopAction
+// purpose :
+// =======================================================================
+void OcctJni_Viewer::stopAction()
+{
+ if (myView.IsNull())
+ {
+ return;
+ }
+}
+
+#define jexp extern "C" JNIEXPORT
+
+jexp jlong JNICALL Java_com_opencascade_jnisample_OcctJniRenderer_cppCreate (JNIEnv* theEnv,
+ jobject theObj)
+{
+ return jlong(new OcctJni_Viewer());
+}
+
+jexp void JNICALL Java_com_opencascade_jnisample_OcctJniRenderer_cppDestroy (JNIEnv* theEnv,
+ jobject theObj,
+ jlong theCppPtr)
+{
+ delete (OcctJni_Viewer* )theCppPtr;
+
+ Handle(Message_Messenger) aMsgMgr = Message::DefaultMessenger();
+ aMsgMgr->RemovePrinters (STANDARD_TYPE (OcctJni_MsgPrinter));
+}
+
+jexp void JNICALL Java_com_opencascade_jnisample_OcctJniRenderer_cppRelease (JNIEnv* theEnv,
+ jobject theObj,
+ jlong theCppPtr)
+{
+ ((OcctJni_Viewer* )theCppPtr)->release();
+}
+
+jexp void JNICALL Java_com_opencascade_jnisample_OcctJniRenderer_cppInit (JNIEnv* theEnv,
+ jobject theObj,
+ jlong theCppPtr)
+{
+ Handle(Message_Messenger) aMsgMgr = Message::DefaultMessenger();
+ aMsgMgr->RemovePrinters (STANDARD_TYPE (OcctJni_MsgPrinter));
+ aMsgMgr->AddPrinter (new OcctJni_MsgPrinter (theEnv, theObj));
+ ((OcctJni_Viewer* )theCppPtr)->init();
+}
+
+jexp void JNICALL Java_com_opencascade_jnisample_OcctJniRenderer_cppResize (JNIEnv* theEnv,
+ jobject theObj,
+ jlong theCppPtr,
+ jint theWidth,
+ jint theHeight)
+{
+ ((OcctJni_Viewer* )theCppPtr)->resize (theWidth, theHeight);
+}
+
+jexp void JNICALL Java_com_opencascade_jnisample_OcctJniRenderer_cppOpen (JNIEnv* theEnv,
+ jobject theObj,
+ jlong theCppPtr,
+ jstring thePath)
+{
+ const char* aPathPtr = theEnv->GetStringUTFChars (thePath, 0);
+ const TCollection_AsciiString aPath (aPathPtr);
+ theEnv->ReleaseStringUTFChars (thePath, aPathPtr);
+ ((OcctJni_Viewer* )theCppPtr)->open (aPath);
+}
+
+jexp void JNICALL Java_com_opencascade_jnisample_OcctJniRenderer_cppRedraw (JNIEnv* theEnv,
+ jobject theObj,
+ jlong theCppPtr)
+{
+ ((OcctJni_Viewer* )theCppPtr)->redraw();
+}
+
+jexp void JNICALL Java_com_opencascade_jnisample_OcctJniRenderer_cppSetAxoProj (JNIEnv* theEnv,
+ jobject theObj,
+ jlong theCppPtr)
+{
+ ((OcctJni_Viewer* )theCppPtr)->setProj (V3d_XposYnegZpos);
+}
+
+jexp void JNICALL Java_com_opencascade_jnisample_OcctJniRenderer_cppSetXposProj (JNIEnv* theEnv,
+ jobject theObj,
+ jlong theCppPtr)
+{
+ ((OcctJni_Viewer* )theCppPtr)->setProj (V3d_Xpos);
+}
+
+jexp void JNICALL Java_com_opencascade_jnisample_OcctJniRenderer_cppSetYposProj (JNIEnv* theEnv,
+ jobject theObj,
+ jlong theCppPtr)
+{
+ ((OcctJni_Viewer* )theCppPtr)->setProj (V3d_Ypos);
+}
+
+jexp void JNICALL Java_com_opencascade_jnisample_OcctJniRenderer_cppSetZposProj (JNIEnv* theEnv,
+ jobject theObj,
+ jlong theCppPtr)
+{
+ ((OcctJni_Viewer* )theCppPtr)->setProj (V3d_Zpos);
+}
+
+jexp void JNICALL Java_com_opencascade_jnisample_OcctJniRenderer_cppSetXnegProj (JNIEnv* theEnv,
+ jobject theObj,
+ jlong theCppPtr)
+{
+ ((OcctJni_Viewer* )theCppPtr)->setProj (V3d_Xneg);
+}
+
+jexp void JNICALL Java_com_opencascade_jnisample_OcctJniRenderer_cppSetYnegProj (JNIEnv* theEnv,
+ jobject theObj,
+ jlong theCppPtr)
+{
+ ((OcctJni_Viewer* )theCppPtr)->setProj (V3d_Yneg);
+}
+
+jexp void JNICALL Java_com_opencascade_jnisample_OcctJniRenderer_cppSetZnegProj (JNIEnv* theEnv,
+ jobject theObj,
+ jlong theCppPtr)
+{
+ ((OcctJni_Viewer* )theCppPtr)->setProj (V3d_Zneg);
+}
+
+jexp void JNICALL Java_com_opencascade_jnisample_OcctJniRenderer_cppFitAll (JNIEnv* theEnv,
+ jobject theObj,
+ jlong theCppPtr)
+{
+ ((OcctJni_Viewer* )theCppPtr)->fitAll();
+}
+
+jexp void JNICALL Java_com_opencascade_jnisample_OcctJniRenderer_cppStartRotation (JNIEnv* theEnv,
+ jobject theObj,
+ jlong theCppPtr,
+ jint theStartX,
+ jint theStartY)
+{
+ ((OcctJni_Viewer* )theCppPtr)->startRotation (theStartX, theStartY);
+}
+
+jexp void JNICALL Java_com_opencascade_jnisample_OcctJniRenderer_cppOnRotation (JNIEnv* theEnv,
+ jobject theObj,
+ jlong theCppPtr,
+ jint theX,
+ jint theY)
+{
+ ((OcctJni_Viewer* )theCppPtr)->onRotation (theX, theY);
+}
+
+jexp void JNICALL Java_com_opencascade_jnisample_OcctJniRenderer_cppOnPanning (JNIEnv* theEnv,
+ jobject theObj,
+ jlong theCppPtr,
+ jint theDX,
+ jint theDY)
+{
+ ((OcctJni_Viewer* )theCppPtr)->onPanning (theDX, theDY);
+}
+
+jexp void JNICALL Java_com_opencascade_jnisample_OcctJniRenderer_cppOnClick (JNIEnv* theEnv,
+ jobject theObj,
+ jlong theCppPtr,
+ jint theX,
+ jint theY)
+{
+ ((OcctJni_Viewer* )theCppPtr)->onClick (theX, theY);
+}
+
+jexp void JNICALL Java_com_opencascade_jnisample_OcctJniRenderer_cppStopAction (JNIEnv* theEnv,
+ jobject theObj,
+ jlong theCppPtr)
+{
+ ((OcctJni_Viewer* )theCppPtr)->stopAction();
+}
+
+jexp jlong JNICALL Java_com_opencascade_jnisample_OcctJniActivity_cppOcctMajorVersion (JNIEnv* theEnv,
+ jobject theObj)
+{
+ return OCC_VERSION_MAJOR;
+}
+
+jexp jlong JNICALL Java_com_opencascade_jnisample_OcctJniActivity_cppOcctMinorVersion (JNIEnv* theEnv,
+ jobject theObj)
+{
+ return OCC_VERSION_MINOR;
+}
+
+jexp jlong JNICALL Java_com_opencascade_jnisample_OcctJniActivity_cppOcctMicroVersion (JNIEnv* theEnv,
+ jobject theObj)
+{
+ return OCC_VERSION_MAINTENANCE;
+}
diff --git a/samples/java/jniviewer/jni/OcctJni_Viewer.hxx b/samples/java/jniviewer/jni/OcctJni_Viewer.hxx
new file mode 100644
index 0000000000..6bd0a41f3e
--- /dev/null
+++ b/samples/java/jniviewer/jni/OcctJni_Viewer.hxx
@@ -0,0 +1,88 @@
+// Copyright (c) 2014 OPEN CASCADE SAS
+//
+// This file is part of Open CASCADE Technology software library.
+//
+// This library is free software; you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License version 2.1 as published
+// by the Free Software Foundation, with special exception defined in the file
+// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
+// distribution for complete text of the license and disclaimer of any warranty.
+//
+// Alternatively, this file may be used under the terms of Open CASCADE
+// commercial license or contractual agreement.
+
+#include
+
+#include
+#include
+#include
+#include
+
+//! Main C++ back-end for activity.
+class OcctJni_Viewer
+{
+
+public:
+
+ //! Empty constructor
+ OcctJni_Viewer();
+
+ //! Initialize the viewer
+ bool init();
+
+ //! Release the viewer
+ void release();
+
+ //! Resize the viewer
+ void resize (int theWidth,
+ int theHeight);
+
+ //! Open CAD file
+ bool open (const TCollection_AsciiString& thePath);
+
+ //! Take snapshot
+ bool saveSnapshot (const TCollection_AsciiString& thePath,
+ int theWidth = 0,
+ int theHeight = 0);
+
+ //! Viewer update.
+ void redraw();
+
+ //! Move camera
+ void setProj (V3d_TypeOfOrientation theProj) { if (!myView.IsNull()) myView->SetProj (theProj); }
+
+ //! Fit All.
+ void fitAll();
+
+ //! Start rotation (remember first point position)
+ void startRotation (int theStartX,
+ int theStartY);
+
+ //! Perform rotation (relative to first point)
+ void onRotation (int theX,
+ int theY);
+
+ //! Perform panning
+ void onPanning (int theDX,
+ int theDY);
+
+ //! Perform selection
+ void onClick (int theX,
+ int theY);
+
+ //! Stop previously started action
+ void stopAction();
+
+protected:
+
+ //! Reset viewer content.
+ void initContent();
+
+protected:
+
+ Handle(V3d_Viewer) myViewer;
+ Handle(V3d_View) myView;
+ Handle(AIS_InteractiveContext) myContext;
+ TopoDS_Shape myShape;
+
+};
diff --git a/samples/java/jniviewer/jni/OcctJni_Window.cxx b/samples/java/jniviewer/jni/OcctJni_Window.cxx
new file mode 100644
index 0000000000..8f50abde3b
--- /dev/null
+++ b/samples/java/jniviewer/jni/OcctJni_Window.cxx
@@ -0,0 +1,17 @@
+// Copyright (c) 2014 OPEN CASCADE SAS
+//
+// This file is part of Open CASCADE Technology software library.
+//
+// This library is free software; you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License version 2.1 as published
+// by the Free Software Foundation, with special exception defined in the file
+// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
+// distribution for complete text of the license and disclaimer of any warranty.
+//
+// Alternatively, this file may be used under the terms of Open CASCADE
+// commercial license or contractual agreement.
+
+#include
+
+IMPLEMENT_STANDARD_HANDLE (OcctJni_Window, Aspect_Window)
+IMPLEMENT_STANDARD_RTTIEXT(OcctJni_Window, Aspect_Window)
diff --git a/samples/java/jniviewer/jni/OcctJni_Window.hxx b/samples/java/jniviewer/jni/OcctJni_Window.hxx
new file mode 100644
index 0000000000..d73c4a6629
--- /dev/null
+++ b/samples/java/jniviewer/jni/OcctJni_Window.hxx
@@ -0,0 +1,106 @@
+// Copyright (c) 2014 OPEN CASCADE SAS
+//
+// This file is part of Open CASCADE Technology software library.
+//
+// This library is free software; you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License version 2.1 as published
+// by the Free Software Foundation, with special exception defined in the file
+// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
+// distribution for complete text of the license and disclaimer of any warranty.
+//
+// Alternatively, this file may be used under the terms of Open CASCADE
+// commercial license or contractual agreement.
+
+#ifndef OcctJni_Window_H
+#define OcctJni_Window_H
+
+#include
+
+//! This class defines dummy window
+class OcctJni_Window : public Aspect_Window
+{
+
+public:
+
+ //! Creates a wrapper over existing Window handle
+ OcctJni_Window (const int theWidth, const int theHeight)
+ : myWidth (theWidth), myHeight(theHeight) {}
+
+ //! Returns native Window handle
+ virtual Aspect_Drawable NativeHandle() const { return 0; }
+
+ //! Returns parent of native Window handle
+ virtual Aspect_Drawable NativeParentHandle() const { return 0; }
+
+ virtual void Destroy() {}
+
+ //! Opens the window
+ virtual void Map() const {}
+
+ //! Closes the window
+ virtual void Unmap() const {}
+
+ //! Applies the resizing to the window
+ virtual Aspect_TypeOfResize DoResize() const { return Aspect_TOR_UNKNOWN; }
+
+ //! Apply the mapping change to the window
+ virtual Standard_Boolean DoMapping() const { return Standard_True; }
+
+ //! Returns True if the window is opened
+ virtual Standard_Boolean IsMapped() const { return Standard_True; }
+
+ //! Returns The Window RATIO equal to the physical WIDTH/HEIGHT dimensions
+ virtual Quantity_Ratio Ratio() const { return 1.0; }
+
+ //! Returns The Window POSITION in PIXEL
+ virtual void Position (Standard_Integer& theX1,
+ Standard_Integer& theY1,
+ Standard_Integer& theX2,
+ Standard_Integer& theY2) const
+ {
+ theX1 = 0;
+ theX2 = myWidth;
+ theY1 = 0;
+ theY2 = myHeight;
+ }
+
+ //! Set The Window POSITION in PIXEL
+ virtual void SetPosition (const Standard_Integer theX1,
+ const Standard_Integer theY1,
+ const Standard_Integer theX2,
+ const Standard_Integer theY2)
+ {
+ myWidth = theX2 - theX1;
+ myHeight = theY2 - theY1;
+ }
+
+ //! Returns The Window SIZE in PIXEL
+ virtual void Size (Standard_Integer& theWidth,
+ Standard_Integer& theHeight) const
+ {
+ theWidth = myWidth;
+ theHeight = myHeight;
+ }
+
+ //! Set The Window SIZE in PIXEL
+ virtual void SetSize (const Standard_Integer theWidth,
+ const Standard_Integer theHeight)
+ {
+ myWidth = theWidth;
+ myHeight = theHeight;
+ }
+
+private:
+
+ int myWidth;
+ int myHeight;
+
+public:
+
+ DEFINE_STANDARD_RTTI(OcctJni_Window)
+
+};
+
+DEFINE_STANDARD_HANDLE(OcctJni_Window, Aspect_Window)
+
+#endif // OcctJni_Window_H
diff --git a/samples/java/jniviewer/project.properties b/samples/java/jniviewer/project.properties
new file mode 100644
index 0000000000..0840b4a059
--- /dev/null
+++ b/samples/java/jniviewer/project.properties
@@ -0,0 +1,14 @@
+# This file is automatically generated by Android Tools.
+# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
+#
+# This file must be checked in Version Control Systems.
+#
+# To customize properties used by the Ant build system edit
+# "ant.properties", and override values to adapt the script to your
+# project structure.
+#
+# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
+#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
+
+# Project target.
+target=android-15
diff --git a/samples/java/jniviewer/res/drawable-hdpi/close_l.png b/samples/java/jniviewer/res/drawable-hdpi/close_l.png
new file mode 100644
index 0000000000..0125c4aaf8
Binary files /dev/null and b/samples/java/jniviewer/res/drawable-hdpi/close_l.png differ
diff --git a/samples/java/jniviewer/res/drawable-hdpi/close_p.png b/samples/java/jniviewer/res/drawable-hdpi/close_p.png
new file mode 100644
index 0000000000..b5ce8bdfd0
Binary files /dev/null and b/samples/java/jniviewer/res/drawable-hdpi/close_p.png differ
diff --git a/samples/java/jniviewer/res/drawable-hdpi/fit.png b/samples/java/jniviewer/res/drawable-hdpi/fit.png
new file mode 100644
index 0000000000..70daee140c
Binary files /dev/null and b/samples/java/jniviewer/res/drawable-hdpi/fit.png differ
diff --git a/samples/java/jniviewer/res/drawable-hdpi/ic_launcher.png b/samples/java/jniviewer/res/drawable-hdpi/ic_launcher.png
new file mode 100755
index 0000000000..d27ba82c09
Binary files /dev/null and b/samples/java/jniviewer/res/drawable-hdpi/ic_launcher.png differ
diff --git a/samples/java/jniviewer/res/drawable-hdpi/info.png b/samples/java/jniviewer/res/drawable-hdpi/info.png
new file mode 100644
index 0000000000..88d27c8e51
Binary files /dev/null and b/samples/java/jniviewer/res/drawable-hdpi/info.png differ
diff --git a/samples/java/jniviewer/res/drawable-hdpi/info_image.png b/samples/java/jniviewer/res/drawable-hdpi/info_image.png
new file mode 100644
index 0000000000..bac9bead0f
Binary files /dev/null and b/samples/java/jniviewer/res/drawable-hdpi/info_image.png differ
diff --git a/samples/java/jniviewer/res/drawable-hdpi/message.png b/samples/java/jniviewer/res/drawable-hdpi/message.png
new file mode 100644
index 0000000000..a3dc8cc209
Binary files /dev/null and b/samples/java/jniviewer/res/drawable-hdpi/message.png differ
diff --git a/samples/java/jniviewer/res/drawable-hdpi/open.png b/samples/java/jniviewer/res/drawable-hdpi/open.png
new file mode 100644
index 0000000000..68e52659f9
Binary files /dev/null and b/samples/java/jniviewer/res/drawable-hdpi/open.png differ
diff --git a/samples/java/jniviewer/res/drawable-hdpi/open_l.png b/samples/java/jniviewer/res/drawable-hdpi/open_l.png
new file mode 100644
index 0000000000..6069ce3893
Binary files /dev/null and b/samples/java/jniviewer/res/drawable-hdpi/open_l.png differ
diff --git a/samples/java/jniviewer/res/drawable-hdpi/open_p.png b/samples/java/jniviewer/res/drawable-hdpi/open_p.png
new file mode 100644
index 0000000000..c0898e6d6a
Binary files /dev/null and b/samples/java/jniviewer/res/drawable-hdpi/open_p.png differ
diff --git a/samples/java/jniviewer/res/drawable-hdpi/proj_back.png b/samples/java/jniviewer/res/drawable-hdpi/proj_back.png
new file mode 100755
index 0000000000..77ab199ab5
Binary files /dev/null and b/samples/java/jniviewer/res/drawable-hdpi/proj_back.png differ
diff --git a/samples/java/jniviewer/res/drawable-hdpi/proj_bottom.png b/samples/java/jniviewer/res/drawable-hdpi/proj_bottom.png
new file mode 100755
index 0000000000..b0bb012866
Binary files /dev/null and b/samples/java/jniviewer/res/drawable-hdpi/proj_bottom.png differ
diff --git a/samples/java/jniviewer/res/drawable-hdpi/proj_front.png b/samples/java/jniviewer/res/drawable-hdpi/proj_front.png
new file mode 100755
index 0000000000..b93d4d3e09
Binary files /dev/null and b/samples/java/jniviewer/res/drawable-hdpi/proj_front.png differ
diff --git a/samples/java/jniviewer/res/drawable-hdpi/proj_left.png b/samples/java/jniviewer/res/drawable-hdpi/proj_left.png
new file mode 100755
index 0000000000..bce95df901
Binary files /dev/null and b/samples/java/jniviewer/res/drawable-hdpi/proj_left.png differ
diff --git a/samples/java/jniviewer/res/drawable-hdpi/proj_right.png b/samples/java/jniviewer/res/drawable-hdpi/proj_right.png
new file mode 100755
index 0000000000..8cdb338b4c
Binary files /dev/null and b/samples/java/jniviewer/res/drawable-hdpi/proj_right.png differ
diff --git a/samples/java/jniviewer/res/drawable-hdpi/proj_top.png b/samples/java/jniviewer/res/drawable-hdpi/proj_top.png
new file mode 100755
index 0000000000..4ad098fc80
Binary files /dev/null and b/samples/java/jniviewer/res/drawable-hdpi/proj_top.png differ
diff --git a/samples/java/jniviewer/res/drawable-hdpi/view.png b/samples/java/jniviewer/res/drawable-hdpi/view.png
new file mode 100644
index 0000000000..76ce87949a
Binary files /dev/null and b/samples/java/jniviewer/res/drawable-hdpi/view.png differ
diff --git a/samples/java/jniviewer/res/drawable-mdpi/ic_launcher.png b/samples/java/jniviewer/res/drawable-mdpi/ic_launcher.png
new file mode 100755
index 0000000000..4b86dbf5e9
Binary files /dev/null and b/samples/java/jniviewer/res/drawable-mdpi/ic_launcher.png differ
diff --git a/samples/java/jniviewer/res/drawable-xhdpi/ic_launcher.png b/samples/java/jniviewer/res/drawable-xhdpi/ic_launcher.png
new file mode 100755
index 0000000000..cd79bea162
Binary files /dev/null and b/samples/java/jniviewer/res/drawable-xhdpi/ic_launcher.png differ
diff --git a/samples/java/jniviewer/res/drawable-xxhdpi/ic_launcher.png b/samples/java/jniviewer/res/drawable-xxhdpi/ic_launcher.png
new file mode 100755
index 0000000000..a34301f386
Binary files /dev/null and b/samples/java/jniviewer/res/drawable-xxhdpi/ic_launcher.png differ
diff --git a/samples/java/jniviewer/res/layout/activity_main.xml b/samples/java/jniviewer/res/layout/activity_main.xml
new file mode 100644
index 0000000000..e7f3ebfd66
--- /dev/null
+++ b/samples/java/jniviewer/res/layout/activity_main.xml
@@ -0,0 +1,166 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/samples/java/jniviewer/res/values/id.xml b/samples/java/jniviewer/res/values/id.xml
new file mode 100644
index 0000000000..56bde943a6
--- /dev/null
+++ b/samples/java/jniviewer/res/values/id.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/samples/java/jniviewer/res/values/strings.xml b/samples/java/jniviewer/res/values/strings.xml
new file mode 100644
index 0000000000..6f2a431604
--- /dev/null
+++ b/samples/java/jniviewer/res/values/strings.xml
@@ -0,0 +1,35 @@
+
+
+ OpenCASCADE JNI Java Sample
+ #484848
+ #0099CC
+ #66252525
+
+ - .png
+ - .jpg
+
+
+ - .brep
+ - .rle
+ - .iges
+ - .igs
+ - .step
+ - .stp
+
+ wireframe/shading
+ color
+ material
+ transparency
+ show/hide hidden lines
+
+ OpenCASCADE JNI Java Sample
+ Simple viewer for BREP, STEP and IGES files.
+ Driven by Open CASCADE Technology %d.%d.%d.
+ Copyright 2014 OPEN CASCADE SAS.
+ 
+ http://www.opencascade.com
+ http://www.opencascade.org
+ ]]>
+
+
diff --git a/samples/java/jniviewer/src/com/opencascade/jnisample/OcctJniActivity.java b/samples/java/jniviewer/src/com/opencascade/jnisample/OcctJniActivity.java
new file mode 100644
index 0000000000..7cb5366496
--- /dev/null
+++ b/samples/java/jniviewer/src/com/opencascade/jnisample/OcctJniActivity.java
@@ -0,0 +1,778 @@
+// Copyright (c) 2014 OPEN CASCADE SAS
+//
+// This file is part of Open CASCADE Technology software library.
+//
+// This library is free software; you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License version 2.1 as published
+// by the Free Software Foundation, with special exception defined in the file
+// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
+// distribution for complete text of the license and disclaimer of any warranty.
+//
+// Alternatively, this file may be used under the terms of Open CASCADE
+// commercial license or contractual agreement.
+
+package com.opencascade.jnisample;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Arrays;
+import java.util.List;
+
+import android.app.Activity;
+import android.content.Context;
+
+import android.content.Intent;
+import android.content.res.AssetManager;
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.graphics.Point;
+import android.graphics.drawable.Drawable;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Environment;
+
+import android.text.Html;
+import android.text.Html.ImageGetter;
+import android.text.Spanned;
+import android.util.TypedValue;
+import android.view.Display;
+import android.view.Gravity;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.ViewGroup;
+import android.widget.ImageButton;
+import android.widget.LinearLayout;
+import android.view.ViewGroup.LayoutParams;
+import android.widget.TextView;
+import android.widget.Toast;
+
+//! Main activity
+public class OcctJniActivity extends Activity implements OnClickListener
+{
+
+ //! Auxiliary method to print temporary info messages
+ public static void printShortInfo (Activity theActivity,
+ CharSequence theInfo)
+ {
+ Context aCtx = theActivity.getApplicationContext();
+ Toast aToast = Toast.makeText (aCtx, theInfo, Toast.LENGTH_LONG);
+ aToast.show();
+ }
+
+ //! Load single native library
+ private static boolean loadLibVerbose (String theLibName,
+ StringBuilder theLoadedInfo,
+ StringBuilder theFailedInfo)
+ {
+ try
+ {
+ System.loadLibrary (theLibName);
+ theLoadedInfo.append ("Info: native library \"");
+ theLoadedInfo.append (theLibName);
+ theLoadedInfo.append ("\" has been loaded\n");
+ return true;
+ }
+ catch (java.lang.UnsatisfiedLinkError theError)
+ {
+ theFailedInfo.append ("Error: native library \"");
+ theFailedInfo.append (theLibName);
+ theFailedInfo.append ("\" is unavailable:\n " + theError.getMessage());
+ return false;
+ }
+ catch (SecurityException theError)
+ {
+ theFailedInfo.append ("Error: native library \"");
+ theFailedInfo.append (theLibName);
+ theFailedInfo.append ("\" can not be loaded for security reasons:\n " + theError.getMessage());
+ return false;
+ }
+ }
+
+ public static boolean wasNativesLoadCalled = false;
+ public static boolean areNativeLoaded = false;
+ public static String nativeLoaded = "";
+ public static String nativeFailed = "";
+
+ //! Auxiliary method to load native libraries
+ public boolean loadNatives()
+ {
+ if (wasNativesLoadCalled)
+ {
+ return areNativeLoaded;
+ }
+ wasNativesLoadCalled = true;
+ StringBuilder aLoaded = new StringBuilder();
+ StringBuilder aFailed = new StringBuilder();
+
+ // copy OCCT resources
+ String aResFolder = getFilesDir().getAbsolutePath();
+ copyAssetFolder (getAssets(), "Shaders", aResFolder + "/Shaders");
+ copyAssetFolder (getAssets(), "SHMessage", aResFolder + "/SHMessage");
+ copyAssetFolder (getAssets(), "XSMessage", aResFolder + "/XSMessage");
+ copyAssetFolder (getAssets(), "TObj", aResFolder + "/TObj");
+ copyAssetFolder (getAssets(), "UnitsAPI", aResFolder + "/UnitsAPI");
+
+ // C++ runtime
+ loadLibVerbose ("gnustl_shared", aLoaded, aFailed);
+
+ // 3rd-parties
+ loadLibVerbose ("freetype", aLoaded, aFailed);
+ loadLibVerbose ("freeimage", aLoaded, aFailed);
+
+ if (// OCCT modeling
+ !loadLibVerbose ("TKernel", aLoaded, aFailed)
+ || !loadLibVerbose ("TKMath", aLoaded, aFailed)
+ || !loadLibVerbose ("TKG2d", aLoaded, aFailed)
+ || !loadLibVerbose ("TKG3d", aLoaded, aFailed)
+ || !loadLibVerbose ("TKGeomBase", aLoaded, aFailed)
+ || !loadLibVerbose ("TKBRep", aLoaded, aFailed)
+ || !loadLibVerbose ("TKGeomAlgo", aLoaded, aFailed)
+ || !loadLibVerbose ("TKTopAlgo", aLoaded, aFailed)
+ || !loadLibVerbose ("TKShHealing", aLoaded, aFailed)
+ || !loadLibVerbose ("TKMesh", aLoaded, aFailed)
+ // exchange
+ || !loadLibVerbose ("TKPrim", aLoaded, aFailed)
+ || !loadLibVerbose ("TKBO", aLoaded, aFailed)
+ || !loadLibVerbose ("TKBool", aLoaded, aFailed)
+ || !loadLibVerbose ("TKFillet", aLoaded, aFailed)
+ || !loadLibVerbose ("TKOffset", aLoaded, aFailed)
+ || !loadLibVerbose ("TKXSBase", aLoaded, aFailed)
+ || !loadLibVerbose ("TKIGES", aLoaded, aFailed)
+ || !loadLibVerbose ("TKSTEPBase", aLoaded, aFailed)
+ || !loadLibVerbose ("TKSTEPAttr", aLoaded, aFailed)
+ || !loadLibVerbose ("TKSTEP209", aLoaded, aFailed)
+ || !loadLibVerbose ("TKSTEP", aLoaded, aFailed)
+ // OCCT Visualization
+ || !loadLibVerbose ("TKService", aLoaded, aFailed)
+ || !loadLibVerbose ("TKHLR", aLoaded, aFailed)
+ || !loadLibVerbose ("TKV3d", aLoaded, aFailed)
+ || !loadLibVerbose ("TKOpenGl", aLoaded, aFailed)
+ // application code
+ || !loadLibVerbose ("TKJniSample", aLoaded, aFailed))
+ {
+ nativeLoaded = aLoaded.toString();
+ nativeFailed = aFailed.toString();
+ areNativeLoaded = false;
+ //exitWithError (theActivity, "Broken apk?\n" + theFailedInfo);
+ return false;
+ }
+ nativeLoaded = aLoaded.toString();
+ areNativeLoaded = true;
+ return true;
+ }
+
+ //! Create activity
+ @Override protected void onCreate (Bundle theBundle)
+ {
+ super.onCreate (theBundle);
+
+ boolean isLoaded = loadNatives();
+ if (!isLoaded)
+ {
+ printShortInfo (this, nativeFailed);
+ OcctJniLogger.postMessage (nativeLoaded + "\n" + nativeFailed);
+ }
+
+ setContentView (R.layout.activity_main);
+
+ myOcctView = (OcctJniView )findViewById (R.id.custom_view);
+ myMessageTextView = (TextView )findViewById (R.id.message_view);
+ OcctJniLogger.setTextView (myMessageTextView);
+
+ createViewAndButtons (Configuration.ORIENTATION_LANDSCAPE);
+
+ myButtonPreferSize = defineButtonSize ((LinearLayout )findViewById (R.id.panel_menu));
+ ImageButton aScrollBtn = (ImageButton )findViewById (R.id.scroll_btn);
+ aScrollBtn.setY (myButtonPreferSize);
+ aScrollBtn.setOnTouchListener (new View.OnTouchListener()
+ {
+ @Override
+ public boolean onTouch (View theView, MotionEvent theEvent)
+ {
+ return onScrollBtnTouch (theView, theEvent);
+ }
+ });
+
+ onConfigurationChanged (getResources().getConfiguration());
+
+ Intent anIntent = getIntent();
+ Uri aDataUrl = anIntent != null ? anIntent.getData() : null;
+ String aDataPath = aDataUrl != null ? aDataUrl.getPath() : "";
+ myOcctView.open (aDataPath);
+ myLastPath = aDataPath;
+ }
+
+ //! Handle scroll events
+ private boolean onScrollBtnTouch (View theView,
+ MotionEvent theEvent)
+ {
+ switch (theEvent.getAction())
+ {
+ case MotionEvent.ACTION_DOWN:
+ {
+ LinearLayout aPanelMenu = (LinearLayout )findViewById (R.id.panel_menu);
+ boolean isLandscape = (getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE);
+ if (aPanelMenu.getVisibility() == View.VISIBLE)
+ {
+ aPanelMenu.setVisibility (View.GONE);
+ if (!isLandscape)
+ {
+ ((ImageButton )theView).setImageResource (R.drawable.open_p);
+ theView.setY (0);
+ }
+ else
+ {
+ ((ImageButton )theView).setImageResource (R.drawable.open_l);
+ theView.setX (0);
+ }
+ }
+ else
+ {
+ aPanelMenu.setVisibility (View.VISIBLE);
+ if (!isLandscape)
+ {
+ ((ImageButton )theView).setImageResource (R.drawable.close_p);
+ theView.setY (myButtonPreferSize);
+ }
+ else
+ {
+ ((ImageButton )theView).setImageResource (R.drawable.close_l);
+ theView.setX (myButtonPreferSize);
+ }
+ }
+ break;
+ }
+ }
+ return false;
+ }
+
+ //! Initialize views and buttons
+ private void createViewAndButtons (int theOrientation)
+ {
+ // open button
+ ImageButton anOpenButton = (ImageButton )findViewById (R.id.open);
+ anOpenButton.setOnClickListener (this);
+
+ // fit all
+ ImageButton aFitAllButton = (ImageButton )findViewById (R.id.fit);
+ aFitAllButton.setOnClickListener (this);
+ aFitAllButton.setOnTouchListener (new View.OnTouchListener()
+ {
+ @Override
+ public boolean onTouch (View theView, MotionEvent theEvent)
+ {
+ return onTouchButton (theView, theEvent);
+ }
+ });
+
+ // message
+ ImageButton aMessageButton = (ImageButton )findViewById (R.id.message);
+ aMessageButton.setOnClickListener (this);
+
+ // info
+ ImageButton anInfoButton = (ImageButton )findViewById (R.id.info);
+ anInfoButton.setOnClickListener (this);
+
+ // font for text view
+ TextView anInfoView = (TextView )findViewById (R.id.info_view);
+ anInfoView.setTextSize (TypedValue.COMPLEX_UNIT_SP, 18);
+
+ // add submenu buttons
+ createSubmenuBtn (R.id.view, R.id.view_group,
+ Arrays.asList (R.id.proj_front, R.id.proj_top, R.id.proj_left,
+ R.id.proj_back, R.id.proj_bottom, R.id.proj_right),
+ Arrays.asList (R.drawable.proj_front, R.drawable.proj_top, R.drawable.proj_left,
+ R.drawable.proj_back, R.drawable.proj_bottom, R.drawable.proj_right),
+ 4);
+ }
+
+ @Override protected void onNewIntent (Intent theIntent)
+ {
+ super.onNewIntent (theIntent);
+ setIntent (theIntent);
+ }
+
+ @Override protected void onDestroy()
+ {
+ super.onDestroy();
+ OcctJniLogger.setTextView (null);
+ }
+
+ @Override protected void onPause()
+ {
+ super.onPause();
+ myOcctView.onPause();
+ }
+
+ @Override protected void onResume()
+ {
+ super.onResume();
+ myOcctView.onResume();
+
+ Intent anIntent = getIntent();
+ Uri aDataUrl = anIntent != null ? anIntent.getData() : null;
+ String aDataPath = aDataUrl != null ? aDataUrl.getPath() : "";
+ if (!aDataPath.equals (myLastPath))
+ {
+ myOcctView.open (aDataPath);
+ myLastPath = aDataPath;
+ }
+ }
+
+ //! Copy folder from assets
+ private boolean copyAssetFolder (AssetManager theAssetMgr,
+ String theAssetFolder,
+ String theFolderPathTo)
+ {
+ try
+ {
+ String[] aFiles = theAssetMgr.list (theAssetFolder);
+ File aFolder = new File (theFolderPathTo);
+ aFolder.mkdirs();
+ boolean isOk = true;
+ for (String aFileIter : aFiles)
+ {
+ if (aFileIter.contains ("."))
+ {
+ isOk &= copyAsset (theAssetMgr,
+ theAssetFolder + "/" + aFileIter,
+ theFolderPathTo + "/" + aFileIter);
+ }
+ else
+ {
+ isOk &= copyAssetFolder (theAssetMgr,
+ theAssetFolder + "/" + aFileIter,
+ theFolderPathTo + "/" + aFileIter);
+ }
+ }
+ return isOk;
+ }
+ catch (Exception theError)
+ {
+ theError.printStackTrace();
+ return false;
+ }
+ }
+
+ //! Copy single file from assets
+ private boolean copyAsset (AssetManager theAssetMgr,
+ String thePathFrom,
+ String thePathTo)
+ {
+ try
+ {
+ InputStream aStreamIn = theAssetMgr.open (thePathFrom);
+ File aFileTo = new File (thePathTo);
+ aFileTo.createNewFile();
+ OutputStream aStreamOut = new FileOutputStream (thePathTo);
+ copyStreamContent (aStreamIn, aStreamOut);
+ aStreamIn.close();
+ aStreamIn = null;
+ aStreamOut.flush();
+ aStreamOut.close();
+ aStreamOut = null;
+ return true;
+ }
+ catch (Exception theError)
+ {
+ theError.printStackTrace();
+ return false;
+ }
+ }
+
+ //! Copy single file
+ private static void copyStreamContent (InputStream theIn,
+ OutputStream theOut) throws IOException
+ {
+ byte[] aBuffer = new byte[1024];
+ int aNbReadBytes = 0;
+ while ((aNbReadBytes = theIn.read (aBuffer)) != -1)
+ {
+ theOut.write (aBuffer, 0, aNbReadBytes);
+ }
+ }
+
+ //! Show/hide text view
+ private void switchTextView (TextView theTextView,
+ ImageButton theClickedBtn,
+ boolean theToSwitchOn)
+ {
+ if (theTextView != null
+ && theTextView.getVisibility() == View.GONE
+ && theToSwitchOn)
+ {
+ theTextView.setVisibility (View.VISIBLE);
+ theClickedBtn.setBackgroundColor (getResources().getColor(R.color.pressedBtnColor));
+ setTextViewPosition (theTextView);
+ }
+ else
+ {
+ theTextView.setVisibility (View.GONE);
+ theClickedBtn.setBackgroundColor (getResources().getColor (R.color.btnColor));
+ }
+ }
+
+ //! Setup text view position
+ private void setTextViewPosition (TextView theTextView)
+ {
+ if (theTextView.getVisibility() != View.VISIBLE)
+ {
+ return;
+ }
+
+ if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE)
+ {
+ theTextView.setX (myButtonPreferSize);
+ theTextView.setY (0);
+ }
+ else
+ {
+ theTextView.setX (0);
+ theTextView.setY (myButtonPreferSize);
+ }
+ }
+
+ @Override
+ public void onClick (View theButton)
+ {
+ ImageButton aClickedBtn = (ImageButton )theButton;
+ switch (aClickedBtn.getId())
+ {
+ case R.id.message:
+ {
+ switchTextView ((TextView )findViewById (R.id.info_view),
+ (ImageButton )findViewById (R.id.info), false);
+ switchTextView (myMessageTextView, aClickedBtn, true);
+ return;
+ }
+ case R.id.info:
+ {
+ String aText = getString (R.string.info_html);
+ aText = String.format (aText, cppOcctMajorVersion(), cppOcctMinorVersion(), cppOcctMicroVersion());
+ Spanned aSpanned = Html.fromHtml (aText, new ImageGetter()
+ {
+ @Override
+ public Drawable getDrawable (String theSource)
+ {
+ Resources aResources = getResources();
+ int anId = aResources.getIdentifier (theSource, "drawable", getPackageName());
+ Drawable aRes = aResources.getDrawable (anId);
+ aRes.setBounds (0, 0, aRes.getIntrinsicWidth(), aRes.getIntrinsicHeight());
+ return aRes;
+ }
+ }, null);
+
+ TextView anInfoView = (TextView )findViewById (R.id.info_view);
+ anInfoView.setText (aSpanned);
+ switchTextView (myMessageTextView, (ImageButton ) findViewById (R.id.message), false);
+ switchTextView (anInfoView, aClickedBtn, true);
+ return;
+ }
+ case R.id.fit:
+ {
+ myOcctView.fitAll();
+ return;
+ }
+ case R.id.proj_front:
+ {
+ myOcctView.setProj (OcctJniRenderer.TypeOfOrientation.Xpos);
+ return;
+ }
+ case R.id.proj_left:
+ {
+ myOcctView.setProj (OcctJniRenderer.TypeOfOrientation.Yneg);
+ return;
+ }
+ case R.id.proj_top:
+ {
+ myOcctView.setProj (OcctJniRenderer.TypeOfOrientation.Zpos);
+ return;
+ }
+ case R.id.proj_back:
+ {
+ myOcctView.setProj (OcctJniRenderer.TypeOfOrientation.Xneg);
+ return;
+ }
+ case R.id.proj_right:
+ {
+ myOcctView.setProj (OcctJniRenderer.TypeOfOrientation.Ypos);
+ return;
+ }
+ case R.id.proj_bottom:
+ {
+ myOcctView.setProj (OcctJniRenderer.TypeOfOrientation.Zneg);
+ return;
+ }
+ case R.id.open:
+ {
+ File aPath = Environment.getExternalStorageDirectory();
+ aClickedBtn.setBackgroundColor (getResources().getColor(R.color.pressedBtnColor));
+ if (myFileOpenDialog == null)
+ {
+ myFileOpenDialog = new OcctJniFileDialog (this, aPath);
+ myFileOpenDialog.setFileEndsWith (".brep");
+ myFileOpenDialog.setFileEndsWith (".rle");
+ myFileOpenDialog.setFileEndsWith (".iges");
+ myFileOpenDialog.setFileEndsWith (".igs");
+ myFileOpenDialog.setFileEndsWith (".step");
+ myFileOpenDialog.setFileEndsWith (".stp");
+ myFileOpenDialog.addFileListener (new OcctJniFileDialog.FileSelectedListener()
+ {
+ public void fileSelected (File theFile)
+ {
+ if (theFile != null && myOcctView != null)
+ {
+ myOcctView.open (theFile.getPath());
+ }
+ }
+ });
+ myFileOpenDialog.addDialogDismissedListener (new OcctJniFileDialog.DialogDismissedListener()
+ {
+ @Override
+ public void dialogDismissed()
+ {
+ ImageButton openButton = (ImageButton )findViewById (R.id.open);
+ openButton.setBackgroundColor (getResources().getColor(R.color.btnColor));
+ }
+ });
+ }
+ myFileOpenDialog.showDialog();
+ return;
+ }
+ }
+ }
+
+ private void createSubmenuBtn (int theParentBtnId,
+ int theParentLayoutId,
+ final List theNewButtonIds,
+ final List theNewButtonImageIds,
+ int thePosition)
+ {
+ int aPosInList = 0;
+ final ImageButton aParentBtn = (ImageButton )findViewById (theParentBtnId);
+
+ ViewGroup.LayoutParams aParams = null;
+ LinearLayout parentLayout = (LinearLayout ) findViewById (theParentLayoutId);
+ for (Integer newButtonId : theNewButtonIds)
+ {
+ ImageButton aNewButton = (ImageButton )findViewById (newButtonId);
+ if (aNewButton == null)
+ {
+ aNewButton = (ImageButton )new ImageButton (this);
+ aNewButton.setId (newButtonId);
+ aNewButton.setImageResource (theNewButtonImageIds.get (aPosInList));
+ aNewButton.setLayoutParams (aParams);
+ parentLayout.addView (aNewButton);
+ }
+
+ aNewButton.setOnClickListener (this);
+ aNewButton.setVisibility (View.GONE);
+
+ aNewButton.setOnTouchListener (new View.OnTouchListener()
+ {
+ @Override
+ public boolean onTouch (View theView, MotionEvent theEvent)
+ {
+ return onTouchButton (theView, theEvent);
+ }
+ });
+ ++aPosInList;
+ }
+
+ if (aParentBtn != null)
+ {
+ aParentBtn.setOnTouchListener (null);
+ aParentBtn.setOnTouchListener (new View.OnTouchListener()
+ {
+ @Override
+ public boolean onTouch (View theView, MotionEvent theEvent)
+ {
+ if (theEvent.getAction () == MotionEvent.ACTION_DOWN)
+ {
+ Boolean isVisible = false;
+ for (Integer aNewButtonId : theNewButtonIds)
+ {
+ ImageButton anBtn = (ImageButton )findViewById (aNewButtonId);
+ if (anBtn != null)
+ {
+ if (anBtn.getVisibility() == View.GONE)
+ {
+ anBtn.setVisibility (View.VISIBLE);
+ isVisible = true;
+ }
+ else
+ {
+ anBtn.setVisibility (View.GONE);
+ }
+ }
+ }
+ aParentBtn.setBackgroundColor (!isVisible ? getResources().getColor(R.color.btnColor) : getResources().getColor(R.color.pressedBtnColor));
+ }
+ return false;
+ }
+ });
+ }
+ }
+
+ //! Implements onTouch functionality
+ private boolean onTouchButton (View theView,
+ MotionEvent theEvent)
+ {
+ switch (theEvent.getAction())
+ {
+ case MotionEvent.ACTION_DOWN:
+ ((ImageButton )theView).setBackgroundColor (getResources().getColor (R.color.pressedBtnColor));
+ break;
+ case MotionEvent.ACTION_UP:
+ ((ImageButton )theView).setBackgroundColor (getResources().getColor (R.color.btnColor));
+ break;
+ }
+ return false;
+ }
+
+ //! Handle configuration change event
+ @Override
+ public void onConfigurationChanged (Configuration theNewConfig)
+ {
+ super.onConfigurationChanged (theNewConfig);
+ LinearLayout aLayoutPanelMenu = (LinearLayout )findViewById (R.id.panel_menu);
+ LayoutParams aPanelMenuLayoutParams = aLayoutPanelMenu.getLayoutParams();
+
+ LinearLayout aLayoutViewGroup = (LinearLayout )findViewById (R.id.view_group);
+ LayoutParams aViewGroupLayoutParams = aLayoutViewGroup.getLayoutParams();
+ ImageButton aScrollBtn = (ImageButton )findViewById (R.id.scroll_btn);
+ LayoutParams aScrollBtnLayoutParams = aScrollBtn.getLayoutParams();
+
+ myButtonPreferSize = defineButtonSize ((LinearLayout )findViewById (R.id.panel_menu));
+ defineButtonSize ((LinearLayout )findViewById (R.id.view_group));
+
+ switch (theNewConfig.orientation)
+ {
+ case Configuration.ORIENTATION_PORTRAIT:
+ {
+ setHorizontal (aLayoutPanelMenu, aPanelMenuLayoutParams);
+ setHorizontal (aLayoutViewGroup, aViewGroupLayoutParams);
+ aLayoutViewGroup.setGravity (Gravity.BOTTOM);
+
+ aScrollBtnLayoutParams.height = LayoutParams.WRAP_CONTENT;
+ aScrollBtnLayoutParams.width = LayoutParams.MATCH_PARENT;
+ aScrollBtn.setLayoutParams (aScrollBtnLayoutParams);
+ if (aLayoutPanelMenu.getVisibility() == View.VISIBLE)
+ {
+ aScrollBtn.setImageResource (R.drawable.close_p);
+ aScrollBtn.setY (myButtonPreferSize);
+ aScrollBtn.setX (0);
+ }
+ else
+ {
+ aScrollBtn.setImageResource (R.drawable.open_p);
+ aScrollBtn.setY (0);
+ aScrollBtn.setX (0);
+ }
+ break;
+ }
+ case Configuration.ORIENTATION_LANDSCAPE:
+ {
+ setVertical (aLayoutPanelMenu, aPanelMenuLayoutParams);
+ setVertical (aLayoutViewGroup, aViewGroupLayoutParams);
+ aLayoutViewGroup.setGravity (Gravity.RIGHT);
+
+ aScrollBtnLayoutParams.height = LayoutParams.MATCH_PARENT;
+ aScrollBtnLayoutParams.width = LayoutParams.WRAP_CONTENT;
+ aScrollBtn.setLayoutParams (aScrollBtnLayoutParams);
+ if (aLayoutPanelMenu.getVisibility() == View.VISIBLE)
+ {
+ aScrollBtn.setImageResource (R.drawable.close_l);
+ aScrollBtn.setX (myButtonPreferSize);
+ aScrollBtn.setY (0);
+ }
+ else
+ {
+ aScrollBtn.setImageResource (R.drawable.open_l);
+ aScrollBtn.setY (0);
+ aScrollBtn.setX (0);
+ }
+ break;
+ }
+ }
+ setTextViewPosition (myMessageTextView);
+ setTextViewPosition ((TextView )findViewById (R.id.info_view));
+ }
+
+ private void setHorizontal (LinearLayout theLayout,
+ LayoutParams theLayoutParams)
+ {
+ theLayout.setOrientation (LinearLayout.HORIZONTAL);
+ theLayoutParams.height = LayoutParams.WRAP_CONTENT;
+ theLayoutParams.width = LayoutParams.MATCH_PARENT;
+ theLayout.setLayoutParams (theLayoutParams);
+ }
+
+ private void setVertical (LinearLayout theLayout,
+ LayoutParams theLayoutParams)
+ {
+ theLayout.setOrientation (LinearLayout.VERTICAL);
+ theLayoutParams.height = LayoutParams.MATCH_PARENT;
+ theLayoutParams.width = LayoutParams.WRAP_CONTENT;
+ theLayout.setLayoutParams (theLayoutParams);
+ }
+
+ //! Define button size
+ private int defineButtonSize (LinearLayout theLayout)
+ {
+ boolean isLandscape = getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE;
+ Display aDisplay = getWindowManager().getDefaultDisplay();
+ Point aDispPnt = new Point();
+ aDisplay.getSize (aDispPnt);
+
+ int aNbChildren = theLayout.getChildCount();
+ int aHeight = aDispPnt.y / aNbChildren;
+ int aWidth = aDispPnt.x / aNbChildren;
+ int aResultSize = 0;
+ for (int aChildIter = 0; aChildIter < aNbChildren; ++aChildIter)
+ {
+ View aView = theLayout.getChildAt (aChildIter);
+ if (aView instanceof ImageButton)
+ {
+ ImageButton aButton = (ImageButton )aView;
+ if (isLandscape)
+ {
+ aButton.setMinimumWidth (aHeight);
+ }
+ else
+ {
+ aButton.setMinimumHeight (aWidth);
+ }
+ }
+ }
+ if (isLandscape)
+ {
+ aResultSize = aHeight;
+ }
+ else
+ {
+ aResultSize = aWidth;
+ }
+ return aResultSize;
+ }
+
+ //! OCCT major version
+ private native long cppOcctMajorVersion();
+
+ //! OCCT minor version
+ private native long cppOcctMinorVersion();
+
+ //! OCCT micro version
+ private native long cppOcctMicroVersion();
+
+ private OcctJniView myOcctView;
+ private TextView myMessageTextView;
+ private String myLastPath;
+ private OcctJniFileDialog myFileOpenDialog;
+ private int myButtonPreferSize = 65;
+
+}
diff --git a/samples/java/jniviewer/src/com/opencascade/jnisample/OcctJniFileDialog.java b/samples/java/jniviewer/src/com/opencascade/jnisample/OcctJniFileDialog.java
new file mode 100644
index 0000000000..e12cc1aa2b
--- /dev/null
+++ b/samples/java/jniviewer/src/com/opencascade/jnisample/OcctJniFileDialog.java
@@ -0,0 +1,376 @@
+// Copyright (c) 2014 OPEN CASCADE SAS
+//
+// This file is part of Open CASCADE Technology software library.
+//
+// This library is free software; you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License version 2.1 as published
+// by the Free Software Foundation, with special exception defined in the file
+// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
+// distribution for complete text of the license and disclaimer of any warranty.
+//
+// Alternatively, this file may be used under the terms of Open CASCADE
+// commercial license or contractual agreement.
+
+package com.opencascade.jnisample;
+
+import java.io.File;
+import java.io.FilenameFilter;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import com.opencascade.jnisample.ListenerList.FireHandler;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.content.DialogInterface;
+import android.graphics.Color;
+import android.os.Environment;
+import android.view.View;
+import android.view.ViewGroup.LayoutParams;
+import android.widget.AdapterView;
+import android.widget.ArrayAdapter;
+import android.widget.EditText;
+import android.widget.LinearLayout;
+import android.widget.ListView;
+import android.widget.Spinner;
+
+//! Simple open file dialog
+public class OcctJniFileDialog
+{
+
+ public enum DialogMode
+ {
+ FileOpen, FileExport, FileSave
+ }
+
+ private static final String PARENT_DIR = "..";
+ private String[] myFileList;
+ private File myCurrentPath;
+ private DialogMode myDialogMode = DialogMode.FileOpen;
+
+ private ListenerList myFileListenerList = new ListenerList();
+ private ListenerList myDialogDismissedList = new ListenerList();
+ private final Activity myActivity;
+ private List myFileEndsWith;
+ private EditText myFileNameInput;
+ private Spinner myFileExtSpinner;
+ int myCurrentExtPositionInList = 0;
+
+ public interface FileSelectedListener
+ {
+ void fileSelected (File theFile);
+ }
+
+ public interface DialogDismissedListener
+ {
+ void dialogDismissed();
+ }
+
+ //! Main constructor.
+ public OcctJniFileDialog (Activity theActivity,
+ File thePath)
+ {
+ myActivity = theActivity;
+ if (!thePath.exists())
+ {
+ thePath = Environment.getExternalStorageDirectory();
+ }
+ loadFileList (thePath);
+ }
+
+ //! Create new dialog
+ public Dialog createFileDialog()
+ {
+ final Object[] anObjWrapper = new Object[1];
+ Dialog aDialog = null;
+ AlertDialog.Builder aBuilder = new AlertDialog.Builder (myActivity);
+
+ aBuilder.setTitle (myCurrentPath.getPath());
+ LinearLayout aTitleLayout = new LinearLayout (myActivity);
+ aTitleLayout.setLayoutParams (new LinearLayout.LayoutParams (LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
+ aTitleLayout.setOrientation (LinearLayout.VERTICAL);
+
+ ListView list = new ListView (myActivity);
+ list.setScrollingCacheEnabled(false);
+ list.setBackgroundColor (Color.parseColor ("#33B5E5"));
+
+ list.setAdapter (new ArrayAdapter (myActivity, android.R.layout.select_dialog_item, myFileList));
+ list.setOnItemClickListener (new AdapterView.OnItemClickListener ()
+ {
+
+ public void onItemClick (AdapterView> arg0, View view, int pos, long id)
+ {
+ String fileChosen = myFileList[pos];
+ File aChosenFile = getChosenFile (fileChosen);
+ if (aChosenFile.isDirectory())
+ {
+ loadFileList (aChosenFile);
+ ((Dialog )anObjWrapper[0]).cancel();
+ ((Dialog )anObjWrapper[0]).dismiss();
+ showDialog();
+ }
+ else
+ {
+ if (myDialogMode == DialogMode.FileOpen)
+ {
+ ((Dialog )anObjWrapper[0]).cancel();
+ ((Dialog )anObjWrapper[0]).dismiss();
+ fireFileSelectedEvent (aChosenFile);
+ }
+ else
+ {
+ myFileNameInput.setText (aChosenFile.getName());
+ }
+ }
+ }
+ });
+ list.setLayoutParams (new LinearLayout.LayoutParams (LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT, 0.6f));
+ aTitleLayout.addView (list);
+
+ if (myDialogMode == DialogMode.FileSave
+ || myDialogMode == DialogMode.FileExport)
+ {
+ myFileNameInput = new EditText (myActivity);
+ myFileExtSpinner = new Spinner (myActivity);
+ ArrayAdapter adapter = null;
+ if (myDialogMode == DialogMode.FileExport)
+ {
+ adapter = ArrayAdapter.createFromResource (myActivity, R.array.ext_to_exp,
+ android.R.layout.simple_spinner_item);
+ }
+ else
+ {
+ adapter = ArrayAdapter.createFromResource (myActivity, R.array.ext_to_save,
+ android.R.layout.simple_spinner_item);
+ }
+ // Specify the layout to use when the list of choices appears
+ adapter.setDropDownViewResource (android.R.layout.simple_spinner_dropdown_item);
+ // Apply the adapter to the spinner
+ myFileExtSpinner.setAdapter (adapter);
+ myFileExtSpinner.setSelection (myCurrentExtPositionInList);
+
+ myFileExtSpinner.setOnItemSelectedListener (new AdapterView.OnItemSelectedListener()
+ {
+
+ @Override
+ public void onNothingSelected (AdapterView> theParentView)
+ {
+ // your code here
+ }
+
+ @Override
+ public void onItemSelected (AdapterView> theParent, View theView, int thePosition, long theId)
+ {
+ if (myCurrentExtPositionInList != thePosition)
+ {
+ myCurrentExtPositionInList = thePosition;
+ setFileEndsWith (Arrays.asList (myFileExtSpinner.getSelectedItem().toString()));
+ loadFileList (myCurrentPath);
+ ((Dialog )anObjWrapper[0]).cancel();
+ ((Dialog )anObjWrapper[0]).dismiss();
+ showDialog();
+ }
+ }
+ });
+
+ myFileExtSpinner.setLayoutParams (new LinearLayout.LayoutParams (LayoutParams.MATCH_PARENT,
+ LayoutParams.WRAP_CONTENT, 0.2f));
+ // titleLayout.addView(fileExtSpinner);
+ myFileNameInput.setLayoutParams (new LinearLayout.LayoutParams (LayoutParams.MATCH_PARENT,
+ LayoutParams.WRAP_CONTENT, 0.2f));
+ LinearLayout aControlsView = new LinearLayout (myActivity);
+
+ aControlsView.addView (myFileNameInput);
+ aControlsView.addView (myFileExtSpinner);
+
+ aTitleLayout.addView (aControlsView);
+ aBuilder.setView (aTitleLayout);
+ aBuilder.setPositiveButton ("OK", new DialogInterface.OnClickListener()
+ {
+ @Override
+ public void onClick (DialogInterface theDialog, int theWhich)
+ {
+ if (theWhich >= 0)
+ {
+ String aFileChosen = myFileList[theWhich];
+ File aChosenFile = getChosenFile (aFileChosen);
+ fireFileSelectedEvent (aChosenFile);
+ }
+ }
+ }).setNegativeButton ("Cancel", null);
+ }
+ else
+ {
+ aBuilder.setNegativeButton ("Cancel", null);
+ }
+
+ aBuilder.setView (aTitleLayout);
+
+ aDialog = aBuilder.show();
+ aDialog.setOnDismissListener (new DialogInterface.OnDismissListener()
+ {
+ @Override
+ public void onDismiss (DialogInterface theDialog)
+ {
+ fireDialogDismissedEvent();
+ }
+ });
+ anObjWrapper[0] = aDialog;
+ return aDialog;
+ }
+
+ public void addFileListener (FileSelectedListener theListener)
+ {
+ myFileListenerList.add (theListener);
+ }
+
+ public void addDialogDismissedListener (DialogDismissedListener theListener)
+ {
+ myDialogDismissedList.add (theListener);
+ }
+
+ //! Show file dialog
+ public void showDialog()
+ {
+ createFileDialog().show();
+ }
+
+ private void fireFileSelectedEvent (final File theFile)
+ {
+ myFileListenerList.fireEvent (new FireHandler()
+ {
+ public void fireEvent (FileSelectedListener theListener)
+ {
+ theListener.fileSelected (theFile);
+ }
+ });
+ }
+
+ private void fireDialogDismissedEvent()
+ {
+ myDialogDismissedList.fireEvent (new FireHandler()
+ {
+ public void fireEvent (DialogDismissedListener theListener)
+ {
+ theListener.dialogDismissed();
+ }
+ });
+ }
+
+ private void loadFileList (File thePath)
+ {
+ myCurrentPath = thePath;
+ List aList = new ArrayList();
+ if (thePath.exists())
+ {
+ if (thePath.getParentFile() != null)
+ {
+ aList.add (PARENT_DIR);
+ }
+ FilenameFilter aFilter = new FilenameFilter()
+ {
+ public boolean accept (File theDir, String theFilename)
+ {
+ File aSel = new File (theDir, theFilename);
+ if (!aSel.canRead())
+ {
+ return false;
+ }
+ boolean isEndWith = false;
+ if (myFileEndsWith != null)
+ {
+ for (String aFileExtIter : myFileEndsWith)
+ {
+ if (theFilename.toLowerCase().endsWith (aFileExtIter))
+ {
+ isEndWith = true;
+ break;
+ }
+ }
+ }
+ return isEndWith || aSel.isDirectory();
+ }
+ };
+ String[] aFileList1 = thePath.list (aFilter);
+ if (aFileList1 != null)
+ {
+ for (String aFileIter : aFileList1)
+ {
+ aList.add (aFileIter);
+ }
+ }
+ }
+ myFileList = (String[] )aList.toArray (new String[] {});
+ }
+
+ private File getChosenFile (String theFileChosen)
+ {
+ if (theFileChosen.equals (PARENT_DIR))
+ return myCurrentPath.getParentFile();
+ else
+ return new File (myCurrentPath, theFileChosen);
+ }
+
+ public void setFileEndsWith (String fileEndsWith)
+ {
+ if (myFileEndsWith == null)
+ {
+ myFileEndsWith = new ArrayList();
+ }
+ if (myFileEndsWith.indexOf (fileEndsWith) == -1)
+ {
+ myFileEndsWith.add (fileEndsWith);
+ }
+ }
+
+ public void setFileEndsWith (List theFileEndsWith)
+ {
+ myFileEndsWith = theFileEndsWith;
+ }
+
+ public DialogMode DialogMode()
+ {
+ return myDialogMode;
+ }
+
+ public void DialogMode (DialogMode theMode)
+ {
+ myDialogMode = theMode;
+ }
+}
+
+class ListenerList
+{
+ private List myListenerList = new ArrayList();
+
+ public interface FireHandler
+ {
+ void fireEvent (L theListener);
+ }
+
+ public void add (L theListener)
+ {
+ myListenerList.add (theListener);
+ }
+
+ public void fireEvent (FireHandler theFireHandler)
+ {
+ List aCopy = new ArrayList (myListenerList);
+ for (L anIter : aCopy)
+ {
+ theFireHandler.fireEvent (anIter);
+ }
+ }
+
+ public void remove (L theListener)
+ {
+ myListenerList.remove (theListener);
+ }
+
+ public List getListenerList()
+ {
+ return myListenerList;
+ }
+}
diff --git a/samples/java/jniviewer/src/com/opencascade/jnisample/OcctJniLogger.java b/samples/java/jniviewer/src/com/opencascade/jnisample/OcctJniLogger.java
new file mode 100644
index 0000000000..cc8b1e4942
--- /dev/null
+++ b/samples/java/jniviewer/src/com/opencascade/jnisample/OcctJniLogger.java
@@ -0,0 +1,71 @@
+// Copyright (c) 2014 OPEN CASCADE SAS
+//
+// This file is part of Open CASCADE Technology software library.
+//
+// This library is free software; you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License version 2.1 as published
+// by the Free Software Foundation, with special exception defined in the file
+// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
+// distribution for complete text of the license and disclaimer of any warranty.
+//
+// Alternatively, this file may be used under the terms of Open CASCADE
+// commercial license or contractual agreement.
+
+package com.opencascade.jnisample;
+
+import java.util.concurrent.locks.ReentrantLock;
+
+import android.util.Log;
+import android.widget.TextView;
+
+//! Auxiliary class for logging messages
+public class OcctJniLogger
+{
+
+ //! Setup text view
+ public static void setTextView (TextView theTextView)
+ {
+ if (myTextView != null)
+ {
+ myLog = myTextView.getText().toString();
+ }
+
+ myTextView = theTextView;
+ if (myTextView != null)
+ {
+ myTextView.setText (myLog);
+ myLog = "";
+ }
+ }
+
+ //! Interface implementation
+ public static void postMessage (String theText)
+ {
+ final String aCopy = new String (theText);
+ Log.e (myTag, theText);
+
+ myMutex.lock();
+ final TextView aView = myTextView;
+ if (aView == null)
+ {
+ myLog += aCopy;
+ myMutex.unlock();
+ return;
+ }
+
+ aView.post (new Runnable()
+ {
+ public void run()
+ {
+ aView.setText (aView.getText() + aCopy + "\n");
+ }
+ });
+ myMutex.unlock();
+ }
+
+ private static final String myTag = "occtJniViewer";
+ private static final ReentrantLock myMutex = new ReentrantLock (true);
+ private static TextView myTextView = null;
+ private static String myLog = "";
+
+}
diff --git a/samples/java/jniviewer/src/com/opencascade/jnisample/OcctJniRenderer.java b/samples/java/jniviewer/src/com/opencascade/jnisample/OcctJniRenderer.java
new file mode 100644
index 0000000000..731037a9ca
--- /dev/null
+++ b/samples/java/jniviewer/src/com/opencascade/jnisample/OcctJniRenderer.java
@@ -0,0 +1,218 @@
+// Copyright (c) 2014 OPEN CASCADE SAS
+//
+// This file is part of Open CASCADE Technology software library.
+//
+// This library is free software; you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License version 2.1 as published
+// by the Free Software Foundation, with special exception defined in the file
+// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
+// distribution for complete text of the license and disclaimer of any warranty.
+//
+// Alternatively, this file may be used under the terms of Open CASCADE
+// commercial license or contractual agreement.
+
+package com.opencascade.jnisample;
+
+import javax.microedition.khronos.egl.EGLConfig;
+import javax.microedition.khronos.opengles.GL10;
+
+import android.opengl.GLSurfaceView;
+
+//! Wrapper for C++ OCCT viewer.
+public class OcctJniRenderer implements GLSurfaceView.Renderer
+{
+
+ //! Wrapper for V3d_TypeOfOrientation
+ enum TypeOfOrientation
+ {
+ Xpos, // front
+ Ypos, // left
+ Zpos, // top
+ Xneg, // back
+ Yneg, // right
+ Zneg // bottom
+ };
+
+ //! Empty constructor.
+ OcctJniRenderer()
+ {
+ if (OcctJniActivity.areNativeLoaded)
+ {
+ myCppViewer = cppCreate();
+ }
+ }
+
+ //! Open file.
+ public void open (String thePath)
+ {
+ if (myCppViewer != 0)
+ {
+ cppOpen (myCppViewer, thePath);
+ }
+ }
+
+ //! Update viewer.
+ public void onDrawFrame (GL10 theGl)
+ {
+ if (myCppViewer != 0)
+ {
+ cppRedraw (myCppViewer);
+ }
+ }
+
+ //! (re)initialize viewer.
+ public void onSurfaceChanged (GL10 theGl, int theWidth, int theHeight)
+ {
+ if (myCppViewer != 0)
+ {
+ cppResize (myCppViewer, theWidth, theHeight);
+ }
+ }
+
+ public void onSurfaceCreated (GL10 theGl, EGLConfig theEglConfig)
+ {
+ if (myCppViewer != 0)
+ {
+ cppInit (myCppViewer);
+ }
+ }
+
+ //! Initialize rotation (remember first point position)
+ public void onStartRotation (int theStartX, int theStartY)
+ {
+ if (myCppViewer != 0)
+ {
+ cppStartRotation (myCppViewer, theStartX, theStartY);
+ }
+ }
+
+ //! Perform rotation (relative to first point)
+ public void onRotation (int theX, int theY)
+ {
+ if (myCppViewer != 0)
+ {
+ cppOnRotation (myCppViewer, theX, theY);
+ }
+ }
+
+ //! Perform panning
+ public void onPanning (int theDX, int theDY)
+ {
+ if (myCppViewer != 0)
+ {
+ cppOnPanning (myCppViewer, theDX, theDY);
+ }
+ }
+
+ //! Perform selection
+ public void onClick (int theX, int theY)
+ {
+ if (myCppViewer != 0)
+ {
+ cppOnClick (myCppViewer, theX, theY);
+ }
+ }
+
+ //! Stop previously active action (e.g. discard first rotation point)
+ public void onStopAction()
+ {
+ if (myCppViewer != 0)
+ {
+ cppStopAction (myCppViewer);
+ }
+ }
+
+ //! Fit All
+ public void fitAll()
+ {
+ if (myCppViewer != 0)
+ {
+ cppFitAll (myCppViewer);
+ }
+ }
+
+ //! Move camera
+ public void setProj (TypeOfOrientation theProj)
+ {
+ if (myCppViewer == 0)
+ {
+ return;
+ }
+
+ switch (theProj)
+ {
+ case Xpos: cppSetXposProj (myCppViewer); break;
+ case Ypos: cppSetYposProj (myCppViewer); break;
+ case Zpos: cppSetZposProj (myCppViewer); break;
+ case Xneg: cppSetXnegProj (myCppViewer); break;
+ case Yneg: cppSetYnegProj (myCppViewer); break;
+ case Zneg: cppSetZnegProj (myCppViewer); break;
+ }
+ }
+
+ //! Post message to the text view.
+ public void postMessage (String theText)
+ {
+ OcctJniLogger.postMessage (theText);
+ }
+
+ //! Create instance of C++ class
+ private native long cppCreate();
+
+ //! Destroy instance of C++ class
+ private native void cppDestroy (long theCppPtr);
+
+ //! Initialize OCCT viewer (steal OpenGL ES context bound to this thread)
+ private native void cppInit (long theCppPtr);
+
+ //! Resize OCCT viewer
+ private native void cppResize (long theCppPtr, int theWidth, int theHeight);
+
+ //! Open CAD file
+ private native void cppOpen (long theCppPtr, String thePath);
+
+ //! Handle detection in the viewer
+ private native void cppMoveTo (long theCppPtr, int theX, int theY);
+
+ //! Redraw OCCT viewer
+ private native void cppRedraw (long theCppPtr);
+
+ //! Fit All
+ private native void cppFitAll (long theCppPtr);
+
+ //! Move camera
+ private native void cppSetXposProj (long theCppPtr);
+
+ //! Move camera
+ private native void cppSetYposProj (long theCppPtr);
+
+ //! Move camera
+ private native void cppSetZposProj (long theCppPtr);
+
+ //! Move camera
+ private native void cppSetXnegProj (long theCppPtr);
+
+ //! Move camera
+ private native void cppSetYnegProj (long theCppPtr);
+
+ //! Move camera
+ private native void cppSetZnegProj (long theCppPtr);
+
+ //! Initialize rotation
+ private native void cppStartRotation (long theCppPtr, int theStartX, int theStartY);
+
+ //! Perform rotation
+ private native void cppOnRotation (long theCppPtr, int theX, int theY);
+
+ //! Perform panning
+ private native void cppOnPanning (long theCppPtr, int theDX, int theDY);
+
+ //! Perform selection
+ private native void cppOnClick (long theCppPtr, int theX, int theY);
+
+ //! Stop action (rotation / panning / scaling)
+ private native void cppStopAction (long theCppPtr);
+
+ private long myCppViewer = 0; //!< pointer to c++ class instance
+
+}
diff --git a/samples/java/jniviewer/src/com/opencascade/jnisample/OcctJniView.java b/samples/java/jniviewer/src/com/opencascade/jnisample/OcctJniView.java
new file mode 100644
index 0000000000..7909d9c61d
--- /dev/null
+++ b/samples/java/jniviewer/src/com/opencascade/jnisample/OcctJniView.java
@@ -0,0 +1,332 @@
+// Copyright (c) 2014 OPEN CASCADE SAS
+//
+// This file is part of Open CASCADE Technology software library.
+//
+// This library is free software; you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License version 2.1 as published
+// by the Free Software Foundation, with special exception defined in the file
+// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
+// distribution for complete text of the license and disclaimer of any warranty.
+//
+// Alternatively, this file may be used under the terms of Open CASCADE
+// commercial license or contractual agreement.
+
+package com.opencascade.jnisample;
+
+import android.app.ActionBar.LayoutParams;
+import android.content.Context;
+import android.graphics.PointF;
+import android.opengl.GLSurfaceView;
+import android.util.AttributeSet;
+import android.util.SparseArray;
+import android.view.MotionEvent;
+import android.widget.RelativeLayout;
+
+import javax.microedition.khronos.egl.EGL10;
+import javax.microedition.khronos.egl.EGLConfig;
+import javax.microedition.khronos.egl.EGLContext;
+import javax.microedition.khronos.egl.EGLDisplay;
+
+//! OpenGL ES 2.0+ view.
+//! Performs rendering in parallel thread.
+class OcctJniView extends GLSurfaceView
+{
+
+ // ! Default constructor.
+ public OcctJniView (Context theContext,
+ AttributeSet theAttrs)
+ {
+ super (theContext, theAttrs);
+
+ setPreserveEGLContextOnPause (true);
+ setEGLContextFactory (new ContextFactory());
+ setEGLConfigChooser (new ConfigChooser());
+
+ RelativeLayout.LayoutParams aLParams = new RelativeLayout.LayoutParams (LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
+ aLParams.addRule (RelativeLayout.ALIGN_TOP);
+
+ myRenderer = new OcctJniRenderer();
+ setRenderer (myRenderer);
+ }
+
+ //! Open file.
+ public void open (String thePath)
+ {
+ final String aPath = thePath;
+ queueEvent (new Runnable() { public void run() { myRenderer.open (aPath); }});
+ }
+
+ //! Create OpenGL ES 2.0+ context
+ private static class ContextFactory implements GLSurfaceView.EGLContextFactory
+ {
+ private static int EGL_CONTEXT_CLIENT_VERSION = 0x3098;
+ public EGLContext createContext (EGL10 theEgl,
+ EGLDisplay theEglDisplay,
+ EGLConfig theEglConfig)
+ {
+ if (theEglConfig == null)
+ {
+ return null;
+ }
+
+ // reset EGL errors stack
+ int anError = EGL10.EGL_SUCCESS;
+ while ((anError = theEgl.eglGetError()) != EGL10.EGL_SUCCESS) {}
+
+ int[] anAttribs = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL10.EGL_NONE };
+ EGLContext aEglContext = theEgl.eglCreateContext (theEglDisplay, theEglConfig, EGL10.EGL_NO_CONTEXT, anAttribs);
+
+ while ((anError = theEgl.eglGetError()) != EGL10.EGL_SUCCESS)
+ {
+ OcctJniLogger.postMessage ("Error: eglCreateContext() " + String.format ("0x%x", anError));
+ }
+ return aEglContext;
+ }
+
+ public void destroyContext (EGL10 theEgl,
+ EGLDisplay theEglDisplay,
+ EGLContext theEglContext)
+ {
+ theEgl.eglDestroyContext (theEglDisplay, theEglContext);
+ }
+ }
+
+ //! Search for RGB24 config with depth and stencil buffers
+ private static class ConfigChooser implements GLSurfaceView.EGLConfigChooser
+ {
+ //! Reset EGL errors stack
+ private void popEglErrors (EGL10 theEgl)
+ {
+ int anError = EGL10.EGL_SUCCESS;
+ while ((anError = theEgl.eglGetError()) != EGL10.EGL_SUCCESS)
+ {
+ OcctJniLogger.postMessage ("EGL Error: " + String.format ("0x%x", anError));
+ }
+ }
+
+ //! Auxiliary method to dump EGL configuration - for debugging purposes
+ @SuppressWarnings("unused")
+ private void printConfig (EGL10 theEgl,
+ EGLDisplay theEglDisplay,
+ EGLConfig theEglConfig)
+ {
+ int[] THE_ATTRIBS =
+ {
+ EGL10.EGL_BUFFER_SIZE, EGL10.EGL_ALPHA_SIZE, EGL10.EGL_BLUE_SIZE, EGL10.EGL_GREEN_SIZE, EGL10.EGL_RED_SIZE, EGL10.EGL_DEPTH_SIZE, EGL10.EGL_STENCIL_SIZE,
+ EGL10.EGL_CONFIG_CAVEAT,
+ EGL10.EGL_CONFIG_ID,
+ EGL10.EGL_LEVEL,
+ EGL10.EGL_MAX_PBUFFER_HEIGHT, EGL10.EGL_MAX_PBUFFER_PIXELS, EGL10.EGL_MAX_PBUFFER_WIDTH,
+ EGL10.EGL_NATIVE_RENDERABLE, EGL10.EGL_NATIVE_VISUAL_ID, EGL10.EGL_NATIVE_VISUAL_TYPE,
+ 0x3030, // EGL10.EGL_PRESERVED_RESOURCES,
+ EGL10.EGL_SAMPLES, EGL10.EGL_SAMPLE_BUFFERS,
+ EGL10.EGL_SURFACE_TYPE,
+ EGL10.EGL_TRANSPARENT_TYPE, EGL10.EGL_TRANSPARENT_RED_VALUE, EGL10.EGL_TRANSPARENT_GREEN_VALUE, EGL10.EGL_TRANSPARENT_BLUE_VALUE,
+ 0x3039, 0x303A, // EGL10.EGL_BIND_TO_TEXTURE_RGB, EGL10.EGL_BIND_TO_TEXTURE_RGBA,
+ 0x303B, 0x303C, // EGL10.EGL_MIN_SWAP_INTERVAL, EGL10.EGL_MAX_SWAP_INTERVAL
+ EGL10.EGL_LUMINANCE_SIZE, EGL10.EGL_ALPHA_MASK_SIZE,
+ EGL10.EGL_COLOR_BUFFER_TYPE, EGL10.EGL_RENDERABLE_TYPE,
+ 0x3042 // EGL10.EGL_CONFORMANT
+ };
+ String[] THE_NAMES =
+ {
+ "EGL_BUFFER_SIZE", "EGL_ALPHA_SIZE", "EGL_BLUE_SIZE", "EGL_GREEN_SIZE", "EGL_RED_SIZE", "EGL_DEPTH_SIZE", "EGL_STENCIL_SIZE",
+ "EGL_CONFIG_CAVEAT",
+ "EGL_CONFIG_ID",
+ "EGL_LEVEL",
+ "EGL_MAX_PBUFFER_HEIGHT", "EGL_MAX_PBUFFER_PIXELS", "EGL_MAX_PBUFFER_WIDTH",
+ "EGL_NATIVE_RENDERABLE", "EGL_NATIVE_VISUAL_ID", "EGL_NATIVE_VISUAL_TYPE",
+ "EGL_PRESERVED_RESOURCES",
+ "EGL_SAMPLES", "EGL_SAMPLE_BUFFERS",
+ "EGL_SURFACE_TYPE",
+ "EGL_TRANSPARENT_TYPE", "EGL_TRANSPARENT_RED_VALUE", "EGL_TRANSPARENT_GREEN_VALUE", "EGL_TRANSPARENT_BLUE_VALUE",
+ "EGL_BIND_TO_TEXTURE_RGB", "EGL_BIND_TO_TEXTURE_RGBA",
+ "EGL_MIN_SWAP_INTERVAL", "EGL_MAX_SWAP_INTERVAL",
+ "EGL_LUMINANCE_SIZE", "EGL_ALPHA_MASK_SIZE",
+ "EGL_COLOR_BUFFER_TYPE", "EGL_RENDERABLE_TYPE",
+ "EGL_CONFORMANT"
+ };
+ int[] aValue = new int[1];
+ for (int anAttrIter = 0; anAttrIter < THE_ATTRIBS.length; ++anAttrIter)
+ {
+ int anAttr = THE_ATTRIBS[anAttrIter];
+ String aName = THE_NAMES [anAttrIter];
+ if (theEgl.eglGetConfigAttrib (theEglDisplay, theEglConfig, anAttr, aValue))
+ {
+ OcctJniLogger.postMessage (String.format (" %s: %d\n", aName, aValue[0]));
+ }
+ else
+ {
+ popEglErrors (theEgl);
+ }
+ }
+ }
+
+ //! Interface implementation
+ public EGLConfig chooseConfig (EGL10 theEgl,
+ EGLDisplay theEglDisplay)
+ {
+ int EGL_OPENGL_ES2_BIT = 4;
+ int[] aCfgAttribs =
+ {
+ EGL10.EGL_RED_SIZE, 8,
+ EGL10.EGL_GREEN_SIZE, 8,
+ EGL10.EGL_BLUE_SIZE, 8,
+ EGL10.EGL_ALPHA_SIZE, 0,
+ EGL10.EGL_DEPTH_SIZE, 24,
+ EGL10.EGL_STENCIL_SIZE, 8,
+ EGL10.EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
+ EGL10.EGL_NONE
+ };
+
+ EGLConfig aConfigs[] = new EGLConfig[1];
+ int[] aNbConfigs = new int[1];
+ if (!theEgl.eglChooseConfig (theEglDisplay, aCfgAttribs, aConfigs, 1, aNbConfigs)
+ || aConfigs[0] == null)
+ {
+ aCfgAttribs[4 * 2 + 1] = 16; // try config with smaller depth buffer
+ popEglErrors (theEgl);
+ if (!theEgl.eglChooseConfig (theEglDisplay, aCfgAttribs, aConfigs, 1, aNbConfigs)
+ || aConfigs[0] == null)
+ {
+ OcctJniLogger.postMessage ("Error: eglChooseConfig() has failed!");
+ return null;
+ }
+ }
+
+ //printConfig (theEgl, theEglDisplay, aConfigs[0]);
+ return aConfigs[0];
+ }
+ }
+
+ //! Callback to handle touch events
+ @Override public boolean onTouchEvent (MotionEvent theEvent)
+ {
+ int aPointerIndex = theEvent.getActionIndex();
+ int aPointerId = theEvent.getPointerId (aPointerIndex);
+ int aMaskedAction = theEvent.getActionMasked();
+ switch (aMaskedAction)
+ {
+ case MotionEvent.ACTION_DOWN:
+ case MotionEvent.ACTION_POINTER_DOWN:
+ {
+ PointF aPntLast = null;
+ if (myActivePointers.size() >= 1)
+ {
+ aPntLast = myActivePointers.get (myActivePointers.keyAt (0));
+ }
+
+ final PointF aPnt = new PointF();
+ aPnt.x = theEvent.getX (aPointerIndex);
+ aPnt.y = theEvent.getY (aPointerIndex);
+ myActivePointers.put (aPointerId, aPnt);
+
+ switch (myActivePointers.size())
+ {
+ case 1:
+ {
+ final int aStartX = (int )aPnt.x;
+ final int aStartY = (int )aPnt.y;
+ queueEvent (new Runnable() { public void run() { myRenderer.onStartRotation (aStartX, aStartY); }});
+ break;
+ }
+ case 2:
+ {
+ myPanFrom.x = (aPntLast.x + aPnt.x) * 0.5f;
+ myPanFrom.y = (aPntLast.y + aPnt.y) * 0.5f;
+ break;
+ }
+ }
+
+ break;
+ }
+ case MotionEvent.ACTION_MOVE:
+ {
+ for (int aNbPointers = theEvent.getPointerCount(), aPntIter = 0; aPntIter < aNbPointers; ++aPntIter)
+ {
+ PointF aPnt = myActivePointers.get (theEvent.getPointerId (aPntIter));
+ if (aPnt != null)
+ {
+ aPnt.x = theEvent.getX (aPntIter);
+ aPnt.y = theEvent.getY (aPntIter);
+ }
+ }
+
+ switch (myActivePointers.size())
+ {
+ case 1:
+ {
+ PointF aPnt = myActivePointers.get (theEvent.getPointerId (0));
+ final int anX = (int )aPnt.x;
+ final int anY = (int )aPnt.y;
+ queueEvent (new Runnable() { public void run() { myRenderer.onRotation (anX, anY); }});
+ break;
+ }
+ case 2:
+ {
+ PointF aPnt1 = myActivePointers.get (myActivePointers.keyAt (0));
+ PointF aPnt2 = myActivePointers.get (myActivePointers.keyAt (1));
+ PointF aPntAver = new PointF ((aPnt1.x + aPnt2.x) * 0.5f,
+ (aPnt1.y + aPnt2.y) * 0.5f);
+ final int aDX = (int )(aPntAver.x - myPanFrom.x);
+ final int aDY = (int )(myPanFrom.y -aPntAver.y);
+ myPanFrom.x = aPntAver.x;
+ myPanFrom.y = aPntAver.y;
+ queueEvent (new Runnable() { public void run() { myRenderer.onPanning (aDX, aDY); }});
+ }
+ }
+ break;
+ }
+ case MotionEvent.ACTION_UP:
+ case MotionEvent.ACTION_POINTER_UP:
+ case MotionEvent.ACTION_CANCEL:
+ {
+ myActivePointers.remove (aPointerId);
+ if (myActivePointers.size() == 0)
+ {
+ final int aPressX = (int )theEvent.getX (aPointerIndex);
+ final int aPressY = (int )theEvent.getY (aPointerIndex);
+ double aPressTimeMs = theEvent.getEventTime() - theEvent.getDownTime();
+ if (aPressTimeMs < 100.0)
+ {
+ queueEvent (new Runnable() { public void run() { myRenderer.onClick (aPressX, aPressY); }});
+ break;
+ }
+ }
+ else if (myActivePointers.size() == 1)
+ {
+ PointF aPnt = myActivePointers.get (myActivePointers.keyAt (0));
+ final int aStartX = (int )aPnt.x;
+ final int aStartY = (int )aPnt.y;
+ queueEvent (new Runnable() { public void run() { myRenderer.onStartRotation (aStartX, aStartY); }});
+ }
+ //queueEvent (new Runnable() { public void run() { myRenderer.onStopAction(); }});
+ break;
+ }
+ }
+ ///invalidate();
+ return true;
+ }
+
+ //! Fit All
+ public void fitAll()
+ {
+ queueEvent (new Runnable() { public void run() { myRenderer.fitAll(); }});
+ }
+
+ //! Move camera
+ public void setProj (final OcctJniRenderer.TypeOfOrientation theProj)
+ {
+ queueEvent (new Runnable() { public void run() { myRenderer.setProj (theProj); }});
+ }
+
+ //! OCCT viewer
+ private OcctJniRenderer myRenderer = null;
+
+ //! Touch events cache
+ private SparseArray myActivePointers = new SparseArray();
+
+ //! Starting point for panning event
+ private PointF myPanFrom = new PointF (0.0f, 0.0f);
+
+}