From 6d4d53ba5c7bbb7f9d43cc3badd5174e7d42bdde Mon Sep 17 00:00:00 2001
From: "Garcia-Hernandez, Ruben Jesus (rgarcia)" <garcia@lrz.de>
Date: Mon, 26 Mar 2018 16:58:29 +0200
Subject: [PATCH] Add marker support to Google Cardboard

---
 .../src/main/jni/treasure_hunt_renderer.cc    | 107 +++++++++++-----
 .../src/main/jni/treasure_hunt_renderer.h     |   4 +-
 NOMADVRLib/ConfigFile.h                       |   1 +
 NOMADVRLib/atomsGL.cpp                        | 119 ++++++++++++++----
 NOMADVRLib/atomsGL.h                          |   1 +
 5 files changed, 179 insertions(+), 53 deletions(-)

diff --git a/GoogleCardboardAndroid/NOMADgvrT/src/main/jni/treasure_hunt_renderer.cc b/GoogleCardboardAndroid/NOMADgvrT/src/main/jni/treasure_hunt_renderer.cc
index a4791da..bbf6327 100644
--- a/GoogleCardboardAndroid/NOMADgvrT/src/main/jni/treasure_hunt_renderer.cc
+++ b/GoogleCardboardAndroid/NOMADgvrT/src/main/jni/treasure_hunt_renderer.cc
@@ -522,6 +522,11 @@ glGenTextures(2+ZLAYERS, textDepthPeeling);
 		eprintf ("SetupUnitCell error %d", e);
 		error=-406;
 	}
+	e=SetupMarkerNoTess(&MarkerVAO, &MarkerVertBuffer, &MarkerIndexBuffer);
+	if (e!=GL_NO_ERROR) {
+		eprintf ("SetupMarkerNoTess error %d", e);
+		error=-411;
+	}
 
   // Because we are using 2X MSAA, we can render to half as many pixels and
   // achieve similar quality.
@@ -540,6 +545,9 @@ glGenTextures(2+ZLAYERS, textDepthPeeling);
   viewport_list_.reset(
       new gvr::BufferViewportList(gvr_api_->CreateEmptyBufferViewportList()));
 
+   if (ISOS || markers) {
+	PrepareISOShader(&ISOP, &ISOMatrixLoc);
+   }
 //isosurfaces
 	if (ISOS) {
 		currentIso=ISOS;
@@ -568,7 +576,6 @@ glGenTextures(2+ZLAYERS, textDepthPeeling);
 			error=-408;
 		}
 		SetupBlending(&BlendVAO, &BlendBuffer, &BlendIndices);
-		PrepareISOShader(&ISOP, &ISOMatrixLoc);
 
 		std::vector<float> vertices;
 #ifndef INDICESGL32
@@ -952,6 +959,42 @@ if (curDataPos!=ISOS) {
 glBindVertexArray(0);
 }
 
