Download Freedom & WAD Chooser

This commit is contained in:
Simon 2016-03-04 23:15:19 +00:00
parent 2f50889ce5
commit ca1d92e24c
5 changed files with 839 additions and 290 deletions

View file

View file

@ -0,0 +1,282 @@
package com.drbeef.dvr;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.os.AsyncTask;
import android.os.SystemClock;
import android.util.Log;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.net.URL;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import doom.util.DoomTools;
class DownloadTask extends AsyncTask<Void, String, Void> {
private Context context;
private ProgressDialog pd;
public boolean please_abort = false;
private String url = "https://www.dropbox.com/s/whngowjwpkwjht2/freedoom.zip?dl=1";
private String freedoomZip = DoomTools.GetDVRFolder() + "/freedoom.zip";
private String wadfile = DoomTools.GetDVRFolder() + "/freedoom.wad";
public DownloadTask set_context(Context context){
this.context = context;
return this;
}
@Override
protected void onPreExecute (){
pd = new ProgressDialog(context);
pd.setTitle("Downloading FREEDOOM WAD file ...");
pd.setMessage("starting");
pd.setIndeterminate(true);
pd.setCancelable(true);
pd.setOnDismissListener( new DialogInterface.OnDismissListener(){
public void onDismiss(DialogInterface dialog) {
Log.i( "DownloadTask.java", "onDismiss");
please_abort = true;
}
});
pd.setOnCancelListener( new DialogInterface.OnCancelListener(){
public void onCancel(DialogInterface dialog) {
Log.i( "DownloadTask.java", "onCancel");
please_abort = true;
}
});
pd.setButton(ProgressDialog.BUTTON_POSITIVE, "Cancel", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
pd.dismiss();
please_abort = true;
}
});
pd.show();
}
public static String printSize( int size ){
if ( size >= (1<<20) )
return String.format("%.1f MB", size * (1.0/(1<<20)));
if ( size >= (1<<10) )
return String.format("%.1f KB", size * (1.0/(1<<10)));
return String.format("%d bytes", size);
}
private void download_demo() throws Exception{
Log.i( "DownloadTask.java", "starting to download "+ url);
if (new File(freedoomZip).exists()){
Log.i( "DownloadTask.java", freedoomZip + " already there. skipping.");
return;
}
/// setup output directory
new File(DoomTools.GetDVRFolder()).mkdirs();
InputStream is = null;
FileOutputStream fos = null;
is = new URL(url).openStream();
fos = new FileOutputStream ( freedoomZip +".part");
byte[] buffer = new byte [4096];
int totalcount =0;
long tprint = SystemClock.uptimeMillis();
int partialcount = 0;
while(true){
if (please_abort)
throw new Exception("aborting") ;
int count = is.read (buffer);
if ( count<=0 ) break;
fos.write (buffer, 0, count);
totalcount += count;
partialcount += count;
long tnow = SystemClock.uptimeMillis();
if ( (tnow-tprint)> 1000) {
float size_MB = totalcount * (1.0f/(1<<20));
float speed_KB = partialcount * (1.0f/(1<<10)) * ((tnow-tprint)/1000.0f);
publishProgress( String.format("downloaded %.1f MB (%.1f KB/sec)",
size_MB, speed_KB));
tprint = tnow;
partialcount = 0;
}
}
is.close();
fos.close();
new File(freedoomZip +".part" )
.renameTo(new File(freedoomZip));
// done
publishProgress("download done" );
SystemClock.sleep(2000);
}
private void extract_data() throws Exception{
Log.i("DownloadTask.java", "extracting WAD data");
ZipFile file = new ZipFile (freedoomZip);
extract_file( file, "freedoom.wad", wadfile);
file.close();
// done
publishProgress("extract done" );
pd.getButton(ProgressDialog.BUTTON_POSITIVE).setText("Done");
SystemClock.sleep(1000);
}
private void extract_file( ZipFile file, String entry_name, String output_name ) throws Exception{
Log.i( "DownloadTask.java", "extracting " + entry_name + " to " + output_name);
String short_name = new File(output_name).getName();
// create output directory
new File(output_name).getParentFile().mkdirs();
ZipEntry entry = file.getEntry(entry_name);
if ( entry.isDirectory() ){
Log.i( "DownloadTask.java", entry_name + " is a directory");
new File(output_name).mkdir();
return;
}
InputStream is = null;
FileOutputStream fos = null;
is = file.getInputStream(entry);
fos = new FileOutputStream ( output_name+".part" );
byte[] buffer = new byte [4096];
int totalcount =0;
long tprint = SystemClock.uptimeMillis();
while(true){
if (please_abort)
throw new Exception("aborting") ;
int count = is.read (buffer);
//Log.i( "DownloadTask.java", "extracted " + count + " bytes");
if ( count<=0 ) break;
fos.write (buffer, 0, count);
totalcount += count;
long tnow = SystemClock.uptimeMillis();
if ( (tnow-tprint)> 1000) {
float size_MB = totalcount * (1.0f/(1<<20));
publishProgress( String.format("%s : extracted %.1f MB",
short_name, size_MB));
tprint = tnow;
}
}
is.close();
fos.close();
/// rename part file
new File(output_name+".part" )
.renameTo(new File(output_name));
// done
publishProgress( String.format("%s : done.",
short_name));
}
@Override
protected Void doInBackground(Void... unused) {
try {
//Inform game we are now downloading
//QVRJNILib.setDownloadStatus(2);
long t = SystemClock.uptimeMillis();
download_demo();
extract_data();
t = SystemClock.uptimeMillis() - t;
Log.i( "DownloadTask.java", "done in " + t + " ms");
} catch (Exception e) {
e.printStackTrace();
//QVRJNILib.setDownloadStatus(0);
publishProgress("Error: " + e );
}
return(null);
}
@Override
protected void onProgressUpdate(String... progress) {
Log.i( "DownloadTask.java", progress[0]);
pd.setMessage( progress[0]);
}
@Override
protected void onPostExecute(Void unused) {
pd.hide();
}
}

