1
0
mirror of https://git.dev.opencascade.org/repos/occt.git synced 2025-08-14 13:30:48 +03:00

0031619: Samples - update JNI sample to use Android Studio

Project structure and project files have been updated to use Android Studio 4.0, gradle and CMake.
Redundant OcctJni_Window has been replaced by Aspect_NeutralWindow.
SD Card permissions are not dynamically requested for compatibility with Android API level 26+.
This commit is contained in:
kgv
2020-06-20 02:14:51 +03:00
parent ef779ae0da
commit bbe85f2b40
50 changed files with 253 additions and 479 deletions

View File

@@ -0,0 +1,35 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.opencascade.jnisample">
<application android:label="@string/app_name" android:icon="@drawable/ic_launcher">
<activity android:name="OcctJniActivity"
android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
android:launchMode="singleTask"
android:configChanges="orientation|keyboardHidden|screenSize">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="" />
<data android:scheme="file" />
<data android:scheme="content" />
<data android:host="*" />
<data android:pathPattern=".*\\.brep" />
<data android:pathPattern=".*\\.rle" />
<data android:pathPattern=".*\\.step" />
<data android:pathPattern=".*\\.stp" />
<data android:pathPattern=".*\\.iges" />
<data android:pathPattern=".*\\.igs" />
</intent-filter>
</activity>
</application>
<uses-feature android:glEsVersion="0x00020000"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
</manifest>

View File

@@ -0,0 +1,864 @@
// 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(), "src/SHMessage", aResFolder + "/SHMessage");
copyAssetFolder (getAssets(), "src/XSMessage", aResFolder + "/XSMessage");
// 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;
myContext = new android.content.ContextWrapper (this);
myContext.getExternalFilesDir (null);
}
//! 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)
{
// should be requested on runtime since API level 26 (Android 8)
askUserPermission (android.Manifest.permission.WRITE_EXTERNAL_STORAGE, null); // for accessing SD card
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<Integer> theNewButtonIds,
final List<Integer> 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;
}
//! Request user permission.
private void askUserPermission (String thePermission, String theRationale)
{
// Dynamically load methods introduced by API level 23.
// On older system this permission is granted by user during application installation.
java.lang.reflect.Method aMetPtrCheckSelfPermission, aMetPtrRequestPermissions, aMetPtrShouldShowRequestPermissionRationale;
try
{
aMetPtrCheckSelfPermission = myContext.getClass().getMethod ("checkSelfPermission", String.class);
aMetPtrRequestPermissions = getClass().getMethod ("requestPermissions", String[].class, int.class);
aMetPtrShouldShowRequestPermissionRationale = getClass().getMethod ("shouldShowRequestPermissionRationale", String.class);
}
catch (SecurityException theError)
{
postMessage ("Unable to find permission methods:\n" + theError.getMessage(), Message_Trace);
return;
}
catch (NoSuchMethodException theError)
{
postMessage ("Unable to find permission methods:\n" + theError.getMessage(), Message_Trace);
return;
}
try
{
int isAlreadyGranted = (Integer )aMetPtrCheckSelfPermission.invoke (myContext, thePermission);
if (isAlreadyGranted == android.content.pm.PackageManager.PERMISSION_GRANTED)
{
return;
}
boolean toShowInfo = theRationale != null && (Boolean )aMetPtrShouldShowRequestPermissionRationale.invoke (this, thePermission);
if (toShowInfo)
{
postMessage (theRationale, Message_Info);
}
// show dialog to user
aMetPtrRequestPermissions.invoke (this, new String[]{thePermission}, 0);
}
catch (IllegalArgumentException theError)
{
postMessage ("Internal error: Unable to call permission method:\n" + theError.getMessage(), Message_Fail);
return;
}
catch (IllegalAccessException theError)
{
postMessage ("Internal error: Unable to call permission method:\n" + theError.getMessage(), Message_Fail);
return;
}
catch (java.lang.reflect.InvocationTargetException theError)
{
postMessage ("Internal error: Unable to call permission method:\n" + theError.getMessage(), Message_Fail);
return;
}
}
//! Message gravity.
private static final int Message_Trace = 0;
private static final int Message_Info = 1;
private static final int Message_Warning = 2;
private static final int Message_Alarm = 3;
private static final int Message_Fail = 4;
//! Auxiliary method to show info message.
public void postMessage (String theMessage, int theGravity)
{
if (theGravity == Message_Trace)
{
return;
}
final String aText = theMessage;
final Context aCtx = this;
this.runOnUiThread (new Runnable() { public void run() {
android.app.AlertDialog.Builder aBuilder = new android.app.AlertDialog.Builder (aCtx);
aBuilder.setMessage (aText).setNegativeButton ("OK", null);
android.app.AlertDialog aDialog = aBuilder.create();
aDialog.show();
}});
}
//! 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 android.content.ContextWrapper myContext = null;
private OcctJniFileDialog myFileOpenDialog;
private int myButtonPreferSize = 65;
}