+void TreasureHuntRenderer::RenderMarker(const float *m) //m[16]
+{
+int e;
+if (!markers)
+	return;
+
+glEnable(GL_BLEND);
+glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+glBindVertexArray(MarkerVAO);
+if ((e = glGetError()) != GL_NO_ERROR)
+	eprintf("b %d", e);
+glUseProgram(ISOP);
+if ((e = glGetError()) != GL_NO_ERROR)
+	eprintf("c %d", e);
+glUniformMatrix4fv(ISOMatrixLoc, 1, GL_FALSE, m);
+if ((e = glGetError()) != GL_NO_ERROR)
+	eprintf("d %d, matrixloc=%d, program=%d", e, ISOMatrixLoc, ISOP); 
+glDrawElements(GL_TRIANGLES, 3*3*MARKERSOLID::nFaces, 
+#ifndef INDICESGL32				
+				GL_UNSIGNED_SHORT, (void*)(currentSet*sizeof(unsigned short)*3*3*MARKERSOLID::nFaces
+)
+#else
+				GL_UNSIGNED_INT, (void*)(currentSet*sizeof(unsigned int)*3*3*MARKERSOLID::nFaces
+)
+#endif
+	);
+if ((e = glGetError()) != GL_NO_ERROR)
+	eprintf("e %d", e);
+glBindVertexArray(0);
+if ((e = glGetError()) != GL_NO_ERROR)
+	eprintf("f %d", e);
+
+glDisable(GL_BLEND);
+}
+
+
 void TreasureHuntRenderer::RenderAtoms(const float *m) //m[16]
 {
 	//eprintf ("RenderAtoms start numatoms %d, timestep %d", numAtoms[currentSet], currentSet);
@@ -966,37 +1009,37 @@ void TreasureHuntRenderer::RenderAtoms(const float *m) //m[16]
 		return;
 	} else { //no tess
 		glBindVertexArray(AtomVAO[0]);
-	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, AtomIndices[0]);
-	if ((e = glGetError()) != GL_NO_ERROR)
-		eprintf("1 Gl error RenderAtom timestep =%d: %d\n", currentSet, e);
-	glBindBuffer(GL_ARRAY_BUFFER, AtomBuffer[0]);
-	if ((e = glGetError()) != GL_NO_ERROR)
-		eprintf("2 Gl error RenderAtom timestep =%d: %d\n", currentSet, e);
+		glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, AtomIndices[0]);
+		if ((e = glGetError()) != GL_NO_ERROR)
+			eprintf("1 Gl error RenderAtom timestep =%d: %d\n", currentSet, e);
+		glBindBuffer(GL_ARRAY_BUFFER, AtomBuffer[0]);
+		if ((e = glGetError()) != GL_NO_ERROR)
+			eprintf("2 Gl error RenderAtom timestep =%d: %d\n", currentSet, e);
 
-	glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 7*sizeof(float), (const void *)0);
-	if ((e = glGetError()) != GL_NO_ERROR)
-		eprintf("3 Gl error RenderAtom timestep =%d: %d\n", currentSet, e);
+		glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 7*sizeof(float), (const void *)0);
+		if ((e = glGetError()) != GL_NO_ERROR)
+			eprintf("3 Gl error RenderAtom timestep =%d: %d\n", currentSet, e);
 
-	glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 7 * sizeof(float), (const void *)(3*sizeof(float)));
-	if ((e = glGetError()) != GL_NO_ERROR)
-		eprintf("4 Gl error RenderAtom timestep =%d: %d\n", currentSet, e);
+		glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 7 * sizeof(float), (const void *)(3*sizeof(float)));
+		if ((e = glGetError()) != GL_NO_ERROR)
+			eprintf("4 Gl error RenderAtom timestep =%d: %d\n", currentSet, e);
 
-	glVertexAttribPointer(2, 1, GL_FLOAT, GL_FALSE, 7 * sizeof(float), (const void *)(6 * sizeof(float)));
-	if ((e = glGetError()) != GL_NO_ERROR)
-		eprintf("5 Gl error RenderAtom timestep =%d: %d\n", currentSet, e);
+		glVertexAttribPointer(2, 1, GL_FLOAT, GL_FALSE, 7 * sizeof(float), (const void *)(6 * sizeof(float)));
+		if ((e = glGetError()) != GL_NO_ERROR)
+			eprintf("5 Gl error RenderAtom timestep =%d: %d\n", currentSet, e);
 
 		glBindTexture(GL_TEXTURE_2D, textures[1]);
-	if ((e = glGetError()) != GL_NO_ERROR)
-		eprintf("6 Gl error RenderAtom timestep =%d: %d\n", currentSet, e);
+		if ((e = glGetError()) != GL_NO_ERROR)
+			eprintf("6 Gl error RenderAtom timestep =%d: %d\n", currentSet, e);
 
 		glUseProgram(AtomsP);
 		glUniform1f(totalatomsLocation, (float)getTotalAtomsInTexture());
-	if ((e = glGetError()) != GL_NO_ERROR)
-		eprintf("7 Gl error RenderAtom timestep =%d: %d\n", currentSet, e);
+		if ((e = glGetError()) != GL_NO_ERROR)
+			eprintf("7 Gl error RenderAtom timestep =%d: %d\n", currentSet, e);
 
 		glUniformMatrix4fv(AtomMatrixLoc, 1, GL_FALSE, m);
