Commit 70378f53 authored by Ruben Jesus Garcia Hernandez's avatar Ruben Jesus Garcia Hernandez
Browse files

Changes to submit NOMADGearVR to Oculus Store and to update to latest

NOMADVRLib
Add missing initialization to rply, add NOMAD License to rply.
parent 52e7546f
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.lrz.NOMADGearvrT"
android:versionCode="1"
android:versionName="1.0" >
android:versionCode="2"
android:versionName="1.0"
android:installLocation="auto"
>
<uses-sdk android:minSdkVersion="21" android:targetSdkVersion="21" />
<!-- Allow reading of the appropriate lens distortion file for the device. -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
......@@ -16,7 +19,7 @@
<uses-feature android:name="android.hardware.usb.host" />
<!-- Tell the system this app requires OpenGL ES 3.0. -->
<!--rgh: For tesselation, we need 3.2-->
<uses-feature android:glEsVersion="0x00030002" android:required="true" />
<uses-feature android:glEsVersion="0x00030001" android:required="true" />
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
......@@ -30,7 +33,8 @@
android:label="@string/app_name"
android:launchMode="singleTask"
android:screenOrientation="landscape"
android:configChanges="orientation|screenSize|keyboard|keyboardHidden">
android:configChanges= "screenSize|screenLayout|orientation|keyboardHidden|keyboard|navigation"
android:excludeFromRecents="true">
<!--Test opening a NOMAD url-->
<intent-filter>
<action android:name="android.intent.action.VIEW" />
......@@ -49,9 +53,10 @@
android:mimeType="application/octet-stream"/>
</intent-filter>
<!-- This filter lets the apk show up as a launchable icon -->
<!-- rgh: hiding as only the gearvrchooser should be shown -->
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
<category android:name="android.intent.category.INFO" />
</intent-filter>
</activity>
</application>
......
......@@ -15,6 +15,8 @@ android {
defaultConfig {
minSdkVersion 21
targetSdkVersion 21
versionCode 2
versionName "0.2"
}
sourceSets {
......
......@@ -14,7 +14,10 @@ LOCAL_SRC_FILES := ../../../Src/OvrApp.cpp ../../../Src/rply/rply.c \
../../../Src/NOMADVRLib/UnitCellShaders.cpp \
../../../Src/NOMADVRLib/polyhedron.cpp \
../../../Src/NOMADVRLib/IsosurfacesGL.cpp \
../../../Src/NOMADVRLib/IsoShaders.cpp
../../../Src/NOMADVRLib/IsoShaders.cpp \
../../../Src/NOMADVRLib/grid.cpp \
../../../Src/NOMADVRLib/markerShaders.cpp
LOCAL_STATIC_LIBRARIES := vrsound vrmodel vrlocale vrgui vrappframework systemutils libovrkernel
LOCAL_SHARED_LIBRARIES := vrapi
......
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">NOMADGearvrT</string>
<string name="app_name">NOMAD GearVR</string>
<string name="action_settings">Settings</string>
<string name="hello_world">Hello world!</string>
......
package oculus;
//This file is the same, except for the package above, as
//NOMADgvrT\src\main\java\com\google\vr\ndk\samples\treasurehunt\Filepath.java
//https://stackoverflow.com/questions/3401579/get-filename-and-path-from-uri-from-mediastore/7265235#7265235
class Filepath {
//@SuppressLint("NewApi")
public static String getFilePath(android.content.Context context, android.net.Uri uri) throws java.net.URISyntaxException {
String selection = null;
String[] selectionArgs = null;
// Uri is different in versions after KITKAT (Android 4.4), we need to
if (android.os.Build.VERSION.SDK_INT >= 19 && android.provider.DocumentsContract.isDocumentUri(context.getApplicationContext(), uri)) {
if (isExternalStorageDocument(uri)) {
final String docId = android.provider.DocumentsContract.getDocumentId(uri);
final String[] split = docId.split(":");
return android.os.Environment.getExternalStorageDirectory() + "/" + split[1];
} else if (isDownloadsDocument(uri)) {
final String id = android.provider.DocumentsContract.getDocumentId(uri);
uri = android.content.ContentUris.withAppendedId(
android.net.Uri.parse("content://downloads/public_downloads"), Long.valueOf(id));
} else if (isMediaDocument(uri)) {
final String docId = android.provider.DocumentsContract.getDocumentId(uri);
final String[] split = docId.split(":");
final String type = split[0];
if ("image".equals(type)) {
uri = android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
} else if ("video".equals(type)) {
uri = android.provider.MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
} else if ("audio".equals(type)) {
uri = android.provider.MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
}
selection = "_id=?";
selectionArgs = new String[]{
split[1]
};
}
}
if ("content".equalsIgnoreCase(uri.getScheme())) {
String[] projection = {
android.provider.MediaStore.Images.Media.DATA
};
android.database.Cursor cursor = null;
try {
cursor = context.getContentResolver()
.query(uri, projection, selection, selectionArgs, null);
int column_index = cursor.getColumnIndexOrThrow(android.provider.MediaStore.Images.Media.DATA);
if (cursor.moveToFirst()) {
return cursor.getString(column_index);
}
} catch (Exception e) {
}
} else if ("file".equalsIgnoreCase(uri.getScheme())) {
return uri.getPath();
}
return null;
}
public static boolean isExternalStorageDocument(android.net.Uri uri) {
return "com.android.externalstorage.documents".equals(uri.getAuthority());
}
public static boolean isDownloadsDocument(android.net.Uri uri) {
return "com.android.providers.downloads.documents".equals(uri.getAuthority());
}
public static boolean isMediaDocument(android.net.Uri uri) {
return "com.android.providers.media.documents".equals(uri.getAuthority());
}
}
......@@ -25,49 +25,82 @@ public class MainActivity extends VrActivity {
System.loadLibrary("ovrapp");
}
public static native long nativeSetAppInterface( VrActivity act, String fromPackageNameString, String commandString, String uriString );
//http://stackoverflow.com/questions/8854359/exception-open-failed-eacces-permission-denied-on-android
// Storage Permissions
private static final int REQUEST_EXTERNAL_STORAGE = 1;
private static String[] PERMISSIONS_STORAGE = {
android.Manifest.permission.READ_EXTERNAL_STORAGE,
android.Manifest.permission.WRITE_EXTERNAL_STORAGE
};
/**
* Checks if the app has permission to write to device storage
*
* If the app does not has permission then the user will be prompted to grant permissions
*
* @param activity
*/
public static void verifyStoragePermissions(android.app.Activity activity) {
// Check if we have write permission
/* int permission = android.support.v4.app.ActivityCompat.checkSelfPermission(activity, android.Manifest.permission.WRITE_EXTERNAL_STORAGE);
if (permission != android.content.pm.PackageManager.PERMISSION_GRANTED) {
// We don't have permission so prompt the user
android.support.v4.app.ActivityCompat.requestPermissions(
activity,
PERMISSIONS_STORAGE,
REQUEST_EXTERNAL_STORAGE
);
}*/
}
public static native long nativeSetAppInterface( VrActivity act, String fromPackageNameString, String commandString, String uriString );
/*
@Override
protected void onActivityResult(int requestCode, int resultCode, android.content.Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if(requestCode==123 && resultCode==RESULT_OK) {
String s=data.getDataString();
android.util.Log.d("NOMADGearvrT","OnActivityResult, s="+s);
String uriString="";
if (s.startsWith("file://")) {
uriString=s.substring(7);
} else if (s.startsWith("content://com.asus.filemanager.OpenFileProvider/file")) {
uriString=s.substring(52);
} else {
android.net.Uri u=android.net.Uri.parse(s);
try {
uriString=Filepath.getFilePath (this.getApplicationContext(), u);
} catch (java.net.URISyntaxException e) {
android.util.Log.d("NOMADgvrT","URISyntaxException, e="+e);
uriString=null;
}
}
android.util.Log.d("NOMADgvrT","OnActivityResult, uri="+uriString);
nativeSetConfigFile(uriString, android.os.Environment.getExternalStorageDirectory().getPath() + "/");
nativeLoadConfigFile(nativeTreasureHuntRenderer);
}
}
*/
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
verifyStoragePermissions(this);
Intent intent = getIntent();
String commandString = VrActivity.getCommandStringFromIntent( intent );
String fromPackageNameString = VrActivity.getPackageStringFromIntent( intent );
String uriString = VrActivity.getUriStringFromIntent( intent );
//rgh: if intent, save to tmp file and pass it over
if (uriString.startsWith("content://")) {
//http://stackoverflow.com/questions/14364091/retrieve-file-path-from-caught-downloadmanager-intent
//http://stackoverflow.com/questions/1477269/write-a-binary-downloaded-file-to-disk-in-java
//http://stackoverflow.com/questions/4864875/folder-for-temporary-files-creation-in-android-why-does-data-local-tmp-doesnt
uriString="file:///data/local/tmp/material.ncfg";
try {
java.io.InputStream input = getContentResolver().openInputStream(intent.getData());
byte[] buffer = new byte[8 * 1024];
java.io.FileOutputStream output = new java.io.FileOutputStream("/data/local/tmp/material.ncfg");
try{
int bytesRead;
while((bytesRead = input.read()) != -1){
output.write(buffer, 0, bytesRead);
}
} finally {
try{
output.close();
} catch (Exception e) {
uriString="error";
}
try {
input.close();
} catch (java.io.IOException e) {
uriString="error";
}
}
} catch (java.io.IOException e) {
uriString="error";
}
String uriString = VrActivity.getUriStringFromIntent( intent );
android.net.Uri u=android.net.Uri.parse(uriString);
try {
uriString=Filepath.getFilePath (this.getApplicationContext(), u);
} catch (java.net.URISyntaxException e) {
android.util.Log.d("NOMADgvrT","URISyntaxException, e="+e);
uriString=null;
}
setAppPtr( nativeSetAppInterface( this, fromPackageNameString, commandString, uriString ) );
}
}
......@@ -34,7 +34,7 @@ void eprintf( const char *fmt, ... )
vsprintf( buffer, fmt, args );
va_end( args );
LOG("Error in NOMADGearvrT");
LOG("Message from NOMADGearvrT");
if (*fmt=='\0')
LOG("Empty format");
LOG("<%s>", buffer);
......@@ -105,33 +105,55 @@ void OvrApp::OneTimeInit( const char * fromPackage, const char * launchIntentJSO
OVR_UNUSED( fromPackage );
OVR_UNUSED( launchIntentJSON );
LOG("OneTimeInit, launchintentURI");
LOG("NOMADGearVRT, OneTimeInit, launchintentURI");
LOG(launchIntentURI);
LOG("launchIntentURI==null");
LOG("NOMADGearVRT, launchIntentURI==null");
LOG("%d", launchIntentURI==nullptr);
//LOG("length of launchIntentURI=%d", strlen(launchIntentURI));
//for (unsigned int i=0;i<strlen(launchIntentURI);i++) {
// LOG("<%c>: [%d]", launchIntentURI[i], launchIntentURI[i]);
//}
const char *defaultURI="file:///sdcard/Oculus/NOMAD/ViveTDefault.ncfg";
//open a default file if none given
if (!launchIntentURI || !strcmp(launchIntentURI, "")) {
LOG(" OneTimeInit changing launchIntentURI");
launchIntentURI=defaultURI;
const char *configLocation="/sdcard/NOMAD/NOMADGearVR.cfg";
const char *defaultURI="/sdcard/Oculus/NOMAD/ViveTDefault.ncfg";
char finalURI[1024];
FILE *cl = fopen (configLocation, "r");
if (cl==nullptr) {
LOG("NOMADGearVRT, /sdcard/NOMAD/NOMADGearVR.cfg not found, using default at /sdcard/Oculus/NOMAD/ViveTDefault.ncfg");
strcpy(finalURI, defaultURI);
} else {
fgets(finalURI, 1024, cl);
//discard newline
int l=strlen(finalURI);
if (finalURI[l-1]=='\n')
finalURI[l-1]='\0';
LOG("NOMADGearVRT, /sdcard/NOMAD/NOMADGearVR.cfg found, using contents=%s", finalURI);
fclose (cl);
}
LOG("OneTimeInit, launchintentURI");
//open a default file if none given
//if (!launchIntentURI || !strcmp(launchIntentURI, "")) {
// LOG(" OneTimeInit changing launchIntentURI");
// launchIntentURI=finalURI;
//}
LOG("NOMADGearVRT OneTimeInit, launchintentURI");
LOG(launchIntentURI);
const char *configfile=launchIntentURI+6; //discard file://
const char *configfile=finalURI;
//change cwd so that relative paths work
std::string s(configfile);
chdir(s.substr(0, s.find_last_of("\\/")).c_str());
LOG("NOMADGEARVRT, configfile=%s", configfile);
int r;
LOG("OneTimeInit, 8");
LOG("NOMADGearVRT OneTimeInit, 8");
if ((r=loadConfigFile(configfile))<0) {
if (-100<r) {
eprintf(loadConfigFileErrors[-r]);
......@@ -150,7 +172,7 @@ void OvrApp::OneTimeInit( const char * fromPackage, const char * launchIntentJSO
}
if (!solid) {
LOG("No atom glyph specified, using Icosahedron");
LOG("NOMADGearVRT No atom glyph specified, using Icosahedron");
solid=new Solid(Solid::Type::Icosahedron);
}
LOG("OneTimeInit, 2");
......@@ -185,7 +207,7 @@ LOG("OneTimeInit, 4");
//rgh: for now, we don't have any tess-ready phones
//if (!PrepareAtomShader(&AtomsP, &AtomMatrixLoc)) {
hasTess=false;
if (!PrepareAtomShaderNoTess(&AtomsP, &AtomMatrixLoc))
if (!PrepareAtomShaderNoTess(&AtomsP, &AtomMatrixLoc, &TotalatomsLoc))
eprintf ("PrepareAtomShaderNoTess failed");
//};
//LOG("OneTimeInit, 7");
......@@ -197,7 +219,7 @@ LOG("OneTimeInit, 4");
if (e!=GL_NO_ERROR)
eprintf ("atomTexture error %d", e);
//LOG("OneTimeInit, 7A");
e=SetupAtoms(&AtomTVAO, &AtomTBuffer);
e=SetupAtoms(&AtomTVAO, &AtomTBuffer, &BondIndices);
if (e!=GL_NO_ERROR)
eprintf ("SetupAtoms error %d", e);
//LOG("OneTimeInit, 7B");
......@@ -213,6 +235,15 @@ LOG("OneTimeInit, 4");
if (ISOS) {
PrepareISOShader(&ISOP, &ISOMatrixLoc);
float m=BACKGROUND[0];
m=std::max(m, BACKGROUND[1]);
m=std::max(m, BACKGROUND[2]);
if (m>0.2f) { //make background darker, preserving colour, so additive blending works
for (int i=0;i<3;i++)
BACKGROUND[i]*=0.2f / m;
}
std::vector<float> vertices;
#ifndef INDICESGL32
std::vector<short> indices;
......@@ -236,10 +267,40 @@ LOG("OneTimeInit, 4");
for (int p = 0; p < TIMESTEPS*ISOS; p++) {
sprintf(tmpname, "%s%d-%s.ply", PATH, timestep,
plyfiles[p % ISOS]);
Matrix4f matFinal=Matrix4f::RotationX(-M_PI_2) *
Matrix4f matFinal;
/*matFinal=Matrix4f::RotationX(-M_PI_2) *
Matrix4f::Translation(translations[p%ISOS][0],
translations[p%ISOS][1],
translations[p%ISOS][2]);
*/
//gvr
if (voxelSize[0]!=-1) {
Matrix4f mvs, abcm, matcubetrans, sctrans, sc;
mvs=Matrix4f::Scaling(scaling/(float)voxelSize[0], scaling/(float)voxelSize[1],
scaling/(float)voxelSize[2]);
matcubetrans=Matrix4f::Translation(cubetrans[0], cubetrans[1], cubetrans[2]);
for (int i=0;i<3;i++) {
for(int j=0;j<3;j++)
abcm.M[i][j]=abc[i][j];
abcm.M[i][3]=0;
}
abcm.M[4][4]=1;
sc=Matrix4f::Scaling(supercell[0], supercell[1], supercell[2]);
sctrans=Matrix4f::Translation(-translations[p%ISOS][2],
-translations[p%ISOS][1], -translations[p%ISOS][0]);
matFinal = abcm*sctrans*sc*mvs;
} else {
matFinal=Matrix4f::Translation(translations[p%ISOS][0], translations[p%ISOS][1],
translations[p%ISOS][2]);
matFinal=Matrix4f::Scaling(scaling)*matFinal;
}
//end gvr
float t[16];
for (int i=0;i<4;i++)
for (int j=0;j<4;j++)
......@@ -295,7 +356,7 @@ void OvrApp::OneTimeShutdown()
bool OvrApp::OnKeyEvent( const int keyCode, const int repeatCount, const KeyEventType eventType )
{
animateTimesteps=!animateTimesteps;
eprintf("OnKeyEvent called!");
//eprintf("OnKeyEvent called! keycode=%d", keyCode);
return true;
/*if ( GuiSys->OnKeyEvent( keyCode, repeatCount, eventType ) )
{
......@@ -306,7 +367,7 @@ bool OvrApp::OnKeyEvent( const int keyCode, const int repeatCount, const KeyEven
Matrix4f OvrApp::Frame( const VrFrame & vrFrame )
{
LOG("Start Frame");
LOG("NOMADGearVRT Start Frame");
CenterEyeViewMatrix = vrapi_GetCenterEyeViewMatrix( &app->GetHeadModelParms(), &vrFrame.Tracking, NULL );
if (animateTimesteps) {
......@@ -316,7 +377,7 @@ Matrix4f OvrApp::Frame( const VrFrame & vrFrame )
currentSet++;
if (currentSet>TIMESTEPS-1)
currentSet=0;
LOG("currentSet updated, animate timesteps %d", currentSet);
LOG("NOMADGearVRT currentSet updated, animate timesteps %d", currentSet);
}
}
Matrix4f rot;
......@@ -359,7 +420,8 @@ void OvrApp::RenderIsos(const OVR::Matrix4f eyeViewProjection, int iso) {
GLenum e;
Matrix4f trans=Matrix4f::Translation(UserTranslation[0], UserTranslation[1], UserTranslation[2]);
//trans.translate(iPos).rotateX(-90).translate(UserPosition);
Matrix4f transform = eyeViewProjection*trans*Matrix4f::Scaling(0.2);
//rgh: prescaled on ply load
Matrix4f transform = eyeViewProjection*trans/**Matrix4f::Scaling(scaling)*/*Matrix4f::RotationX(-M_PI_2);
float t[16];
for (int i=0;i<4;i++)
for (int j=0;j<4;j++)
......@@ -367,7 +429,7 @@ void OvrApp::RenderIsos(const OVR::Matrix4f eyeViewProjection, int iso) {
glUseProgram(ISOP);
if ((e = glGetError()) != GL_NO_ERROR)
eprintf("1 Gl error RenderIsos timestep =%d: %d\n", currentSet, e);
glUniformMatrix4fv(ISOMatrixLoc, 1, GL_FALSE, t);
glUniformMatrix4fv(ISOMatrixLoc, 1, GL_FALSE, t);
if ((e = glGetError()) != GL_NO_ERROR)
eprintf("2 Gl error RenderIsos timestep =%d: %d\n", currentSet, e);
......@@ -380,13 +442,17 @@ glUniformMatrix4fv(ISOMatrixLoc, 1, GL_FALSE, t);
if ((e = glGetError()) != GL_NO_ERROR)
eprintf("4 Gl error RenderIsos timestep =%d: %d\n", currentSet, e);
} else {
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
glDepthMask(GL_FALSE);
for (int i=0;i<ISOS;i++) {
//rgh FIXME, redo this when we have the new rendering code for atom trajectories
glBindVertexArray(ISOVAO[currentSet*ISOS+i]);
glBindBuffer(GL_ARRAY_BUFFER, ISOBuffer[currentSet*ISOS+i]);
glBindBuffer(GL_ARRAY_BUFFER, ISOBuffer[currentSet*ISOS+i]);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ISOIndices[currentSet*ISOS+i]);
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glEnableVertexAttribArray(2);
glEnableVertexAttribArray(2);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 10*sizeof(float), (const void *)(0*sizeof(float)));
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 10*sizeof(float), (const void *)(3*sizeof(float)));
glVertexAttribPointer(2, 4, GL_FLOAT, GL_FALSE, 10*sizeof(float), (const void *)(6*sizeof(float)));
......@@ -397,7 +463,10 @@ glUniformMatrix4fv(ISOMatrixLoc, 1, GL_FALSE, t);
if ((e = glGetError()) != GL_NO_ERROR)
eprintf("6 Gl error RenderIsos timestep =%d: %d\n", currentSet, e);
}
glDisable(GL_BLEND);
glDepthMask(GL_TRUE);
}
glBindVertexArray(0);
}
......@@ -411,13 +480,15 @@ void OvrApp::RenderAtoms(const float *m) //m[16]
if (hasTess) {
//FIXME, unimplemented
LOG("FIXME, No Tess code for atoms yet!");
LOG("NOMADGearVRT FIXME, No Tess code for atoms yet!");
return;
} else { //no tess
glBindVertexArray(AtomVAO[0]);
glBindTexture(GL_TEXTURE_2D, textures[1]);
glUseProgram(AtomsP);
glUniformMatrix4fv(AtomMatrixLoc, 1, GL_FALSE, m);
glUniform1f(TotalatomsLoc, (float)getTotalAtomsInTexture());
if (currentSet==0) {
glDrawElements(GL_TRIANGLES, numAtoms[currentSet]* 3 * solid->nFaces,
#ifndef INDICESGL32
......@@ -463,21 +534,17 @@ if (!showTrajectories)
int e;
if (!AtomTVAO) {
LOG("RenderAtomTrajectoriesUnitCell, no atoms");
LOG("NOMADGearVRT RenderAtomTrajectoriesUnitCell, no atoms");
return;
}
glBindVertexArray(AtomTVAO[0]);
//glUseProgram(UnitCellP);
//glUniformMatrix4fv(m_nUnitCellMatrixLocation, 1, GL_FALSE, matrix);
float color[4]={1,0,0,1};
glUniform4fv(UnitCellColourLoc, 1, color);
glUniform4fv(UnitCellColourLoc, 1, atomtrajectorycolour);
if ((e = glGetError()) != GL_NO_ERROR)
eprintf("Gl error after glUniform4fv 2 RenderUnitCell: %d\n", e);
//glEnableVertexAttribArray(0);
//glDisableVertexAttribArray(1);
eprintf("Gl error after glUniform4fv 2 RenderAtomTrajectoriesUnitCell: %d\n", e);
//LOG("atomtrajectories.size()=%d", atomtrajectories.size());
//rgh FIXME, old code which does not work with large atom sets!
glBindBuffer(GL_ARRAY_BUFFER, AtomTBuffer[0]);
for (unsigned int i=0;i<atomtrajectories.size();i++) {
......@@ -505,7 +572,7 @@ void OvrApp::RenderUnitCell(const Matrix4f eyeViewProjection)
if (UnitCellVAO==0)
eprintf ("Error, Unit Cell VAO not loaded");
int e;
Matrix4f sc=Matrix4f::Scaling(scaling);
int p[3];
for (p[0]=0;p[0]<repetitions[0];(p[0])++)
for (p[1]=0;p[1]<repetitions[1];(p[1])++)
......@@ -513,58 +580,72 @@ void OvrApp::RenderUnitCell(const Matrix4f eyeViewProjection)
{
float delta[3];
GetDisplacement(p, delta);
Vector3f iPos(delta[0]+UserTranslation[0], delta[1]+UserTranslation[1], delta[2]+UserTranslation[2]);
//delta is in atom coordinates, need rotateX(-90)
Vector3f iPos(delta[0]+UserTranslation[0]/scaling, delta[2]+UserTranslation[1]/scaling,
-delta[1]+UserTranslation[2]/scaling);
Matrix4f trans=Matrix4f::Translation(iPos);
//trans.translate(iPos).rotateX(-90).translate(UserPosition);
Matrix4f transform = eyeViewProjection*trans;
Matrix4f transform = eyeViewProjection*sc*trans*Matrix4f::RotationX(-M_PI_2);
float t[16];
for (int i=0;i<4;i++)
for (int j=0;j<4;j++)
t[j*4+i]=transform.M[i][j];
glUseProgram(UnitCellP);
glUniformMatrix4fv(UnitCellMatrixLoc, 1, GL_FALSE, t);
if ((e = glGetError()) != GL_NO_ERROR)
if ((e = glGetError()) != GL_NO_ERROR)
eprintf("Gl error after glUniform4fv 1 RenderUnitCell: %d\n", e);
float color[4]={1,1,1,1};
glUniform4fv(UnitCellColourLoc, 1, color);
if ((e = glGetError()) != GL_NO_ERROR)
eprintf("Gl error after glUniform4fv 2 RenderUnitCell: %d\n", e);
glBindVertexArray(UnitCellVAO);
if ((e = glGetError()) != GL_NO_ERROR)
eprintf("Gl error after glBindVertexArray RenderUnitCell: %d\n", e);
glDrawElements(GL_LINES, 24, GL_UNSIGNED_INT, 0);
if ((e = glGetError()) != GL_NO_ERROR)
eprintf("Gl error after RenderUnitCell: %d\n", e);
if (displayunitcell) {
glUniform4fv(UnitCellColourLoc, 1, unitcellcolour);
if ((e = glGetError()) != GL_NO_ERROR)
eprintf("Gl error after glUniform4fv 2 RenderUnitCell: %d\n", e);
glBindVertexArray(UnitCellVAO);
if ((e = glGetError()) != GL_NO_ERROR)
eprintf("Gl error after glBindVertexArray RenderUnitCell: %d\n", e);