View File

@@ -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<FileSelectedListener> myFileListenerList = new ListenerList<OcctJniFileDialog.FileSelectedListener>();
private ListenerList<DialogDismissedListener> myDialogDismissedList = new ListenerList<DialogDismissedListener>();
private final Activity myActivity;
private List<String> 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<String> (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<CharSequence> 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<OcctJniFileDialog.FileSelectedListener>()
{
public void fireEvent (FileSelectedListener theListener)
{
theListener.fileSelected (theFile);
}
});
}
private void fireDialogDismissedEvent()
{
myDialogDismissedList.fireEvent (new FireHandler<OcctJniFileDialog.DialogDismissedListener>()
{
public void fireEvent (DialogDismissedListener theListener)
{
theListener.dialogDismissed();
}
});
}
private void loadFileList (File thePath)
{
myCurrentPath = thePath;
List<String> aList = new ArrayList<String>();
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<String>();
}
if (myFileEndsWith.indexOf (fileEndsWith) == -1)
{
myFileEndsWith.add (fileEndsWith);
}
}
public void setFileEndsWith (List<String> theFileEndsWith)
{
myFileEndsWith = theFileEndsWith;
}
public DialogMode DialogMode()
{
return myDialogMode;
}
public void DialogMode (DialogMode theMode)
{
myDialogMode = theMode;
}
}
class ListenerList<L>
{
private List<L> myListenerList = new ArrayList<L>();
public interface FireHandler<L>
{
void fireEvent (L theListener);
}
public void add (L theListener)
{
myListenerList.add (theListener);
}
public void fireEvent (FireHandler<L> theFireHandler)
{
List<L> aCopy = new ArrayList<L> (myListenerList);
for (L anIter : aCopy)
{
theFireHandler.fireEvent (anIter);
}
}
public void remove (L theListener)
{
myListenerList.remove (theListener);
}
public List<L> getListenerList()
{
return myListenerList;
}
}

View File

@@ -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 = "";
}

View File

@@ -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
}

View File

@@ -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<PointF> myActivePointers = new SparseArray<PointF>();
//! Starting point for panning event
private PointF myPanFrom = new PointF (0.0f, 0.0f);
}

View File