-	if ((e = glGetError()) != GL_NO_ERROR)
-		eprintf("8 Gl error RenderAtom timestep =%d: %d\n", currentSet, e);
+		if ((e = glGetError()) != GL_NO_ERROR)
+			eprintf("8 Gl error RenderAtom timestep =%d: %d\n", currentSet, e);
 
 		if (currentSet==0) {
 			glDrawElements(GL_TRIANGLES, numAtoms[currentSet]* 3 * solid->nFaces, 
@@ -1006,8 +1049,8 @@ void TreasureHuntRenderer::RenderAtoms(const float *m) //m[16]
 				GL_UNSIGNED_INT,
 #endif	
 				0);
-	if ((e = glGetError()) != GL_NO_ERROR)
-		eprintf("9 Gl error RenderAtom timestep =%d: %d\n", currentSet, e);
+		if ((e = glGetError()) != GL_NO_ERROR)
+			eprintf("9 Gl error RenderAtom timestep =%d: %d\n", currentSet, e);
 
 		} else {
 			glDrawElements(GL_TRIANGLES, (numAtoms[currentSet]-numAtoms[currentSet-1]) * 3 * solid->nFaces,
@@ -1017,8 +1060,8 @@ void TreasureHuntRenderer::RenderAtoms(const float *m) //m[16]
 				GL_UNSIGNED_INT, (void*)(numAtoms[currentSet-1]*sizeof(unsigned int)*3*solid->nFaces)
 #endif
 				);
-	if ((e = glGetError()) != GL_NO_ERROR)
-		eprintf("10 Gl error RenderAtom timestep =%d: %d\n", currentSet, e);
+			if ((e = glGetError()) != GL_NO_ERROR)
+				eprintf("10 Gl error RenderAtom timestep =%d: %d\n", currentSet, e);
 
 		}
 		if ((e = glGetError()) != GL_NO_ERROR)
@@ -1028,12 +1071,12 @@ void TreasureHuntRenderer::RenderAtoms(const float *m) //m[16]
 			glBindVertexArray(AtomVAO[1]);
 			glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, AtomIndices[1]);
 			glBindBuffer(GL_ARRAY_BUFFER, AtomBuffer[1]);
-	glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 7*sizeof(float), (const void *)0);
-	glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 7 * sizeof(float), (const void *)(3*sizeof(float)));
-	glVertexAttribPointer(2, 1, GL_FLOAT, GL_FALSE, 7 * sizeof(float), (const void *)(6 * sizeof(float)));
+			glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 7*sizeof(float), (const void *)0);
+			glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 7 * sizeof(float), (const void *)(3*sizeof(float)));
+			glVertexAttribPointer(2, 1, GL_FLOAT, GL_FALSE, 7 * sizeof(float), (const void *)(6 * sizeof(float)));
 
-	if ((e = glGetError()) != GL_NO_ERROR)
-		eprintf("5 Gl error RenderAtom timestep =%d: %d\n", currentSet, e);
+			if ((e = glGetError()) != GL_NO_ERROR)
+				eprintf("5 Gl error RenderAtom timestep =%d: %d\n", currentSet, e);
 			glDrawElements(GL_TRIANGLES, numClonedAtoms* 3 * solid->nFaces, 
 #ifndef INDICESGL32				
 				GL_UNSIGNED_SHORT,
@@ -1072,6 +1115,7 @@ if ((e = glGetError()) != GL_NO_ERROR)
 	eprintf("Gl error after glUniform4fv 1 RenderAtomTrajectories: %d\n", e);
 RenderAtomTrajectoriesUnitCell();
 RenderAtoms(t);
+RenderMarker(t);
 }
 
 void TreasureHuntRenderer::RenderAtomTrajectoriesUnitCell()