View file

@ -27,8 +27,11 @@ import com.google.vrtoolkit.cardboard.Eye;
import com.google.vrtoolkit.cardboard.HeadTransform;
import com.google.vrtoolkit.cardboard.Viewport;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
@ -51,23 +54,14 @@ public class MainActivity
{
private static final String TAG = "DVR";
private static final int GL_RGBA8 = 0x8058;
private int[] currentFBO = new int[1];
//Head orientation
private float[] eulerAngles = new float[3];
OpenGL openGL = null;
// Audio Cache Manager
private AudioManager mAudioMgr;
private int MONO = 0;
private int STEREO = 1;
private int mStereoMode = STEREO;
private int eyeID = 0;
static private Bitmap mDoomBitmap;
private Bitmap mDoomBitmap;
// width of mBitmap
private int mDoomWidth;
@ -87,127 +81,11 @@ public class MainActivity
private CardboardView cardboardView;
private FloatBuffer screenVertices;
private int positionParam;
private int texCoordParam;
private int samplerParam;
private int modelViewProjectionParam;
private float[] modelScreen;
private float[] camera;
private float[] view;
private float[] modelViewProjection;
private float[] modelView;
private float screenDistance = 8f;
private float screenScale = 4f;
public static final String vs_Image =
"uniform mat4 u_MVPMatrix;" +
"attribute vec4 a_Position;" +
"attribute vec2 a_texCoord;" +
"varying vec2 v_texCoord;" +
"void main() {" +
" gl_Position = u_MVPMatrix * a_Position;" +
" v_texCoord = a_texCoord;" +
"}";
public static final String fs_Image =
"precision mediump float;" +
"varying vec2 v_texCoord;" +
"uniform sampler2D s_texture;" +
"void main() {" +
" gl_FragColor = texture2D( s_texture, v_texCoord );" +
"}";
public static int loadShader(int type, String shaderCode){
int shader = GLES20.glCreateShader(type);
GLES20.glShaderSource(shader, shaderCode);
GLES20.glCompileShader(shader);
return shader;
}
//FBO render eye buffer
private DVRFBO fbo;
static boolean CreateFBO( DVRFBO fbo, int width, int height)
{
Log.d(TAG, "CreateFBO");
// Create the color buffer texture.
GLES20.glGenTextures(1, fbo.ColorTexture, 0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, fbo.ColorTexture[0]);
GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, null);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
// Create depth buffer.
GLES20.glGenRenderbuffers(1, fbo.DepthBuffer, 0);
GLES20.glBindRenderbuffer(GLES20.GL_RENDERBUFFER, fbo.DepthBuffer[0]);
GLES20.glRenderbufferStorage(GLES20.GL_RENDERBUFFER, GLES11Ext.GL_DEPTH_COMPONENT24_OES, width, height);
GLES20.glBindRenderbuffer(GLES20.GL_RENDERBUFFER, 0);
// Create the frame buffer.
GLES20.glGenFramebuffers(1, fbo.FrameBuffer, 0);
GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, fbo.FrameBuffer[0]);
GLES20.glFramebufferRenderbuffer(GLES20.GL_FRAMEBUFFER, GLES20.GL_DEPTH_ATTACHMENT, GLES20.GL_RENDERBUFFER, fbo.DepthBuffer[0]);
GLES20.glFramebufferTexture2D(GLES20.GL_FRAMEBUFFER, GLES20.GL_COLOR_ATTACHMENT0, GLES20.GL_TEXTURE_2D, fbo.ColorTexture[0], 0);
int renderFramebufferStatus = GLES20.glCheckFramebufferStatus(GLES20.GL_FRAMEBUFFER);
GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0);
if ( renderFramebufferStatus != GLES20.GL_FRAMEBUFFER_COMPLETE )
{
Log.d(TAG, "Incomplete frame buffer object!!");
return false;
}
fbo.width = width;
fbo.height = height;
return true;
}
static void DestroyFBO( DVRFBO fbo )
{
GLES20.glDeleteFramebuffers( 1, fbo.FrameBuffer, 0 );
fbo.FrameBuffer[0] = 0;
GLES20.glDeleteRenderbuffers( 1, fbo.DepthBuffer, 0 );
fbo.DepthBuffer[0] = 0;
GLES20.glDeleteTextures( 1, fbo.ColorTexture, 0 );
fbo.ColorTexture[0] = 0;
fbo.width = 0;
fbo.height = 0;
}
// Geometric variables
public static float vertices[];
public static final short[] indices = new short[] {0, 1, 2, 0, 2, 3};
public static final float uvs[] = new float[] {
0.0f, 1.0f,
0.0f, 0.0f,
1.0f, 0.0f,
1.0f, 1.0f
};
public static final float[] SCREEN_COORDS = new float[] {
-1.3f, -1.0f, 1.0f,
-1.3f, 1.0f, 1.0f,
1.3f, 1.0f, 1.0f,
1.3f, -1.0f, 1.0f
};
public FloatBuffer vertexBuffer;
public ShortBuffer listBuffer;
public FloatBuffer uvBuffer;
//Shader Program
public static int sp_Image;
private DownloadTask mDownloadTask = null;
private WADChooser mWADChooser = null;
public static boolean mDVRInitialised = false;
//Can't rebuild eye buffers until surface changed flag recorded
public static boolean mSurfaceChanged = false;
@ -264,6 +142,13 @@ public class MainActivity
}
}
public void startDownload()
{
mDownloadTask = new DownloadTask();
mDownloadTask.set_context(MainActivity.this);
mDownloadTask.execute();
}
@Override
public void onCreate(Bundle savedInstanceState) {
@ -282,29 +167,65 @@ public class MainActivity
cardboardView.setRenderer(this);
setCardboardView(cardboardView);
modelScreen = new float[16];
camera = new float[16];
view = new float[16];
modelViewProjection = new float[16];
modelView = new float[16];
openGL = new OpenGL();
openGL.onCreate();
vibrator = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
//At the very least ensure we have a directory containing a config file
copy_asset("DVR.cfg", DoomTools.GetDVRFolder() + "/");
copy_asset("prboom.wad", DoomTools.GetDVRFolder() + "/");
copy_asset("DVR.cfg", DoomTools.GetDVRFolder() + File.separator);
copy_asset("prboom.wad", DoomTools.GetDVRFolder() + File.separator);
copy_asset("extraparams.txt", DoomTools.GetDVRFolder() + File.separator);
if (!DoomTools.wadsExist()) {
MessageBox("Read this carefully",
"You must install a game file. Tap \"Install WADs\" for auto-install. "
+ "Tap \"Help Me!\" for instructions on manual installation. "
+ "A fast WIFI network and SDCARD are required."
+ "If you experience game problems, try the Cleanup option.");
//See if user is trying to use command line params
BufferedReader br;
try {
br = new BufferedReader(new FileReader(DoomTools.GetDVRFolder() + "extraparams.txt"));
String s;
StringBuilder sb=new StringBuilder(0);
while ((s=br.readLine())!=null)
sb.append(s + " ");
br.close();
commandLineParams = new String(sb.toString());
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if (!DoomTools.wadsExist()) {
AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(
this);
//Create the FBOs
fbo = new DVRFBO();
// set title
alertDialogBuilder.setTitle("No WAD files found");
// set dialog message
alertDialogBuilder
.setMessage("Would you like to download the free FREEDOOM WAD (8MB)?\n\nIf you own or purchase the full game of Doom/Doom2 (or any other wad)you can click \'Cancel\' and copy the WAD file to the folder:\n\n{phonememory}/DVR")
.setCancelable(false)
.setPositiveButton("Download", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
MainActivity.this.startDownload();
}
})
.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
dialog.cancel();
}
});
// create alert dialog
AlertDialog alertDialog = alertDialogBuilder.create();
// show it
alertDialog.show();
}
mWADChooser = new WADChooser(openGL);
// Audio?
mAudioMgr = AudioManager.getInstance(this);
@ -325,64 +246,12 @@ public class MainActivity
mSurfaceChanged = true;
}
void CopyBitmapToTexture(Bitmap bmp, int textureUnit)
{
// Bind texture to texturename
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureUnit);
// Set filtering
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
// Set wrapping mode
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
// Load the bitmap into the bound texture.
GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bmp, 0);
//unbind
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
}
@Override
public void onSurfaceCreated(EGLConfig config) {
Log.i(TAG, "onSurfaceCreated");
ByteBuffer bbVertices = ByteBuffer.allocateDirect(SCREEN_COORDS.length * 4);
bbVertices.order(ByteOrder.nativeOrder());
screenVertices = bbVertices.asFloatBuffer();
screenVertices.put(SCREEN_COORDS);
screenVertices.position(0);
// initialize byte buffer for the draw list
ByteBuffer dlb = ByteBuffer.allocateDirect(indices.length * 2);
dlb.order(ByteOrder.nativeOrder());
listBuffer = dlb.asShortBuffer();
listBuffer.put(indices);
listBuffer.position(0);
// Create the shaders, images
int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vs_Image);
int fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fs_Image);
sp_Image = GLES20.glCreateProgram(); // create empty OpenGL ES Program
GLES20.glAttachShader(sp_Image, vertexShader); // add the vertex shader to program
GLES20.glAttachShader(sp_Image, fragmentShader); // add the fragment shader to program
GLES20.glLinkProgram(sp_Image); // creates OpenGL ES program executable
positionParam = GLES20.glGetAttribLocation(sp_Image, "a_Position");
texCoordParam = GLES20.glGetAttribLocation(sp_Image, "a_texCoord");
modelViewProjectionParam = GLES20.glGetUniformLocation(sp_Image, "u_MVPMatrix");
samplerParam = GLES20.glGetUniformLocation(sp_Image, "s_texture");
GLES20.glEnableVertexAttribArray(positionParam);
GLES20.glEnableVertexAttribArray(texCoordParam);
// Build the camera matrix
Matrix.setLookAtM(camera, 0, 0.0f, 0.0f, 0.01f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f);
openGL.onSurfaceCreated(config);
//Start intro music
mPlayer = MediaPlayer.create(this, R.raw.m010912339);
@ -405,22 +274,27 @@ public class MainActivity
// Bind texture to texturename
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, splashTexture[0]);
CopyBitmapToTexture(bmp, splashTexture[0]);
}
public void SwitchStereoMode(int stereo_mode)
{
mStereoMode = stereo_mode;
openGL.CopyBitmapToTexture(bmp, splashTexture[0]);
}
@Override
public void onNewFrame(HeadTransform headTransform) {
headTransform.getEulerAngles(eulerAngles, 0);
float yaw = eulerAngles[1] / (M_PI / 180.0f);
float pitch = -eulerAngles[0] / (M_PI / 180.0f);
float roll = -eulerAngles[2] / (M_PI / 180.0f);
if (!mShowingSpashScreen && mWADChooser.choosingWAD())
{
return;
}
if (!mDVRInitialised) {
if (!mSurfaceChanged)
return;
SetupUVCoords();
openGL.SetupUVCoords();
//Reset our orientation
cardboardView.resetHeadTracker();
@ -428,7 +302,7 @@ public class MainActivity
if (!mShowingSpashScreen) {
final String[] argv;
String args = new String();
args = "doom -iwad " + WADChooser.GetChosenWAD();
args = "doom -iwad " + mWADChooser.GetChosenWAD() + " " + commandLineParams;
argv = args.split(" ");
String dvr= DoomTools.GetDVRFolder();
Natives.DoomInit(argv, dvr);
@ -437,11 +311,6 @@ public class MainActivity
}
if (mDVRInitialised) {
headTransform.getEulerAngles(eulerAngles, 0);
float yaw = eulerAngles[1] / (M_PI / 180.0f);
float pitch = -eulerAngles[0] / (M_PI / 180.0f);
float roll = -eulerAngles[2] / (M_PI / 180.0f);
if (Natives.gameState() == 0)
Natives.DoomStartFrame(pitch, yaw, roll);
else
@ -451,7 +320,11 @@ public class MainActivity
@Override
public void onDrawEye(Eye eye) {
if (mDVRInitialised || mShowingSpashScreen) {
if (!mShowingSpashScreen && mWADChooser.choosingWAD())
{
mWADChooser.onDrawEye(eye);
}
else if (mDVRInitialised || mShowingSpashScreen) {
if (mShowingSpashScreen) {
GLES20.glEnable(GLES20.GL_SCISSOR_TEST);
@ -463,7 +336,7 @@ public class MainActivity
Natives.DoomDrawEye(eye.getType() - 1);
//Now we'll have a populated bitmap, copy to the fbo colour buffer
CopyBitmapToTexture(mDoomBitmap, fbo.ColorTexture[0]);
openGL.CopyBitmapToTexture(mDoomBitmap, openGL.fbo.ColorTexture[0]);
}
GLES20.glViewport(eye.getViewport().x,
@ -480,27 +353,27 @@ public class MainActivity
eye.getViewport().height);
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
GLES20.glUseProgram(sp_Image);
GLES20.glUseProgram(openGL.sp_Image);
if (Natives.gameState() != 0) {
if (Natives.gameState() != 0 || mShowingSpashScreen) {
// Apply the eye transformation to the camera.
Matrix.multiplyMM(view, 0, eye.getEyeView(), 0, camera, 0);
Matrix.multiplyMM(openGL.view, 0, eye.getEyeView(), 0, openGL.camera, 0);
// Build the ModelView and ModelViewProjection matrices
// for calculating screen position.
float[] perspective = eye.getPerspective(0.1f, 100.0f);
float scale = screenScale;
float scale = openGL.screenScale;
if (mShowingSpashScreen)
scale /= 2;
// Object first appears directly in front of user.
Matrix.setIdentityM(modelScreen, 0);
Matrix.translateM(modelScreen, 0, 0, 0, -screenDistance);
Matrix.scaleM(modelScreen, 0, scale, scale, 1.0f);
Matrix.multiplyMM(modelView, 0, view, 0, modelScreen, 0);
Matrix.multiplyMM(modelViewProjection, 0, perspective, 0, modelView, 0);
GLES20.glVertexAttribPointer(positionParam, 3, GLES20.GL_FLOAT, false, 0, screenVertices);
Matrix.setIdentityM(openGL.modelScreen, 0);
Matrix.translateM(openGL.modelScreen, 0, 0, 0, -openGL.screenDistance);
Matrix.scaleM(openGL.modelScreen, 0, scale, scale, 1.0f);
Matrix.multiplyMM(openGL.modelView, 0, openGL.view, 0, openGL.modelScreen, 0);
Matrix.multiplyMM(openGL.modelViewProjection, 0, perspective, 0, openGL.modelView, 0);
GLES20.glVertexAttribPointer(openGL.positionParam, 3, GLES20.GL_FLOAT, false, 0, openGL.screenVertices);
} else {
@ -512,35 +385,35 @@ public class MainActivity
int pitchOffset = (int)(-(eulerAngles[0]/M_PI)*(eye.getViewport().height));
SetupTriangle(x, y, w, h);
openGL.SetupTriangle(x, y, w, h);
// Calculate the projection and view transformation
Matrix.orthoM(view, 0, 0, eye.getViewport().width, 0, eye.getViewport().height, 0, 50);
Matrix.orthoM(openGL.view, 0, 0, eye.getViewport().width, 0, eye.getViewport().height, 0, 50);
//Translate so origin is centre of image
if (eye.getType() == Eye.Type.LEFT)
Matrix.translateM(view, 0, w / 2, eye.getViewport().height / 2, 0);
Matrix.translateM(openGL.view, 0, w / 2, eye.getViewport().height / 2, 0);
else
Matrix.translateM(view, 0, eye.getViewport().width - w / 2, eye.getViewport().height / 2, 0);
Matrix.translateM(openGL.view, 0, eye.getViewport().width - w / 2, eye.getViewport().height / 2, 0);
//rotate for head roll
Matrix.rotateM(view, 0, (int) (-(eulerAngles[2] / M_PI) * 180.f), 0, 0, 1);
Matrix.rotateM(openGL.view, 0, (int) (-(eulerAngles[2] / M_PI) * 180.f), 0, 0, 1);
//translate back to where it was before
if (eye.getType() == Eye.Type.LEFT)
Matrix.translateM(view, 0, -w / 2, -eye.getViewport().height / 2, 0);
Matrix.translateM(openGL.view, 0, -w / 2, -eye.getViewport().height / 2, 0);
else
Matrix.translateM(view, 0, w / 2 - eye.getViewport().width, -eye.getViewport().height / 2, 0);
Matrix.translateM(openGL.view, 0, w / 2 - eye.getViewport().width, -eye.getViewport().height / 2, 0);
//Now apply head pitch transformation
Matrix.translateM(view, 0, 0, pitchOffset, 0);
Matrix.multiplyMM(modelViewProjection, 0, view, 0, camera, 0);
Matrix.translateM(openGL.view, 0, 0, pitchOffset, 0);
Matrix.multiplyMM(openGL.modelViewProjection, 0, openGL.view, 0, openGL.camera, 0);
// Prepare the triangle coordinate data
GLES20.glVertexAttribPointer(positionParam, 3, GLES20.GL_FLOAT, false, 0, vertexBuffer);
GLES20.glVertexAttribPointer(openGL.positionParam, 3, GLES20.GL_FLOAT, false, 0, openGL.vertexBuffer);
}
// Prepare the texturecoordinates
GLES20.glVertexAttribPointer(texCoordParam, 2, GLES20.GL_FLOAT, false, 0, uvBuffer);
GLES20.glVertexAttribPointer(openGL.texCoordParam, 2, GLES20.GL_FLOAT, false, 0, openGL.uvBuffer);
// Apply the projection and view transformation
GLES20.glUniformMatrix4fv(modelViewProjectionParam, 1, false, modelViewProjection, 0);
GLES20.glUniformMatrix4fv(openGL.modelViewProjectionParam, 1, false, openGL.modelViewProjection, 0);
// Bind texture to fbo's color texture
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
@ -551,14 +424,14 @@ public class MainActivity
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, splashTexture[0]);
}
else {
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, fbo.ColorTexture[0]);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, openGL.fbo.ColorTexture[0]);
}
// Set the sampler texture unit to our fbo's color texture
GLES20.glUniform1i(samplerParam, 0);
GLES20.glUniform1i(openGL.samplerParam, 0);
// Draw the triangles
GLES20.glDrawElements(GLES20.GL_TRIANGLES, 6, GLES20.GL_UNSIGNED_SHORT, listBuffer);
GLES20.glDrawElements(GLES20.GL_TRIANGLES, 6, GLES20.GL_UNSIGNED_SHORT, openGL.listBuffer);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, activeTex0.get(0));
}
}
@ -577,6 +450,18 @@ public class MainActivity
public void onCardboardTrigger() {
Log.i(TAG, "onCardboardTrigger");
if (!mShowingSpashScreen && mWADChooser.choosingWAD())
{
if (eulerAngles[1] / (M_PI / 180.0f) > 15.0f)
mWADChooser.MoveNext();
else if (eulerAngles[1] / (M_PI / 180.0f) < -15.0f)
mWADChooser.MovePrev();
else
mWADChooser.SelectWAD();
return;
}
if (System.currentTimeMillis() - triggerTimeout > 200) {
if (mDVRInitialised) {
@ -592,13 +477,6 @@ public class MainActivity
}
}
public int getCharacter(int keyCode, KeyEvent event)
{
if (keyCode==KeyEvent.KEYCODE_DEL) return '\b';
return event.getUnicodeChar();
}
private void dismissSplashScreen()
{
if (mShowingSpashScreen) {
@ -613,6 +491,30 @@ public class MainActivity
int keyCode = event.getKeyCode();
int action = event.getAction();
if (!mShowingSpashScreen &&
mWADChooser.choosingWAD())
{
if (action == KeyEvent.ACTION_UP &&
keyCode == KeyEvent.KEYCODE_BUTTON_A) {
if (eulerAngles[1] / (M_PI / 180.0f) > 10.0f)
mWADChooser.MoveNext();
else if (eulerAngles[1] / (M_PI / 180.0f) < -10.0f)
mWADChooser.MovePrev();
else
mWADChooser.SelectWAD();
}
else if (action == KeyEvent.ACTION_UP &&
keyCode == KeyEvent.KEYCODE_DPAD_LEFT) {
mWADChooser.MovePrev();
}
else if (action == KeyEvent.ACTION_UP &&
keyCode == KeyEvent.KEYCODE_DPAD_RIGHT) {
mWADChooser.MoveNext();
}
return true;
}
if ( action != KeyEvent.ACTION_DOWN && action != KeyEvent.ACTION_UP )
{
return super.dispatchKeyEvent( event );
@ -744,35 +646,6 @@ public class MainActivity
return (axisValue > axisValue2) ? axisValue : axisValue2;
}
public void SetupUVCoords()
{
// The texture buffer
ByteBuffer bb = ByteBuffer.allocateDirect(uvs.length * 4);
bb.order(ByteOrder.nativeOrder());
uvBuffer = bb.asFloatBuffer();
uvBuffer.put(uvs);
uvBuffer.position(0);
}
public void SetupTriangle(int x, int y, int width, int height)
{
// We have to create the vertices of our triangle.
vertices = new float[]
{
x, y, 0.0f,
x, y + height, 0.0f,
x + width, y + height, 0.0f,
x + width, y, 0.0f,
};
// The vertex buffer.
ByteBuffer bb = ByteBuffer.allocateDirect(vertices.length * 4);
bb.order(ByteOrder.nativeOrder());
vertexBuffer = bb.asFloatBuffer();
vertexBuffer.put(vertices);
vertexBuffer.position(0);
}
/**
* Show the menu
*/
@ -860,22 +733,13 @@ public class MainActivity
mDoomHeight = h;
mDoomBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.RGB_565);
CreateFBO(fbo, mDoomWidth, mDoomHeight);
openGL.SetBitmap(mDoomBitmap);
openGL.CreateFBO(mDoomWidth, mDoomHeight);
}
@Override
public void OnFatalError(final String text) {
MessageBox("Fatal Error", "Doom has terminated. " + "Reason: "
+ text);
try {
Thread.sleep(10000);
}
catch (InterruptedException ie){
}
// Must quit here or the LIB will crash
DoomTools.hardExit(-1);
Log.e(TAG, "ERROR: " + text);
}
@Override

View file

@ -0,0 +1,255 @@
package com.drbeef.dvr;
import android.content.pm.ActivityInfo;
import android.content.res.AssetManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.media.MediaPlayer;
import android.opengl.GLES11Ext;
import android.opengl.GLES20;
import android.opengl.GLUtils;
import android.opengl.Matrix;
import android.os.Bundle;
import android.util.Log;
import android.view.Window;
import android.view.WindowManager;
import com.google.vrtoolkit.cardboard.CardboardView;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.nio.ShortBuffer;
import javax.microedition.khronos.egl.EGLConfig;
public class OpenGL {
private static final int GL_RGBA8 = 0x8058;
Bitmap mDoomBitmap;
public void SetBitmap(Bitmap bmp)
{
mDoomBitmap = bmp;
}
public void onCreate() {
modelScreen = new float[16];
camera = new float[16];
view = new float[16];
modelViewProjection = new float[16];
modelView = new float[16];
//Create the FBOs
fbo = new DVRFBO();
}
public void onSurfaceCreated(EGLConfig config) {
Log.i("DVR", "onSurfaceCreated");
ByteBuffer bbVertices = ByteBuffer.allocateDirect(SCREEN_COORDS.length * 4);
bbVertices.order(ByteOrder.nativeOrder());
screenVertices = bbVertices.asFloatBuffer();
screenVertices.put(SCREEN_COORDS);
screenVertices.position(0);
// initialize byte buffer for the draw list
ByteBuffer dlb = ByteBuffer.allocateDirect(indices.length * 2);
dlb.order(ByteOrder.nativeOrder());
listBuffer = dlb.asShortBuffer();
listBuffer.put(indices);
listBuffer.position(0);
// Create the shaders, images
int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vs_Image);
int fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fs_Image);
sp_Image = GLES20.glCreateProgram(); // create empty OpenGL ES Program
GLES20.glAttachShader(sp_Image, vertexShader); // add the vertex shader to program
GLES20.glAttachShader(sp_Image, fragmentShader); // add the fragment shader to program
GLES20.glLinkProgram(sp_Image); // creates OpenGL ES program executable
positionParam = GLES20.glGetAttribLocation(sp_Image, "a_Position");
texCoordParam = GLES20.glGetAttribLocation(sp_Image, "a_texCoord");
modelViewProjectionParam = GLES20.glGetUniformLocation(sp_Image, "u_MVPMatrix");
samplerParam = GLES20.glGetUniformLocation(sp_Image, "s_texture");
GLES20.glEnableVertexAttribArray(positionParam);
GLES20.glEnableVertexAttribArray(texCoordParam);
// Build the camera matrix
Matrix.setLookAtM(camera, 0, 0.0f, 0.0f, 0.01f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f);
}
void CopyBitmapToTexture(Bitmap bmp, int textureUnit)
{
// Bind texture to texturename
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureUnit);
// Set filtering
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
// Set wrapping mode
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
// Load the bitmap into the bound texture.
GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bmp, 0);
//unbind
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
}
public void SetupUVCoords()
{
// The texture buffer
ByteBuffer bb = ByteBuffer.allocateDirect(uvs.length * 4);
bb.order(ByteOrder.nativeOrder());
uvBuffer = bb.asFloatBuffer();
uvBuffer.put(uvs);
uvBuffer.position(0);
}
public void SetupTriangle(int x, int y, int width, int height)
{
// We have to create the vertices of our triangle.
vertices = new float[]
{
x, y, 0.0f,
x, y + height, 0.0f,
x + width, y + height, 0.0f,
x + width, y, 0.0f,
};
// The vertex buffer.
ByteBuffer bb = ByteBuffer.allocateDirect(vertices.length * 4);
bb.order(ByteOrder.nativeOrder());
vertexBuffer = bb.asFloatBuffer();
vertexBuffer.put(vertices);
vertexBuffer.position(0);
}
public FloatBuffer screenVertices;
public int positionParam;
public int texCoordParam;
public int samplerParam;
public int modelViewProjectionParam;
public float[] modelScreen;
public float[] camera;
public float[] view;
public float[] modelViewProjection;
public float[] modelView;
public float screenDistance = 8f;
public float screenScale = 4f;
public static final String vs_Image =
"uniform mat4 u_MVPMatrix;" +
"attribute vec4 a_Position;" +
"attribute vec2 a_texCoord;" +
"varying vec2 v_texCoord;" +
"void main() {" +
" gl_Position = u_MVPMatrix * a_Position;" +
" v_texCoord = a_texCoord;" +
"}";
public static final String fs_Image =
"precision mediump float;" +
"varying vec2 v_texCoord;" +
"uniform sampler2D s_texture;" +
"void main() {" +
" gl_FragColor = texture2D( s_texture, v_texCoord );" +
"}";
public static int loadShader(int type, String shaderCode){
int shader = GLES20.glCreateShader(type);
GLES20.glShaderSource(shader, shaderCode);
GLES20.glCompileShader(shader);
return shader;
}
//FBO render eye buffer
public DVRFBO fbo;
boolean CreateFBO( int width, int height)
{
Log.d("DVR", "CreateFBO");
// Create the color buffer texture.
GLES20.glGenTextures(1, fbo.ColorTexture, 0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, fbo.ColorTexture[0]);
GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, null);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
// Create depth buffer.
GLES20.glGenRenderbuffers(1, fbo.DepthBuffer, 0);
GLES20.glBindRenderbuffer(GLES20.GL_RENDERBUFFER, fbo.DepthBuffer[0]);
GLES20.glRenderbufferStorage(GLES20.GL_RENDERBUFFER, GLES11Ext.GL_DEPTH_COMPONENT24_OES, width, height);
GLES20.glBindRenderbuffer(GLES20.GL_RENDERBUFFER, 0);
// Create the frame buffer.
GLES20.glGenFramebuffers(1, fbo.FrameBuffer, 0);
GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, fbo.FrameBuffer[0]);
GLES20.glFramebufferRenderbuffer(GLES20.GL_FRAMEBUFFER, GLES20.GL_DEPTH_ATTACHMENT, GLES20.GL_RENDERBUFFER, fbo.DepthBuffer[0]);
GLES20.glFramebufferTexture2D(GLES20.GL_FRAMEBUFFER, GLES20.GL_COLOR_ATTACHMENT0, GLES20.GL_TEXTURE_2D, fbo.ColorTexture[0], 0);
int renderFramebufferStatus = GLES20.glCheckFramebufferStatus(GLES20.GL_FRAMEBUFFER);
GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0);
if ( renderFramebufferStatus != GLES20.GL_FRAMEBUFFER_COMPLETE )
{
Log.d("DVR", "Incomplete frame buffer object!!");
return false;
}
fbo.width = width;
fbo.height = height;
return true;
}
void DestroyFBO( )
{
GLES20.glDeleteFramebuffers( 1, fbo.FrameBuffer, 0 );
fbo.FrameBuffer[0] = 0;
GLES20.glDeleteRenderbuffers( 1, fbo.DepthBuffer, 0 );
fbo.DepthBuffer[0] = 0;
GLES20.glDeleteTextures( 1, fbo.ColorTexture, 0 );
fbo.ColorTexture[0] = 0;
fbo.width = 0;
fbo.height = 0;
}
// Geometric variables
public static float vertices[];
public static final short[] indices = new short[] {0, 1, 2, 0, 2, 3};
public static final float uvs[] = new float[] {
0.0f, 1.0f,
0.0f, 0.0f,
1.0f, 0.0f,
1.0f, 1.0f
};
public static final float[] SCREEN_COORDS = new float[] {
-1.3f, -1.0f, 1.0f,
-1.3f, 1.0f, 1.0f,
1.3f, 1.0f, 1.0f,
1.3f, -1.0f, 1.0f
};
public FloatBuffer vertexBuffer;
public ShortBuffer listBuffer;
public FloatBuffer uvBuffer;
//Shader Program
public static int sp_Image;
}