@@ -0,0 +1,43 @@
cmake_minimum_required(VERSION 3.4.1)
set(HEADER_FILES OcctJni_MsgPrinter.hxx OcctJni_Viewer.hxx)
set(SOURCE_FILES OcctJni_MsgPrinter.cxx OcctJni_Viewer.cxx)
set (anOcctLibs
TKernel TKMath TKG2d TKG3d TKGeomBase TKBRep TKGeomAlgo TKTopAlgo TKShHealing TKMesh
# exchange
TKPrim TKBO TKBool TKFillet TKOffset
TKXSBase
TKIGES
TKSTEPBase TKSTEPAttr TKSTEP209 TKSTEP
# OCCT Visualization
TKService TKHLR TKV3d TKOpenGl
)
set(aLibDeps "")
# OCCT libraries
include_directories(${OCCT_ROOT}/inc)
foreach(anOcctLib ${anOcctLibs})
add_library(lib_${anOcctLib} SHARED IMPORTED)
set_target_properties(lib_${anOcctLib} PROPERTIES IMPORTED_LOCATION ${OCCT_ROOT}/libs/${ANDROID_ABI}/lib${anOcctLib}.so)
list(APPEND aLibDeps lib_${anOcctLib})
endforeach()
# FreeType
add_library(lib_FreeType SHARED IMPORTED)
set_target_properties(lib_FreeType PROPERTIES IMPORTED_LOCATION ${FREETYPE_ROOT}/libs/${ANDROID_ABI}/libfreetype.so)
list(APPEND aLibDeps lib_FreeType)
# FreeImage - uncomment, if OCCT was built with FreeImage
#add_library(lib_FreeImage SHARED IMPORTED)
#set_target_properties(lib_FreeImage PROPERTIES IMPORTED_LOCATION ${FREETYPE_ROOT}/libs/${ANDROID_ABI}/libfreeimage.so)
#list(APPEND aLibDeps lib_FreeImage)
# system libraries
list(APPEND aLibDeps EGL GLESv2 log android)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Wall -frtti -fexceptions -fpermissive")
add_library(TKJniSample SHARED ${SOURCE_FILES})
target_link_libraries(TKJniSample ${aLibDeps})

View File

@@ -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.
#include "OcctJni_MsgPrinter.hxx"
#include <TCollection_AsciiString.hxx>
#include <TCollection_ExtendedString.hxx>
#include <android/log.h>
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_AsciiString& theString,
const Message_Gravity theGravity) 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);
}

View File

@@ -0,0 +1,53 @@
// 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 <Message_Printer.hxx>
#include <jni.h>
// 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();
protected:
//! Main printing method
virtual void send (const TCollection_AsciiString& theString,
const Message_Gravity theGravity) const override;
private:
JNIEnv* myJEnv;
jobject myJObj;
jmethodID myJMet;
public:
DEFINE_STANDARD_RTTIEXT(OcctJni_MsgPrinter,Message_Printer)
};
DEFINE_STANDARD_HANDLE(OcctJni_MsgPrinter, Message_Printer)
#endif // OcctJni_MsgPrinter_H

View File