@@ -1192,6 +1236,7 @@ gvr::Mat4f transform = MatrixMul(eyeViewProjection, MatrixMul(sc, MatrixMul(tran
 					//atom trajectories
 					RenderAtomTrajectoriesUnitCell();
 					RenderAtoms(t);
+					RenderMarker(t);
 				}
 }
 
diff --git a/GoogleCardboardAndroid/NOMADgvrT/src/main/jni/treasure_hunt_renderer.h b/GoogleCardboardAndroid/NOMADgvrT/src/main/jni/treasure_hunt_renderer.h
index beef782..9b1d272 100644
--- a/GoogleCardboardAndroid/NOMADgvrT/src/main/jni/treasure_hunt_renderer.h
+++ b/GoogleCardboardAndroid/NOMADgvrT/src/main/jni/treasure_hunt_renderer.h
@@ -162,7 +162,8 @@ GLuint peelingFramebuffer;
 	//if no tesselation is available, we still need the tess atoms for the trajectories!
 	GLuint *AtomTVAO=nullptr, *AtomTBuffer=nullptr, *AtomVAO=nullptr, *AtomBuffer=nullptr, *AtomIndices=nullptr,//[2], atoms, extraatoms
 		BondIndices,
-		UnitCellVAO, UnitCellBuffer, UnitCellIndexBuffer;
+		UnitCellVAO, UnitCellBuffer, UnitCellIndexBuffer,
+		MarkerVAO, MarkerVertBuffer, MarkerIndexBuffer;
 GLuint			AtomsP, UnitCellP; // framework does not provide support for tesselation and provides many things we don't need.
 	GLint		AtomMatrixLoc, UnitCellMatrixLoc, UnitCellColourLoc, totalatomsLocation;
 GLuint	TransP=0, BlendP=0;
@@ -182,6 +183,7 @@ bool animateMovement=false;
 int currentIso;
 
 void RenderAtoms(const float *m);
+void RenderMarker(const float *m);
 void RenderUnitCell(const gvr::Mat4f eyeViewProjection);
 void RenderAtomTrajectoriesUnitCell();
 void RenderAtomTrajectories(const gvr::Mat4f eyeViewProjection);
diff --git a/NOMADVRLib/ConfigFile.h b/NOMADVRLib/ConfigFile.h
index ec4ac4a..9de0d03 100644
--- a/NOMADVRLib/ConfigFile.h
+++ b/NOMADVRLib/ConfigFile.h
@@ -76,6 +76,7 @@ extern float movementspeed;  //how fast to move the user
 //markers such as hole positions and electron positions
 extern float ** markers;
 extern float ** markercolours;
+#define MARKERSOLID Octahedron
 
 extern const char * loadConfigFileErrors[];
 
diff --git a/NOMADVRLib/atomsGL.cpp b/NOMADVRLib/atomsGL.cpp
index bb3ba53..642d0c1 100644
--- a/NOMADVRLib/atomsGL.cpp
+++ b/NOMADVRLib/atomsGL.cpp
@@ -81,7 +81,6 @@ GLenum SetupAtomsNoTess (GLuint **AtomVAO /*[4]*/, GLuint **AtomVertBuffer/*[3]*
 	//atoms, cloned atoms
 	//rgh: FIXME: add AtomVAO[2] for atom trajectories
 {
-	//eprintf ("SetupAtomsNoTess 1");
 if (!numAtoms)
 		return 0;
 
@@ -90,15 +89,12 @@ if (!solid) {
 	return 0;
 }
 
-//eprintf ("SetupAtomsNoTess 2");
-	//for now, render an icosahedron
 	//http://prideout.net/blog/?p=48 //public domain code
-	//xyz nxnynz u=atom type ; 7 floats
+	//xyz nxnynz u=atom type ; 7 floats; u only used for colour
 	int e;
 
 	int totalatoms=numAtoms[getAtomTimesteps() -1];
 	
-//eprintf ("SetupAtomsNoTess 2");
 	*AtomVAO = new GLuint[4]; //atoms, cloned atoms, unused (bonds use Tess atom positions), trajectories
 	*AtomIndexBuffer= new GLuint[3];//atoms, cloned atoms, bonds
 	*AtomVertBuffer = new GLuint[3];//atoms, cloned atoms, trajectories
@@ -106,25 +102,19 @@ if (!solid) {
 	glGenVertexArrays(4, *AtomVAO);
 	glGenBuffers(2, *AtomIndexBuffer);
 	glGenBuffers(3, *AtomVertBuffer);
-//eprintf ("SetupAtomsNoTess 3");
 	glBindVertexArray((*AtomVAO)[0]);
 	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, (*AtomIndexBuffer)[0]);
 	glBindBuffer(GL_ARRAY_BUFFER, (*AtomVertBuffer)[0]);
-//eprintf ("SetupAtomsNoTess 4");
 	glEnableVertexAttribArray(0);
 	glEnableVertexAttribArray(1);
 	glEnableVertexAttribArray(2);
 	glDisableVertexAttribArray(3);
-	//eprintf ("SetupAtomsNoTess 5, totalatoms=%d, nVerts=%d", totalatoms, solid->nVerts);
 	float *tmp = new float[solid->nVerts * 7 * totalatoms];
-	//eprintf ("SetupAtomsNoTess 6");
 #ifdef INDICESGL32		
 	int *tmpi = new int[solid->nFaces*3 * totalatoms];
-	//eprintf ("SetupAtomsNoTess 7");
 	int *currenti=tmpi;
 #else
 	unsigned short *tmpi = new unsigned short[solid->nFaces*3 * totalatoms];
-	//eprintf ("SetupAtomsNoTess 7B");
 	unsigned short *currenti=tmpi;
 #endif
 
@@ -168,8 +158,6 @@ if (!solid) {
 	if (glGetError() != GL_NO_ERROR)
 		eprintf("opengl error attrib pointer 0\n");
 
-	//glBindVertexArray(0);
-	//glDisableVertexAttribArray(0);
 	delete[] tmp;
 	delete[] tmpi;
 	if ((e = glGetError()) != GL_NO_ERROR)
@@ -178,17 +166,13 @@ if (!solid) {
 	//FIXME TODO: cloned atoms
 	tmp = new float[solid->nVerts * 7 * numClonedAtoms];
 	current=tmp;
-	//eprintf ("SetupAtomsNoTess 6");
 #ifdef INDICESGL32		
 	tmpi = new int[solid->nFaces*3 * numClonedAtoms];
-	//eprintf ("SetupAtomsNoTess 7");
 	currenti=tmpi;
 #else
 	tmpi = new unsigned short[solid->nFaces*3 * numClonedAtoms];
-	//eprintf ("SetupAtomsNoTess 7B");
 	currenti=tmpi;
 #endif
-	//eprintf ("Before For 2");
 
 	for (int a = 0; a < numClonedAtoms; a++) {
 		const int atomNumber = static_cast<int>(clonedAtoms[0][4 * a + 3]);
@@ -206,9 +190,6 @@ if (!solid) {
 			*currenti++ = solid->Faces[i] + a*solid->nVerts;
 	} //a
 	
-	//eprintf ("After For 2");
-
-
 	glBindVertexArray((*AtomVAO)[1]);
 	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, (*AtomIndexBuffer)[1]);
 	glBindBuffer(GL_ARRAY_BUFFER, (*AtomVertBuffer)[1]);
@@ -525,8 +506,104 @@ GLenum SetupInfoCube (GLuint *VAO, GLuint *VertBuffer, GLuint *IndexBuffer)
 	return glGetError();
 }
 
-GLenum SetupMarker(GLuint *MarkerVAO, GLuint *MarkerVertBuffer)
+float getMarkerLobeScaling(int l, int k)
 {
+	if (l == k)
+		return 2.0f;
+	return 0.5f;
+}
+
+GLenum SetupMarkerNoTess(GLuint *MarkerVAO, GLuint *MarkerVertBuffer, GLuint *MarkerIndexBuffer)
+{
+	if (!markers)
+		return glGetError();
+
+	GLenum e;
+	if ((e = glGetError()) != GL_NO_ERROR)
+		eprintf("opengl error %d, begin of SetupMarkerNoTess\n", e, __LINE__);
+
+	glGenVertexArrays(1, MarkerVAO);
+	glGenBuffers(1, MarkerVertBuffer);
+	glGenBuffers(1, MarkerIndexBuffer);
+
+	glBindVertexArray(*MarkerVAO);
+	glBindBuffer(GL_ARRAY_BUFFER, *MarkerVertBuffer);
+	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, *MarkerIndexBuffer);
+
+	glEnableVertexAttribArray(0);
+	glEnableVertexAttribArray(1);
+	glEnableVertexAttribArray(2);
+	glDisableVertexAttribArray(3);
+
+	glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 10 * sizeof(float), (const void *)0);
+	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)));
+
+	float *tmp = new float[10 * MARKERSOLID::nVerts*3* TIMESTEPS]; //xyz, nxnynz, rgba; compatible with IsoShaders
+	float *current = tmp;
+	for (int i = 0; i < TIMESTEPS; i++) {
+		for (int l = 0; l < 3; l++) {//3 ellipsoids
+			for (int j = 0; j < MARKERSOLID::nVerts; j++) {
+				for (int k = 0; k < 3; k++) { //pos
+					float s = getMarkerLobeScaling(l, k);
+					*current++ = s*MARKERSOLID::Verts[j * 3 + k] * markerscaling * atomScaling/* * atomRadius(0)*/ +
+						markers[i][k];
+				}
+				float length=0;
+				for (int k = 0; k < 3; k++) { //normal; normalized in IsoShader
+					float s = getMarkerLobeScaling(l, k);
+					*current = MARKERSOLID::Verts[j * 3 + k]*s;
+					length += (*current)*(*current);
+					current++;
+				}
+				length=1.0f / sqrtf(length);
+				for (int k=0;k<3;k++) {
+					*(current-1-k)*=length;
+				}
+				for (int k = 0; k < 4; k++) { //colour
+					*current++ = markercolours[i][k];
+				}
+			}
+		}
+	}
+	glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 10 * MARKERSOLID::nVerts * 3 * TIMESTEPS, tmp,
+		GL_STATIC_DRAW);
+
+	delete[] tmp;
+#ifdef INDICESGL32		
+	int *tmpi=new int[TIMESTEPS * 3 * Icosahedron::nFaces * 3];
+	int * currenti;
+#else
+	short *tmpi = new short[TIMESTEPS * 3 * Icosahedron::nFaces * 3];
+	short *currenti;
+#endif
+
+	currenti = tmpi;
+	for (int i = 0; i < TIMESTEPS; i++) {
+		for (int l = 0; l < 3; l++) {//ellipsoids
+			for (int j = 0; j < MARKERSOLID::nFaces; j++) {
+				for (int k = 0; k < 3; k++) {
+					*currenti++ = MARKERSOLID::Faces[j * 3 + k] + 
+						MARKERSOLID::nVerts * (l+3*i);
+				}
+			}
+		}
+	}
+
+	glBufferData(GL_ELEMENT_ARRAY_BUFFER,
+#ifdef INDICESGL32		
+		sizeof(int)*MARKERSOLID::nFaces * 3 * TIMESTEPS * 3
+#else
+		sizeof(unsigned int)*MARKERSOLID::nFaces * 3 * TIMESTEPS * 3
+#endif
+		, tmpi, GL_STATIC_DRAW);
+	delete[] tmpi;
+	glBindVertexArray(0);
+	return e;
+}
+
+GLenum SetupMarker(GLuint *MarkerVAO, GLuint *MarkerVertBuffer)
+{//requires tesselation
 	if (!markers)
 		return glGetError();
 	GLenum e;
diff --git a/NOMADVRLib/atomsGL.h b/NOMADVRLib/atomsGL.h
index 09cab91..6c610af 100644
--- a/NOMADVRLib/atomsGL.h
+++ b/NOMADVRLib/atomsGL.h
@@ -31,6 +31,7 @@ GLenum SetupAtoms(GLuint **AtomVAO, GLuint **AtomVertBuffer, GLuint *BondIndices
 GLenum SetupAtomsNoTess (GLuint **AtomVAO, GLuint **AtomVertBuffer, GLuint **AtomIndexBuffer);
 GLenum SetupUnitCell(GLuint *UnitCellVAO, GLuint *UnitCellVertBuffer, GLuint *UnitCellIndexBuffer);
 GLenum SetupMarker(GLuint *MarkerVAO, GLuint *MarkerVertBuffer);
+GLenum SetupMarkerNoTess(GLuint *MarkerVAO, GLuint *MarkerVertBuffer, GLuint *MarkerIndexBuffer);
 GLenum SetupInfoCube (GLuint *VAO, GLuint *VertBuffer, GLuint *IndexBuffer);
 
 bool PrepareUnitCellAtomShader (GLuint *AtomP, GLuint *cellP, GLuint *MarkerP, 
-- 
GitLab