3D Views: Source Code
Page 1
Main Screen - App Description
The 3D Views
app allows you to view scenes in three dimensions with OpenGL ES.Swipe left and right to view in 3600.Tap the scene to see the next scene.
The right navigation bar includes an X
icon, world icon and Tap - View
text. Tap the X
to exit the application.Tap the world icon for more 3D content at my 3D sub domain.Tap the Tap - View
text to see a new scene.
Introduction
The 3D Views
Android app incorporates two dimensionaland three dimensional code with Java, OpenGL ES, XML resources, photographs, Photoshop 2D images and 3ds Max renderings.This short series of code demonstrates how to prepare a simple 3D model viewer for Android.
The CubeViewActivity
Java class loads the application's mainActivity
, creates an OpenGL ES SurfaceView
, changes views when you tap the scene, closes the app when you tap the upper right corner X
,opens the Web browser to my 3D subdomain when you tap the Web (World) icon,saves and restores the view.
Updated
This app has been updated (8/23/23) with an action bar.An X
allows users to quickly exit and a world iconnavigates to more 3D scenes online.
Java Activity
CubeViewActivity Subclass of Activity
package com.seventhundersoftware.cubeview; import android.content.ActivityNotFoundException; import android.content.Intent; import android.content.SharedPreferences; import android.content.pm.ActivityInfo; import android.app.Activity; import android.app.ActivityManager; import android.content.Context; import android.content.pm.ConfigurationInfo; import android.net.Uri; import android.os.Build; import android.os.Bundle; import android.util.DisplayMetrics; import android.util.Log; import android.view.View; import android.view.View.OnSystemUiVisibilityChangeListener; import android.widget.FrameLayout; import android.widget.Button; import android.widget.ImageButton; import android.widget.LinearLayout; import android.widget.TextView; import android.widget.Toast; import com.seventhundersoftware.cubeview.common.TextureHelper; import static com.seventhundersoftware.cubeview.CubeViewConstants.*; /*** * Copyright (c) 2021 Amy Washburn Butler * GNU General Public License v3.0 * The CubeViewActivity class loads the application's main * Activity, creates an OpenGL ES SurfaceView, * changes views, when the user taps a translucent, overlay button, * saves and restores the view. * * The app's lifecycle pairs: * onCreate() onDestroy() * onPause(), onResume(), * onSaveInstanceState(), onRestoreInstanceState(), * onStart(),onStop() */ public class CubeViewActivity extends Activity { public static final String PREFERENCE_FILE_NAME = "CubeView.xml"; /** Hold a reference to our GLSurfaceView */ private CubeViewGLSurfaceView mGLSurfaceView = null; private CubeViewRenderer mRenderer = null; private Context mContext = null; private static final String SETTING_VIEWS = "setting_views"; private static final String TAG = "CubeViewActivity"; private ActivityManager activityManager = null; private ConfigurationInfo configurationInfo = null; private boolean supportsEs2 = false; private int currentApiVersion; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); FrameLayout fl = (FrameLayout) findViewById(R.id.cube_view); setContentView(R.layout.cube_view); this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); ImageButton btnClose = (ImageButton) findViewById(R.id.btn_close); btnClose.setOnClickListener(this::onButtonStop) ; ImageButton btnEmail = (ImageButton) findViewById(R.id.btn_web); btnEmail.setOnClickListener(this::onButtonWeb) ; TextView btnTap = (TextView) findViewById(R.id.btn_info); btnTap.setOnClickListener(this::onButtonTap) ; currentApiVersion = android.os.Build.VERSION.SDK_INT; final int flags = View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY; if (currentApiVersion >= Build.VERSION_CODES.KITKAT) { getWindow().getDecorView().setSystemUiVisibility(flags); final View decorView = getWindow().getDecorView(); decorView.setOnSystemUiVisibilityChangeListener(new OnSystemUiVisibilityChangeListener() { @Override public void onSystemUiVisibilityChange(int visibility) { if ((visibility & View.SYSTEM_UI_FLAG_FULLSCREEN) == 0) { decorView.setSystemUiVisibility(flags); } } }); } mGLSurfaceView = findViewById(R.id.gl_surface_view); mContext = this; // Check if the system supports OpenGL ES 2.0. activityManager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE); configurationInfo = activityManager.getDeviceConfigurationInfo(); supportsEs2 = configurationInfo.reqGlEsVersion >= 0x20000; // Request an OpenGL ES 2.0 compatible context. mGLSurfaceView.setEGLContextClientVersion(2); } public void onButtonStop(View v){ int clicked_btn_stop = Log.d(TAG, "clicked stop button"); this.onCloseApp(); } public void onButtonTap(View v){ int clicked_btn_stop = Log.d(TAG, "clicked tap button"); mGLSurfaceView.assignView(); } public void onButtonWeb(View v){ int clicked_btn_web = Log.d(TAG, "clicked email button"); try { Uri webpage = Uri.parse("https://3d.7Thunders.biz"); Intent myIntent = new Intent( Intent.ACTION_VIEW, webpage); startActivity(myIntent); } catch (ActivityNotFoundException e) { Toast.makeText(this, "No application can handle this request." + " Please install a webbrowser", Toast.LENGTH_LONG).show(); } Log.d(TAG, "Starting Web browser."); this.onCloseApp(); } /*** * Close the application from * the X button and browser world icon. * Used profiler to verify all memory's cleaned up. * finish() calls onDestroy(). */ protected void onCloseApp(){ this.finish(); } /*** * OnDestroy() and onCreate() often pair. * Meaning if onDestroy() is called, then * onCreate() will be called at start up. */ @Override protected void onDestroy(){ super.onDestroy(); TextureHelper.FreeTexture(); if(mRenderer != null){ mRenderer.onDestroy(); } Log.d(TAG,"onDestroy()"); // Profiler won't display lingering memory: System.exit(0); } /*** * onResume() and onPause() often pair. * Meaning if onPause() is called, then * onResume() will be called at start up. */ @Override protected void onResume() { super.onResume(); Log.d(TAG,"onResume()"); if (supportsEs2) { // Request an OpenGL ES 2.0 compatible context. mGLSurfaceView.setEGLContextClientVersion(2); final DisplayMetrics displayMetrics = new DisplayMetrics(); getWindowManager().getDefaultDisplay().getMetrics(displayMetrics); // Activity creates SurfaceView. // Activity creates Renderer. // SurfaceView assigns Renderer. // The last parameter is the image number. if(mRenderer == null){ mRenderer = new CubeViewRenderer(this); mGLSurfaceView.setRenderer(mRenderer, displayMetrics.density); } Log.d(TAG,"onCreate()"); } } /*** * Android pauses or moves away from app. */ @Override protected void onPause() { super.onPause(); int iSaveView = I_ISLANDS; SharedPreferences sharedPrefs = getApplicationContext().getSharedPreferences(PREFERENCE_FILE_NAME, Context.MODE_PRIVATE); SharedPreferences.Editor editor = sharedPrefs.edit(); if(mGLSurfaceView != null){ iSaveView = mGLSurfaceView.getView(); } editor.putInt(SETTING_VIEWS, iSaveView); editor.apply(); Log.d(TAG,"onPause()"); } /*** * onStart() and onStart() often pair. * Left here for output to show the * Android life cycle. */ @Override protected void onStart() { super.onStart(); Log.d(TAG,"onStart()"); } @Override protected void onStop() { super.onStop(); Log.d(TAG,"onStop()"); } /*** * onSaveInstanceState() and onRestoreInstanceState() * often pair. However when view orientation is * restricted to either landscape or portrait, * then onRestoreInstanceState() is not called. * This app only displays in landscape mode. * Therefore these two methods are just left * for reference. * @param savedInstanceState: Bundle to save state. */ @Override protected void onSaveInstanceState (Bundle savedInstanceState){ super.onSaveInstanceState(savedInstanceState); } @Override public void onRestoreInstanceState(Bundle savedInstanceState) { super.onRestoreInstanceState(savedInstanceState); } }
Graphics
The island scene and art gallery graphics were prepared with 3ds Max and Photoshop.The lighthouse scene was modified from iPhone photos taken in panoramic mode.The grid view was prepared with Photoshop.
Summary
The CubeViewActivity
Java class loads the application's mainActivity
, creates an OpenGL ES SurfaceView
, changes views when you tap the scene, closes the app when you tap the upper right corner X
,opens the Web browser to my 3D subdomain when you tap the Web (World) icon,saves and restores the view.
Java & OpenGL ES
This set of pages include Android Java, combined with OpenGL ES, to display a set of simple three dimensional views. The views apply a unique, simple concept to render 3D backgrounds, without Skyboxes or time consuming shader switching. Each view's contained in one graphic, with room for other sprites and meshes.
Java and OpenGL ES source code was ported from WebGL with only minor changes.
The book, 3D Scenes: Learn WebGL Book 3
, explains implementation
and graphics preparation for the WebGL app, in detail.