@@ -0,0 +1,815 @@
// 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 "OcctJni_Viewer.hxx"
#include "OcctJni_MsgPrinter.hxx"
#include <AIS_Shape.hxx>
#include <Aspect_NeutralWindow.hxx>
#include <Image_AlienPixMap.hxx>
#include <BRepTools.hxx>
#include <Message_Messenger.hxx>
#include <Message_MsgFile.hxx>
#include <Message_PrinterSystemLog.hxx>
#include <OpenGl_GraphicDriver.hxx>
#include <OSD_Environment.hxx>
#include <OSD_Timer.hxx>
#include <Standard_Version.hxx>
#include <BRepPrimAPI_MakeBox.hxx>
#include <STEPControl_Reader.hxx>
#include <IGESControl_Reader.hxx>
#include <XSControl_WorkSession.hxx>
#include <EGL/egl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <jni.h>
//! @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()
{
#ifndef NDEBUG
// Register printer for logging messages into global Android log.
// Should never be used in production (or specify higher gravity for logging only failures).
Handle(Message_Messenger) aMsgMgr = Message::DefaultMessenger();
aMsgMgr->RemovePrinters (STANDARD_TYPE (Message_PrinterSystemLog));
aMsgMgr->AddPrinter (new Message_PrinterSystemLog ("OcctJni_Viewer"));
#endif
// prepare necessary environment
TCollection_AsciiString aResRoot = "/data/data/com.opencascade.jnisample/files";
setResourceEnv ("CSF_XSMessage", aResRoot + "/XSMessage", "XSTEP.us", Standard_False);
setResourceEnv ("CSF_SHMessage", aResRoot + "/XSMessage", "SHAPE.us", Standard_False);
}
// =======================================================================
// 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(Aspect_NeutralWindow) aWindow = Handle(Aspect_NeutralWindow)::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);
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);
myViewer->SetDefaultBackgroundColor (Quantity_NOC_BLACK);
myViewer->SetDefaultLights();
myViewer->SetLightOn();
// create AIS context
myContext = new AIS_InteractiveContext (myViewer);
//myContext->SetDisplayMode (AIS_WireFrame, false);
myContext->SetDisplayMode (AIS_Shaded, false);
Handle(Aspect_NeutralWindow) aWindow = new Aspect_NeutralWindow();
aWindow->SetSize (aWidth, aHeight);
myView = myViewer->CreateView();
myView->SetWindow (aWindow, (Aspect_RenderingContext )anEglContext);
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(Aspect_NeutralWindow) aWindow = Handle(Aspect_NeutralWindow)::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->SetImmediateUpdate (Standard_False);
myView->SetWindow (aWindow, (Aspect_RenderingContext )anEglContext);
//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<Image_ColorRGBA> (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 (0.01, Standard_False);
myView->Invalidate();
}
// =======================================================================
// function : startRotation
// purpose :
// =======================================================================
void OcctJni_Viewer::startRotation (int theStartX,
int theStartY)
{
if (myView.IsNull())
{
return;
}
myView->StartRotation (theStartX, theStartY, 0.45);
myView->Invalidate();
}
// =======================================================================
// function : onRotation
// purpose :
// =======================================================================
void OcctJni_Viewer::onRotation (int theX,
int theY)
{
if (myView.IsNull())
{
return;
}
myView->Rotation (theX, theY);
myView->Invalidate();
}
// =======================================================================
// function : onPanning
// purpose :
// =======================================================================
void OcctJni_Viewer::onPanning (int theDX,
int theDY)
{
if (myView.IsNull())
{
return;
}
myView->Pan (theDX, theDY);
myView->Invalidate();
}
// =======================================================================
// 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_False);
myView->Invalidate();
}
// =======================================================================
// 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;
}

View File

@@ -0,0 +1,86 @@
// 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 <AIS_InteractiveContext.hxx>
#include <TopoDS_Shape.hxx>
#include <V3d_Viewer.hxx>
#include <V3d_View.hxx>
//! 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;
};

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1002 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 443 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 917 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 839 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

View File