View file

@ -1,14 +1,162 @@
package com.drbeef.dvr;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.opengl.GLES20;
import android.opengl.Matrix;
import com.google.vrtoolkit.cardboard.Eye;
import java.io.File;
import java.nio.IntBuffer;
import java.util.ArrayList;
import java.util.List;
import doom.util.DoomTools;
import doom.util.Natives;
/**
* Created by Simon on 04/03/2016.
*/
public class WADChooser {
static String wad = "doom.wad";
OpenGL openGL = null;
public static String GetChosenWAD()
List<String> wads = new ArrayList<String>();
private int selectedWAD = 0;
WADChooser(OpenGL openGL) {
this.openGL = openGL;
File[] files = new File(DoomTools.GetDVRFolder()).listFiles();
for (File file : files) {
if (file.isFile() &&
file.getName().toUpperCase().compareTo("PRBOOM.WAD") != 0 &&
file.getName().toUpperCase().endsWith("WAD"))
wads.add(file.getName());
}
//No point choosing a wad if there's only one!
if (wads.size() == 1) mChoosingWAD = false;
}
private boolean mChoosingWAD = true;
public boolean choosingWAD() {
return mChoosingWAD;
}
public void SelectWAD()
{
return wad;
mChoosingWAD = false;
}
public String GetChosenWAD() {
return wads.get(selectedWAD);
}
public void MoveNext()
{
selectedWAD++;
if (selectedWAD == wads.size())
selectedWAD = 0;
}
public void MovePrev()
{
selectedWAD--;
if (selectedWAD < 0)
selectedWAD = wads.size()-1;
}
void DrawWADName()
{
// Create an empty, mutable bitmap
Bitmap bitmap = Bitmap.createBitmap(256, 256, Bitmap.Config.ARGB_4444);
// get a canvas to paint over the bitmap
Canvas canvas = new Canvas(bitmap);
bitmap.eraseColor(0);
// get a background image from resources
// note the image format must match the bitmap format
// Drawable background = context.getResources().getDrawable(R.drawable.background);
// background.setBounds(0, 0, 256, 256);
// background.draw(canvas); // draw the background to our bitmap
// Draw the text
Paint textPaint = new Paint();
textPaint.setTextSize(20);
textPaint.setAntiAlias(true);
textPaint.setARGB(0xff, 0xff, 0x20, 0x00);
// draw the text centered
canvas.drawText("Choose WAD:", 16, 60, textPaint);
canvas.drawText("<- " + GetChosenWAD() + " ->", 16, 112, textPaint);
openGL.CopyBitmapToTexture(bitmap, openGL.fbo.ColorTexture[0]);
}
public void onDrawEye(Eye eye) {
DrawWADName();
GLES20.glEnable(GLES20.GL_SCISSOR_TEST);
GLES20.glScissor(eye.getViewport().x, eye.getViewport().y,
eye.getViewport().width, eye.getViewport().height);
GLES20.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);
GLES20.glViewport(eye.getViewport().x,
eye.getViewport().y,
eye.getViewport().width,
eye.getViewport().height);
//Clear the viewport
GLES20.glEnable(GLES20.GL_SCISSOR_TEST);
GLES20.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
GLES20.glScissor(eye.getViewport().x,
eye.getViewport().y,
eye.getViewport().width,
eye.getViewport().height);
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
GLES20.glUseProgram(openGL.sp_Image);
// Apply the eye transformation to the camera.
Matrix.multiplyMM(openGL.view, 0, eye.getEyeView(), 0, openGL.camera, 0);
// Build the ModelView and ModelViewProjection matrices
// for calculating screen position.
float[] perspective = eye.getPerspective(0.1f, 100.0f);
// Object first appears directly in front of user.
Matrix.setIdentityM(openGL.modelScreen, 0);
Matrix.translateM(openGL.modelScreen, 0, 0, 0, -openGL.screenDistance);
Matrix.scaleM(openGL.modelScreen, 0, openGL.screenScale, openGL.screenScale, 1.0f);
Matrix.multiplyMM(openGL.modelView, 0, openGL.view, 0, openGL.modelScreen, 0);
Matrix.multiplyMM(openGL.modelViewProjection, 0, perspective, 0, openGL.modelView, 0);
GLES20.glVertexAttribPointer(openGL.positionParam, 3, GLES20.GL_FLOAT, false, 0, openGL.screenVertices);
// Prepare the texturecoordinates
GLES20.glVertexAttribPointer(openGL.texCoordParam, 2, GLES20.GL_FLOAT, false, 0, openGL.uvBuffer);
// Apply the projection and view transformation
GLES20.glUniformMatrix4fv(openGL.modelViewProjectionParam, 1, false, openGL.modelViewProjection, 0);
// Bind texture to fbo's color texture
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
IntBuffer activeTex0 = IntBuffer.allocate(2);
GLES20.glGetIntegerv(GLES20.GL_TEXTURE_BINDING_2D, activeTex0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, openGL.fbo.ColorTexture[0]);
// Set the sampler texture unit to our fbo's color texture
GLES20.glUniform1i(openGL.samplerParam, 0);
// Draw the triangles
GLES20.glDrawElements(GLES20.GL_TRIANGLES, 6, GLES20.GL_UNSIGNED_SHORT, openGL.listBuffer);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, activeTex0.get(0));
}
}