@@ -0,0 +1,166 @@
<TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/panel_main"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:stretchColumns="1">
<LinearLayout android:layout_height="fill_parent"
android:layout_width="fill_parent"
android:id="@+id/linearLayout2">
<FrameLayout
android:id="@+id/submenu_group"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<com.opencascade.jnisample.OcctJniView
android:id="@+id/custom_view"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_gravity="bottom|end" >
</com.opencascade.jnisample.OcctJniView>
<ImageButton
android:id="@+id/scroll_btn"
style="?android:borderlessButtonStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@null"
android:src="@drawable/close_p" />
<LinearLayout
android:id="@+id/panel_menu"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<ImageButton
android:id="@+id/open"
style="?android:borderlessButtonStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight=".2"
android:background="@color/btnColor"
android:src="@drawable/open" />
<ImageButton
android:id="@+id/fit"
style="?android:borderlessButtonStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight=".2"
android:background="@color/btnColor"
android:src="@drawable/fit" />
<ImageButton
android:id="@+id/view"
style="?android:borderlessButtonStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight=".2"
android:background="@color/btnColor"
android:src="@drawable/view" />
<ImageButton
android:id="@+id/info"
style="?android:borderlessButtonStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight=".2"
android:background="@color/btnColor"
android:src="@drawable/info" />
<ImageButton
android:id="@+id/message"
style="?android:borderlessButtonStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight=".2"
android:background="@color/btnColor"
android:src="@drawable/message" />
</LinearLayout>
<TextView
android:id="@+id/message_view"
android:background="@color/viewColor"
android:text="Message Log"
android:textSize="16px"
android:textStyle="bold"
android:visibility="gone"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<TextView
android:id="@+id/info_view"
android:background="@color/viewColor"
android:gravity="center"
android:text="info Log"
android:textSize="16px"
android:textStyle="bold"
android:visibility="gone"
android:layout_width="fill_parent"
android:layout_height="wrap_content"/>
<LinearLayout
android:id="@+id/view_group"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:orientation="horizontal" >
<ImageButton
style="?android:borderlessButtonStyle"
android:background="@color/btnColor"
android:id="@+id/proj_front"
android:layout_height="wrap_content"
android:layout_width="fill_parent"
android:src="@drawable/proj_front"
android:layout_weight=".16"/>
<ImageButton
style="?android:borderlessButtonStyle"
android:background="@color/btnColor"
android:id="@+id/proj_top"
android:layout_height="wrap_content"
android:layout_width="fill_parent"
android:src="@drawable/proj_top"
android:layout_weight=".16"/>
<ImageButton
style="?android:borderlessButtonStyle"
android:background="@color/btnColor"
android:id="@+id/proj_left"
android:layout_height="wrap_content"
android:layout_width="fill_parent"
android:src="@drawable/proj_left"
android:layout_weight=".16"/>
<ImageButton
style="?android:borderlessButtonStyle"
android:background="@color/btnColor"
android:id="@+id/proj_back"
android:layout_height="wrap_content"
android:layout_width="fill_parent"
android:src="@drawable/proj_back"
android:layout_weight=".16"/>
<ImageButton
style="?android:borderlessButtonStyle"
android:background="@color/btnColor"
android:id="@+id/proj_bottom"
android:layout_height="wrap_content"
android:layout_width="fill_parent"
android:src="@drawable/proj_bottom"
android:layout_weight=".16"/>
<ImageButton
style="?android:borderlessButtonStyle"
android:background="@color/btnColor"
android:id="@+id/proj_right"
android:layout_height="wrap_content"
android:layout_width="fill_parent"
android:src="@drawable/proj_right"
android:layout_weight=".16"/>
</LinearLayout>
</FrameLayout>
</LinearLayout>
</TableLayout>

View File

@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<item name="open" type="id"/>
<item name="save" type="id"/>
<item name="screenshot" type="id"/>
<item name="mesh_none" type="id"/>
<item name="mesh_low_q" type="id"/>
<item name="mesh_norm_q" type="id"/>
<item name="mesh_high_q" type="id"/>
<item name="view1" type="id"/>
<item name="view2" type="id"/>
<item name="view3" type="id"/>
<item name="settings" type="id"/>
<item name="message" type="id"/>
<item name="lock" type="id"/>
<item name="info" type="id"/>
</resources>

View File

@@ -0,0 +1,35 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">OpenCASCADE JNI Java Sample</string>
<color name="btnColor">#484848</color>
<color name="pressedBtnColor">#0099CC</color>
<color name="viewColor">#66252525</color>
<string-array name="ext_to_save">
<item>.png</item>
<item>.jpg</item>
</string-array>
<string-array name="ext_to_exp">
<item>.brep</item>
<item>.rle</item>
<item>.iges</item>
<item>.igs</item>
<item>.step</item>
<item>.stp</item>
</string-array>
<string name="wireframe_shading_title">wireframe/shading</string>
<string name="color_title">color</string>
<string name="material_title">material</string>
<string name="transparency_title">transparency</string>
<string name="hidden_lines_title">show/hide hidden lines</string>
<string name="info_html" formatted="false">
<![CDATA[
<p>OpenCASCADE JNI Java Sample</p>
<p>Simple viewer for BREP, STEP and IGES files.</p>
<p>Driven by Open CASCADE Technology %d.%d.%d.</p>
<p>Copyright 2014 OPEN CASCADE SAS.</p>
<p><img src="info_image"></p>
<p>http://www.opencascade.com</p>
<p>http://www.opencascade.org</p>
]]>
</string>
</resources>