Part of the Khronos Group
OpenGL.org

The Industry's Foundation for High Performance Graphics

from games to virtual reality, mobile phones to supercomputers

Page 2 of 3 FirstFirst 123 LastLast
Results 11 to 20 of 30

Thread: Using textures instead of points in a map OpenGl-ES 2.0

  1. #11
    Member Regular Contributor
    Join Date
    Jun 2013
    Posts
    491
    Quote Originally Posted by Hank Finley View Post
    and when I pass the shader the mPointSize buffer, is that correct?
    Code :
    // Pass in the texture coordinate information
    mPointSize.position(0);
    GLES20.glVertexAttribPointer(mPointSizeHandle, mVec2DataSize, GLES20.GL_FLOAT, false, 0, mPointSize); //Error code gets sent back after this line.
    GLES20.glEnableVertexAttribArray(mPointSizeHandle);
    Is the point size a uniform or an attribute? The last posted version of the GLSL code has it as a uniform, but the application is treating it as an attribute. If it is an attribute, then it needs to be specified per-vertex.

  2. #12
    Intern Newbie
    Join Date
    Aug 2013
    Posts
    39
    ok I see what you mean, I'll keep it as uniform as you implied in your solution, so I have altered:
    Code :
    mPointSizeHandle = GLES20.glGetUniformLocation(mPointsProgramHandle, "u_pointSize");

    Not quite sure how to pass the buffer through however.

    I tried:
    Code :
    GLES20.glUniform2fv(mPointSizeHandle, 1, mPointSize);

    Looking a little strange however:
    Click image for larger version. 

Name:	device-2013-08-28-215218.jpg 
Views:	105 
Size:	3.8 KB 
ID:	1133
    Last edited by Hank Finley; 08-28-2013 at 04:53 AM.

  3. #13
    Intern Newbie
    Join Date
    Aug 2013
    Posts
    39
    Hi GClements, could you show me an example of how the u_pointsize vec2 variable should be set.

    Explaining further, I have this FloatBuffer mPointSize that I'll pass to the shader program for u_pointsize. You said:
    u_pointSize is a vec2 in normalised device coordinates; the value should be the size in pixels divided by the viewport size in pixels.
    What I'm asking is, how to populate mPointSize? I realize that you have explained that above but I still cannot figure this out.
    Last edited by Hank Finley; 08-29-2013 at 07:31 AM.

  4. #14
    Member Regular Contributor
    Join Date
    Jun 2013
    Posts
    491
    Quote Originally Posted by Hank Finley View Post
    Hi GClements, could you show me an example of how the u_pointsize vec2 variable should be set.
    I'm not familiar with the Java-specific buffer stuff, but:
    Code :
    GLES20.glUniform2f(mPointSizeHandle, 10.0/width, 10.0/height);
    should produce points 10 pixels in diameter (width and height should be the screen dimensions in pixels).

    It's not clear whether your image is the result of a small number of really large points or just too many points.

    Also, are the texture coordinates correct? They should be (0,0), (0,1), (1,0) and (1,1); if they're too large, the points will be enlarged as well.

  5. #15
    Intern Newbie
    Join Date
    Aug 2013
    Posts
    39
    Trying to simplify everything down so I can figure out the issue.

    I have one point with the six vertice positions that I am passing through as follows:
    Code :
    float[] singlePointPositionData = {
        -0.010406494f, -0.22647285f, 0.0f,
        -0.010406494f, -0.22647285f, 0.0f,
        -0.010406494f, -0.22647285f, 0.0f,
        -0.010406494f, -0.22647285f, 0.0f,
        -0.010406494f, -0.22647285f, 0.0f,
        -0.010406494f, -0.22647285f, 0.0f
    };

    Code :
    float[] squareTextureCoordinateData = {
        0.0f, 0.0f, 				
        0.0f, 1.0f,
        1.0f, 0.0f,
        0.0f, 1.0f,
        1.0f, 1.0f,
        1.0f, 0.0f
    };

    Using this now:
    Code :
    GLES20.glUniform2f(mPointSizeHandle, 10.0f/480f, 10.0f/762f); //Values are the size of my veiwport in pixels

    At present it displays with a stretched triangle (it should once everything is in order, display with the points position coordinates above, within the red box):
    Click image for larger version. 

Name:	device-2013-08-30-160213.jpg 
Views:	110 
Size:	11.6 KB 
ID:	1134

  6. #16
    Member Regular Contributor
    Join Date
    Jun 2013
    Posts
    491
    Quote Originally Posted by Hank Finley View Post
    At present it displays with a stretched triangle
    That's strange. The vertex shader offsets each point by a fixed multiple of "a_TexCoordinate - vec2(0.5,0.5)", so the vertices should at least be centred around the correct point regardless of the size.

    All I can suggest is to:

    1. Experiment with changing individual numbers to see how that affects the final result. That may provide enough clues to track down the source of the problem.
    2. Post more complete code: the draw call, anything which sets the state (uniforms and attributes) used by the draw call, anything which assigns to variables used in the code, etc (use pastebin if it exceeds the size limits of the forum). Currently, the code is split into many fragments across multiple posts, some of which will have since changed.

  7. #17
    Intern Newbie
    Join Date
    Aug 2013
    Posts
    39
    1. I found an issue with my position buffer, which once fixed it rendered the first square. This did not render the texture just produced a black square. Which is fine for now I would rather work on getting the individual squares rendering correctly first.

    2. I added in another 6 vertices for a second square, since the first is displaying.

    3.This is what it displays:
    (Notice on the left the first point is rendered, the red squares are just me rendering another set of all six points as primitive points just to show where they should be)
    Click image for larger version. 

Name:	device-2013-08-31-172357b.jpg 
Views:	97 
Size:	12.8 KB 
ID:	1138

    4. Could it be the stride or offset between triangles that I have wrong? I tried altering them to see what happens but haven't really made much progress except a few program crashes.

    5. Code:
    Code :
    final float[] squareTextureCoordinateData =
    {
    		// Front face
    		0.0f, 0.0f, 				
    		0.0f, 1.0f,
    		1.0f, 0.0f,
    		0.0f, 1.0f,
    		1.0f, 1.0f,
    		1.0f, 0.0f
    };

    Code :
    final float[] singlePointData =
    	{
    		-0.010406494f, -0.22647285f, 0.0f,
    		-0.010406494f, -0.22647285f, 0.0f,
    		-0.010406494f, -0.22647285f, 0.0f,
    		-0.010406494f, -0.22647285f, 0.0f,
    		-0.010406494f, -0.22647285f, 0.0f,
    		-0.010406494f, -0.22647285f, 0.0f,
     
    		-0.0031433105f, -0.22737312f, 0.0f,
    		-0.0031433105f, -0.22737312f, 0.0f,
    		-0.0031433105f, -0.22737312f, 0.0f,
    		-0.0031433105f, -0.22737312f, 0.0f,
    		-0.0031433105f, -0.22737312f, 0.0f,
    		-0.0031433105f, -0.22737312f, 0.0f
    	};

    Code :
    private void drawTexturedPoint(final FloatBuffer geometryBuffer)
    {
    	GLES20.glUseProgram(mPointsProgramHandle);
     
        mPointSizeHandle = GLES20.glGetUniformLocation(mPointsProgramHandle, "u_pointSize");
        mPointMVPMatrixHandle = GLES20.glGetUniformLocation(mPointsProgramHandle, "u_MVPMatrix");
    	mTextureUniformHandle = GLES20.glGetUniformLocation(mPointsProgramHandle, "u_Texture");
    	mPointPositionHandle = GLES20.glGetAttribLocation(mPointsProgramHandle, "a_Position");
        mTextureCoordinateHandle = GLES20.glGetAttribLocation(mPointsProgramHandle, "a_TexCoordinate");
     
        // Set the active texture unit to texture unit 0.
        GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
        // Bind the texture to this unit.
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextureDataHandle);
        // Tell the texture uniform sampler to use this texture in the shader by binding to texture unit 0.
        GLES20.glUniform1i(mTextureUniformHandle, 0);
     
        GLES20.glUniform2f(mPointSizeHandle, 10.0f/480f, 10.0f/762f);
     
    	// Pass in the position information
    	geometryBuffer.position(0);
        GLES20.glVertexAttribPointer(mPointPositionHandle, 3, GLES20.GL_FLOAT, false, (3*4), geometryBuffer);
     
        GLES20.glEnableVertexAttribArray(mPointPositionHandle);
     
        // Pass in the texture coordinate information
        mSquareTextureCoordinates.position(0);
        GLES20.glVertexAttribPointer(mTextureCoordinateHandle, 2, GLES20.GL_FLOAT, false, 0, mSquareTextureCoordinates);
        GLES20.glEnableVertexAttribArray(mTextureCoordinateHandle);
     
        GLES20.glUniformMatrix4fv(mPointMVPMatrixHandle, 1, false, mMVPMatrix, 0);
     
        // Draw the cube.
        GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, geometryBuffer.capacity()/3);
    }

    6. All the renderer code
    Code :
    public class vboCustomGLRenderer  implements GLSurfaceView.Renderer {
     
    	private final Context mActivityContext;
     
    	/**
    	 * Store the model matrix. This matrix is used to move models from object space (where each model can be thought
    	 * of being located at the center of the universe) to world space.
    	 */
    	private float[] mModelMatrix = new float[16];
     
    	/**
    	 * Store the view matrix. This can be thought of as our camera. This matrix transforms world space to eye space;
    	 * it positions things relative to our eye.
    	 */
    	private float[] mViewMatrix = new float[16];
     
    	/** Store the projection matrix. This is used to project the scene onto a 2D viewport. */
    	private float[] mProjectionMatrix = new float[16];
     
    	/** Allocate storage for the final combined matrix. This will be passed into the shader program. */
    	private float[] mMVPMatrix = new float[16];
     
    	/** This will be used to pass in the transformation matrix. */
    	private int mMVPMatrixHandle;
     
    	/** This will be used to pass in model position information. */
    	private int mLinePositionHandle;
     
    	/** This will be used to pass in model color information. */
    	private int mLineColorUniformLocation;
     
    	/** This will be used to pass in model position information. */
    	private int mPointPositionHandle;
     
    	/** How many bytes per float. */
    	private final int mBytesPerFloat = 4;	
     
    	/** Offset of the position data. */
    	private final int mPositionOffset = 0;
     
    	/** Size of the position data in elements. */
    	private final int mPositionDataSize = 3;
     
    	/** How many elements per vertex for double values. */
    	private final int mPositionFloatStrideBytes = mPositionDataSize * mBytesPerFloat;
     
    	/** This is a handle to our per-vertex line shading program. */
    	private int mLinesProgramHandle;
     
    	/** This is a handle to our points program. */
    	private int mPointsProgramHandle;
     
    	private FloatBuffer mPointSize;
     
    	/** Store our model data in a float buffer. */
    	private final FloatBuffer mSquareTextureCoordinates;
     
    	/** This will be used to pass in model texture coordinate information. */
    	private int mTextureCoordinateHandle;
     
    	/** Size of the texture coordinate data in elements. */
    	private final int mVec2DataSize = 2;
     
    	/** This will be used to pass in the texture. */
    	private int mTextureUniformHandle;
     
    	/** This is a handle to our texture data. */
    	private int mTextureDataHandle;
     
    	private int mPointSizeHandle;
    	private int mPointMVPMatrixHandle;
     
        public double eyeX = 0;
        public double eyeY = 0;
        public float eyeZ = 1.5f;
     
    	// We are looking toward the distance
        public double lookX = eyeX;
        public double lookY = eyeY;
        public float lookZ = 0.0f;
     
    	// Set our up vector. This is where our head would be pointing were we holding the camera.
        public float upX = 0.0f;
        public float upY = 1.0f;
        public float upZ = 0.0f;
     
        public double modelOffsetX = -(default_settings.mbrMinX + ((default_settings.mbrMaxX - default_settings.mbrMinX)/2));
        public double modelOffsetY = -(default_settings.mbrMinY + ((default_settings.mbrMaxY - default_settings.mbrMinY)/2));
     
        public double mScaleFactor = 1;
        public double modelXShift = 0;
        public double modelYShift = 0;
        public double viewXShift = 0;
        public double viewYShift = 0;
     
    	static float mWidth = 0;
    	static float mHeight = 0;
    	static double mLeft = 0;
    	static double mRight = 0;
    	static double mTop = 0;
    	static double mBottom = 0;
    	double mRatio = 0;
    	double screen_width_height_ratio;
    	double screen_height_width_ratio;
    	final float near = 1.5f;
    	final float far = 10.0f;
     
    	double screen_vs_map_horz_ratio = 0;
    	double screen_vs_map_vert_ratio = 0;
     
        FloatBuffer tempPoint;
     
    	public vboCustomGLRenderer(final Context activityContext) {
    		mActivityContext = activityContext;
     
    		final float[] squareTextureCoordinateData =
    		{
    				// Front face
    				0.0f, 0.0f, 				
    				0.0f, 1.0f,
    				1.0f, 0.0f,
    				0.0f, 1.0f,
    				1.0f, 1.0f,
    				1.0f, 0.0f
    		};
    		mSquareTextureCoordinates = ByteBuffer.allocateDirect(squareTextureCoordinateData.length * mBytesPerFloat)
    		.order(ByteOrder.nativeOrder()).asFloatBuffer();
    		mSquareTextureCoordinates.put(squareTextureCoordinateData).position(0);
     
    		final float[] singlePointData =
    			{
    				-0.010406494f, -0.22647285f, 0.0f,
    				-0.010406494f, -0.22647285f, 0.0f,
    				-0.010406494f, -0.22647285f, 0.0f,
    				-0.010406494f, -0.22647285f, 0.0f,
    				-0.010406494f, -0.22647285f, 0.0f,
    				-0.010406494f, -0.22647285f, 0.0f,
     
    				-0.0031433105f, -0.22737312f, 0.0f,
    				-0.0031433105f, -0.22737312f, 0.0f,
    				-0.0031433105f, -0.22737312f, 0.0f,
    				-0.0031433105f, -0.22737312f, 0.0f,
    				-0.0031433105f, -0.22737312f, 0.0f,
    				-0.0031433105f, -0.22737312f, 0.0f
    			};
     
    		/*
    		Coordinates for all six points
    		-0.010406494, -0.22647285, 0.0
    		-0.0031433105, -0.22737312, 0.0
    		0.0064849854, -0.22831154, 0.0
    		0.009414673, -0.23442268, 0.0
    		0.009063721, -0.23643303, 0.0
    		0.008743286, -0.23848152, 0.0
    		*/
     
    		tempPoint = ByteBuffer.allocateDirect(singlePointData.length * mBytesPerFloat)
    		.order(ByteOrder.nativeOrder()).asFloatBuffer();
    		tempPoint.put(singlePointData).position(0);
    	}
     
    	boolean loadComplete = false;
     
    	public void setDraw(boolean loadComplete){
    		this.loadComplete = loadComplete;
    	}
     
    	public void setEye(double x, double y){
     
        	eyeX -= (x / screen_vs_map_horz_ratio);
        	lookX = eyeX;
        	eyeY += (y / screen_vs_map_vert_ratio);
        	lookY = eyeY;
     
        	// Set the camera position (View matrix)
    		Matrix.setLookAtM(mViewMatrix, 0, (float)eyeX, (float)eyeY, eyeZ, (float)lookX, (float)lookY, lookZ, upX, upY, upZ);
    	}
     
    	public void setScaleFactor(float scaleFactor, float gdx, float gdy){
     
            // Don't let the object get too small or too large.
            //mScaleFactor = Math.max(0.1f, Math.min(mScaleFactor, 10000.0f));
     
    		mScaleFactor *= scaleFactor;
     
        	mRight = mRight / scaleFactor;
        	mLeft = -mRight;
        	mTop = mTop / scaleFactor;
        	mBottom = -mTop;
     
        	//The eye shift is in pixels will get converted to screen ratio when sent to setEye().
        	double eyeXShift = (((mWidth  / 2) - gdx) - (((mWidth  / 2) - gdx) / scaleFactor));
        	double eyeYShift = (((mHeight / 2) - gdy) - (((mHeight / 2) - gdy) / scaleFactor));
     
        	screen_vs_map_horz_ratio = (mWidth/(mRight-mLeft));
        	screen_vs_map_vert_ratio = (mHeight/(mTop-mBottom));
     
        	eyeX -= (eyeXShift / screen_vs_map_horz_ratio);
        	lookX = eyeX;
        	eyeY += (eyeYShift / screen_vs_map_vert_ratio);
        	lookY = eyeY;
     
    		Matrix.frustumM(mProjectionMatrix, 0, (float)mLeft, (float)mRight, (float)mBottom, (float)mTop, near, far);
     
    		float psize = 25f/480f;
    		mPointSize.position(0);
    		mPointSize.put(psize);
    		mPointSize.put(psize);
    		mPointSize.flip();
    	}
     
    	protected String getLineVertexShader()
    	{
    		// TO DO: Explain why we normalize the vectors, explain some of the vector math behind it all. Explain what is eye space.
    		final String lineVertexShader =
    				"uniform mat4 u_MVPMatrix;      \n"		// A constant representing the combined model/view/projection matrix.
     
    				  + "attribute vec4 a_Position;     \n"		// Per-vertex position information we will pass in.
    				  + "attribute vec4 a_Color;        \n"		// Per-vertex color information we will pass in.			  
     
    				  + "varying vec4 v_Color;          \n"		// This will be passed into the fragment shader.
     
    				  + "void main()                    \n"		// The entry point for our vertex shader.
    				  + "{                              \n"
    				  + "   v_Color = a_Color;          \n"		// Pass the color through to the fragment shader. 
    				  											// It will be interpolated across the triangle.
    				  + "   gl_Position = u_MVPMatrix   \n" 	// gl_Position is a special variable used to store the final position.
    				  + "               * a_Position;   \n"     // Multiply the vertex by the matrix to get the final point in
    				  + "   gl_PointSize = 15.0;         \n" 			                                            			 
    				  + "}                              \n";    // normalized screen coordinates.
     
    		return lineVertexShader;
    	}
     
    	protected String getLineFragmentShader()
    	{
    		final String lineFragmentShader =
    			"precision mediump float;       \n"		// Set the default precision to medium. We don't need as high of a 
    			+ "uniform vec4 u_Color;          \n"		// This is the color from the vertex shader interpolated across the 
    									// triangle per fragment.			  
    			+ "void main()                    \n"		// The entry point for our fragment shader.
    			+ "{                              \n"
    			+ "   gl_FragColor = u_Color;     \n"		// Pass the color directly through the pipeline.		  
    			+ "}                              \n";
    		return lineFragmentShader;
    	}
     
    	protected String getPointVertexShader()
    	{
    		// Define a simple shader program for our points.
    		final String pointVertexShader =
    		"uniform mat4 u_MVPMatrix;						\n"		
    		+ "uniform vec2 u_pointSize;						\n"		
    		+ "attribute vec4 a_Position;						\n"
    		+ "attribute vec2 a_TexCoordinate;					\n"		// Per-vertex texture coordinate information we will pass in.			  
     
    		+ "varying vec2 v_TexCoordinate;					\n"		// This will be passed into the fragment shader.
     
    		+ "void main()                  					\n"
    		+ "{                            					\n"
    		+ "   v_TexCoordinate = a_TexCoordinate;			\n"		// Pass through the texture coordinate.
    		+ "   gl_Position = u_MVPMatrix * a_Position;		\n"		// gl_Position is a special variable used to store the final position.
    		+ "   gl_Position += vec4(gl_Position.w * u_pointSize * (a_TexCoordinate - vec2(0.5,0.5)), 0, 0);\n"
    		+ "}                              					\n";
    		return pointVertexShader;
    	}
     
    	protected String getPointFragmentShader()
    	{
    		final String pointFragmentShader = 
    		      "precision mediump float;		\n"		// Set the default precision to medium. We don't need as high of a precision in the fragment shader.
    			+ "uniform sampler2D u_Texture;	\n"		// The input texture.
     
    			+ "varying vec2 v_TexCoordinate;\n"		// Interpolated texture coordinate per fragment.
     
    			+ "void main()					\n"		// The entry point for our fragment shader.
    			+ "{							\n"
    			+ "   gl_FragColor = (texture2D(u_Texture, v_TexCoordinate));\n"		// Pass the color directly through the pipeline.		  
    			+ "}							\n";
    		return pointFragmentShader;
    	}
     
    	/** 
    	 * Helper function to compile a shader.
    	 * 
    	 * @param shaderType The shader type.
    	 * @param shaderSource The shader source code.
    	 * @return An OpenGL handle to the shader.
    	 */
    	private int compileShader(String shader, final int shaderType, final String shaderSource) 
    	{
    		int shaderHandle = GLES20.glCreateShader(shaderType);
     
    		if (shaderHandle != 0) 
    		{
    			// Pass in the shader source.
    			GLES20.glShaderSource(shaderHandle, shaderSource);
     
    			// Compile the shader.
    			GLES20.glCompileShader(shaderHandle);
     
    			// Get the compilation status.
    			final int[] compileStatus = new int[1];
    			GLES20.glGetShaderiv(shaderHandle, GLES20.GL_COMPILE_STATUS, compileStatus, 0);
     
    			// If the compilation failed, delete the shader.
    			if (compileStatus[0] == 0) 
    			{
    				Log.e("vboCustomGLRenderer: compileShader", "Error compiling shader: " + shader + " " + GLES20.glGetShaderInfoLog(shaderHandle));
    				GLES20.glDeleteShader(shaderHandle);
    				shaderHandle = 0;
    			}
    		}
     
    		if (shaderHandle == 0)
    		{			
    			throw new RuntimeException("Error creating shader." );
    		}
    		return shaderHandle;
    	}
     
    	/**
    	 * Helper function to compile and link a program.
    	 * 
    	 * @param vertexShaderHandle An OpenGL handle to an already-compiled vertex shader.
    	 * @param fragmentShaderHandle An OpenGL handle to an already-compiled fragment shader.
    	 * @param attributes Attributes that need to be bound to the program.
    	 * @return An OpenGL handle to the program.
    	 */
    	private int createAndLinkProgram(final int vertexShaderHandle, final int fragmentShaderHandle, final String[] attributes) 
    	{
    		int programHandle = GLES20.glCreateProgram();
     
    		if (programHandle != 0) 
    		{
    			// Bind the vertex shader to the program.
    			GLES20.glAttachShader(programHandle, vertexShaderHandle);			
     
    			// Bind the fragment shader to the program.
    			GLES20.glAttachShader(programHandle, fragmentShaderHandle);
     
    			// Bind attributes
    			if (attributes != null)
    			{
    				final int size = attributes.length;
    				for (int i = 0; i < size; i++)
    				{
    					GLES20.glBindAttribLocation(programHandle, i, attributes[i]);
    				}						
    			}
     
    			// Link the two shaders together into a program.
    			GLES20.glLinkProgram(programHandle);
     
    			// Get the link status.
    			final int[] linkStatus = new int[1];
    			GLES20.glGetProgramiv(programHandle, GLES20.GL_LINK_STATUS, linkStatus, 0);
     
    			// If the link failed, delete the program.
    			if (linkStatus[0] == 0) 
    			{				
    				Log.e("vboCustomGLRenderer: createAndLinkProgram", "Error compiling program: " + GLES20.glGetProgramInfoLog(programHandle));
    				GLES20.glDeleteProgram(programHandle);
    				programHandle = 0;
    			}
    		}
     
    		if (programHandle == 0)
    		{
    			throw new RuntimeException("Error creating program.");
    		}
     
    		return programHandle;
    	}
     
    	public static int loadTexture(final Context context, final int resourceId)
    	{
    		final int[] textureHandle = new int[1];
     
    		GLES20.glGenTextures(1, textureHandle, 0);
     
    		if (textureHandle[0] != 0)
    		{
    			final BitmapFactory.Options options = new BitmapFactory.Options();
    			options.inScaled = false;	// No pre-scaling
     
    			// Read in the resource
    			final Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(), resourceId, options);
     
    			// Bind to the texture in OpenGL
    			GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureHandle[0]);
     
    			// Set filtering
    			GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST);
    			GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_NEAREST);
     
    			// Load the bitmap into the bound texture.
    			GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);
     
    			// Recycle the bitmap, since its data has been loaded into OpenGL.
    			bitmap.recycle();						
    		}
     
    		if (textureHandle[0] == 0)
    		{
    			throw new RuntimeException("Error loading texture.");
    		}
     
    		return textureHandle[0];
    	}	
     
        @Override
        public void onSurfaceCreated(GL10 unused, EGLConfig config) {
     
            // Set the background frame color
        	//White
            GLES20.glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
     
            // Set the view matrix. This matrix can be said to represent the camera position.
    		// NOTE: In OpenGL 1, a ModelView matrix is used, which is a combination of a model and
    		// view matrix. In OpenGL 2, we can keep track of these matrices separately if we choose.
            Matrix.setLookAtM(mViewMatrix, 0, (float)eyeX, (float)eyeY, eyeZ, (float)lookX, (float)lookY, lookZ, upX, upY, upZ);
     
            //Load the line shaders
    		final String lineVertexShader = getLineVertexShader();
            final String lineFragmentShader = getLineFragmentShader();	
     
    		final int lineVertexShaderHandle = compileShader("lineVertexShader", GLES20.GL_VERTEX_SHADER, lineVertexShader);
            final int lineFragmentShaderHandle = compileShader("lineFragmentShader", GLES20.GL_FRAGMENT_SHADER, lineFragmentShader);
     
    		mLinesProgramHandle = createAndLinkProgram(lineVertexShaderHandle, lineFragmentShaderHandle, new String[] {"a_Position", "a_Color"});
     
            //Load the point(square texture) shaders
    		final String pointsVertexShader = getPointVertexShader();  
            final String pointsFragmentShader = getPointFragmentShader();	
     
    		final int pointVertexShaderHandle = compileShader("pointsVertexShader", GLES20.GL_VERTEX_SHADER, pointsVertexShader);	
            final int pointFragmentShaderHandle = compileShader("pointsFragmentShader", GLES20.GL_FRAGMENT_SHADER, pointsFragmentShader);
     
    		mPointsProgramHandle = createAndLinkProgram(pointVertexShaderHandle, pointFragmentShaderHandle, new String[] {"u_pointSize", "a_Position", "a_TexCoordinate"});
     
     
            // Load the texture
            mTextureDataHandle = loadTexture(mActivityContext, com.ANDRRA1.R.drawable.andrra_point);
        }
     
        @Override
        public void onSurfaceChanged(GL10 unused, int width, int height) {
     
        	// Adjust the viewport based on geometry changes,
            // such as screen rotation
    		// Set the OpenGL viewport to the same size as the surface.
            GLES20.glViewport(0, 0, width, height);
        	//Log.d("","onSurfaceChanged");
     
    		screen_width_height_ratio = (double) width / height;
    		screen_height_width_ratio = (double) height / width;
     
    		//Initialize
    		if (mRatio == 0){
    			mWidth = (float) width;
    			mHeight = (float) height;
     
    			//map height to width ratio
    			double map_extents_width = default_settings.mbrMaxX - default_settings.mbrMinX;
    			double map_extents_height = default_settings.mbrMaxY - default_settings.mbrMinY;
    			double map_width_height_ratio = map_extents_width/map_extents_height;
    			//float map_height_width_ratio = map_extents_height/map_extents_width;
    			if (screen_width_height_ratio > map_width_height_ratio){
    				mRight = (screen_width_height_ratio * map_extents_height)/2;
    				mLeft = -mRight;
    				mTop = map_extents_height/2;
    				mBottom = -mTop;
    			}
    			else{
    				mRight = map_extents_width/2;
    				mLeft = -mRight;
    				mTop = (screen_height_width_ratio * map_extents_width)/2;
    				mBottom = -mTop;
    			}
     
    			mRatio = screen_width_height_ratio;
    		}
     
    		if (screen_width_height_ratio != mRatio){
    			final double wRatio = width/mWidth;
    			final double oldWidth = mRight - mLeft;
    			final double newWidth = wRatio * oldWidth;
    			final double widthDiff = (newWidth - oldWidth)/2;
    			mLeft = mLeft - widthDiff;
    			mRight = mRight + widthDiff;
     
    			final double hRatio = height/mHeight;
    			final double oldHeight = mTop - mBottom;
    			final double newHeight = hRatio * oldHeight;
    			final double heightDiff = (newHeight - oldHeight)/2;
    			mBottom = mBottom - heightDiff;
    			mTop = mTop + heightDiff;
     
    			mWidth = (float) width;
    			mHeight = (float) height;
     
    			mRatio = screen_width_height_ratio;
    		}
     
        	screen_vs_map_horz_ratio = (mWidth/(mRight-mLeft));
        	screen_vs_map_vert_ratio = (mHeight/(mTop-mBottom));
     
    		Matrix.frustumM(mProjectionMatrix, 0, (float)mLeft, (float)mRight, (float)mBottom, (float)mTop, near, far);
            checkGLError("onSurfaceChanged");
        }
     
        ListIterator<mapLayer> orgNonAssetCatLayersList_it;
        ListIterator<FloatBuffer> mapLayerObjectList_it;
        ListIterator<Byte> mapLayerObjectTypeList_it;
        mapLayer MapLayer;
     
        @Override
        public void onDrawFrame(GL10 unused) {
     
    		GLES20.glClear(GLES20.GL_DEPTH_BUFFER_BIT | GLES20.GL_COLOR_BUFFER_BIT);
     
    	    if (loadComplete){
    	    	preset();
    			orgNonAssetCatLayersList_it = default_settings.orgNonAssetCatMappableLayers.listIterator();
    			while (orgNonAssetCatLayersList_it.hasNext()) {
    				MapLayer = orgNonAssetCatLayersList_it.next();
     
    				if (MapLayer.BatchedPolygonVBO != null){
    					drawPolygon(MapLayer.BatchedPolygonVBO);
    				}
    			}
    			//Draws all points from a seperate buffer as primitive points.
    	    	drawPoint(default_settings.orgAssetCatNDRRALayer.BatchedPointVBO);
    	    	//Draws the first two squares. Defined amd initialized in constructor.
    			drawTexturedPoint(tempPoint);
    		    checkGLError("onDrawFrame");
        	}
        }
     
    	private void preset()
    	{
    		Matrix.setIdentityM(mModelMatrix, 0);
     
    		// This multiplies the view matrix by the model matrix, and stores the result in the MVP matrix
            // (which currently contains model * view).
            Matrix.multiplyMM(mMVPMatrix, 0, mViewMatrix, 0, mModelMatrix, 0);
     
            // This multiplies the modelview matrix by the projection matrix, and stores the result in the MVP matrix
            // (which now contains model * view * projection).
            Matrix.multiplyMM(mMVPMatrix, 0, mProjectionMatrix, 0, mMVPMatrix, 0);
    	}
     
    	private void drawPolygon(final FloatBuffer geometryBuffer)
    	{
    		final float[] colorArray = {0f,0f,0f};
     
    		GLES20.glUseProgram(mLinesProgramHandle);
     
            mMVPMatrixHandle = GLES20.glGetUniformLocation(mLinesProgramHandle, "u_MVPMatrix");
            mLinePositionHandle = GLES20.glGetAttribLocation(mLinesProgramHandle, "a_Position");
            mLineColorUniformLocation = GLES20.glGetUniformLocation(mLinesProgramHandle, "u_Color");
     
            GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mMVPMatrix, 0);
     
    		// Pass in the position information
    		geometryBuffer.position(mPositionOffset);
            GLES20.glVertexAttribPointer(mLinePositionHandle, mPositionDataSize, GLES20.GL_FLOAT, false, mPositionFloatStrideBytes, geometryBuffer);
     
            GLES20.glEnableVertexAttribArray(mLinePositionHandle);
     
            GLES20.glUniform4f(mLineColorUniformLocation, colorArray[0], colorArray[1], colorArray[2], 1f);
     
            GLES20.glLineWidth(1.0f);
            GLES20.glDrawArrays(GLES20.GL_LINES, 0, geometryBuffer.capacity()/mPositionDataSize);
    	}
     
    	private void drawPoint(final FloatBuffer geometryBuffer)
    	{
    		final float[] colorArray = {1f,0f,0f};
     
    		GLES20.glUseProgram(mLinesProgramHandle);
     
            mMVPMatrixHandle = GLES20.glGetUniformLocation(mLinesProgramHandle, "u_MVPMatrix");
            mLinePositionHandle = GLES20.glGetAttribLocation(mLinesProgramHandle, "a_Position");
            mLineColorUniformLocation = GLES20.glGetUniformLocation(mLinesProgramHandle, "u_Color");
     
            GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mMVPMatrix, 0);
     
    		// Pass in the position information
    		geometryBuffer.position(mPositionOffset);
            GLES20.glVertexAttribPointer(mLinePositionHandle, mPositionDataSize, GLES20.GL_FLOAT, false, mPositionFloatStrideBytes, geometryBuffer);
     
            GLES20.glEnableVertexAttribArray(mLinePositionHandle);
     
            GLES20.glUniform4f(mLineColorUniformLocation, colorArray[0], colorArray[1], colorArray[2], 1f);
     
            GLES20.glDrawArrays(GLES20.GL_POINTS, 0, geometryBuffer.capacity()/mPositionDataSize);
    	}
     
    	/**
    	 * Draws a textured square, representing a point.
    	 */
    	private void drawTexturedPoint(final FloatBuffer geometryBuffer)
    	{
    		GLES20.glUseProgram(mPointsProgramHandle);
     
            mPointSizeHandle = GLES20.glGetUniformLocation(mPointsProgramHandle, "u_pointSize");
            mPointMVPMatrixHandle = GLES20.glGetUniformLocation(mPointsProgramHandle, "u_MVPMatrix");
    		mTextureUniformHandle = GLES20.glGetUniformLocation(mPointsProgramHandle, "u_Texture");
    		mPointPositionHandle = GLES20.glGetAttribLocation(mPointsProgramHandle, "a_Position");
            mTextureCoordinateHandle = GLES20.glGetAttribLocation(mPointsProgramHandle, "a_TexCoordinate");
     
            // Set the active texture unit to texture unit 0.
            GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
            // Bind the texture to this unit.
            GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextureDataHandle);
            // Tell the texture uniform sampler to use this texture in the shader by binding to texture unit 0.
            GLES20.glUniform1i(mTextureUniformHandle, 0);
     
            GLES20.glUniform2f(mPointSizeHandle, 15.0f/480f, 15.0f/762f);
     
    		// Pass in the position information
    		geometryBuffer.position(0);
            GLES20.glVertexAttribPointer(mPointPositionHandle, 3, GLES20.GL_FLOAT, false, (3*4), geometryBuffer);
     
            GLES20.glEnableVertexAttribArray(mPointPositionHandle);
     
            // Pass in the texture coordinate information
            mSquareTextureCoordinates.position(0);
            GLES20.glVertexAttribPointer(mTextureCoordinateHandle, 2, GLES20.GL_FLOAT, false, 0, mSquareTextureCoordinates);
            GLES20.glEnableVertexAttribArray(mTextureCoordinateHandle);
     
            GLES20.glUniformMatrix4fv(mPointMVPMatrixHandle, 1, false, mMVPMatrix, 0);
     
            // Draw the cube.
            GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, geometryBuffer.capacity()/3);
    	}
     
    	private void checkGLError(String op) {
    	    int error;
    	    String errorType = "";
     
    	    while ((error = GLES20.glGetError()) != GLES20.GL_NO_ERROR) {
     
                switch (error) {
    	            case GLES20.GL_INVALID_ENUM:		//1280
    	            	errorType = "GL_INVALID_ENUM";
    	            break;
    	            case GLES20.GL_INVALID_VALUE:		//1281
    	            	errorType = "GL_INVALID_VALUE";
    	            break;
    	            case GLES20.GL_INVALID_OPERATION:	//1292
    	            	errorType = "GL_INVALID_OPERATION";
    	            break;
    	            case 1283:							//1283
    	            	errorType = "GL_STACK_OVERFLOW";
    	            break;
    	            case 1284:							//1284
    	            	errorType = "GL_STACK_UNDERFLOW";
    	            break;
    	            case GLES20.GL_OUT_OF_MEMORY:		//1285
    	            	errorType = "GL_OUT_OF_MEMORY";
    	            break;
    	            case GLES20.GL_INVALID_FRAMEBUFFER_OPERATION:		//1286
    	            	errorType = "GL_INVALID_FRAMEBUFFER_OPERATION";
    	            break;
    				default:
    					errorType = "Unknown GL Error Type";
                }
    	        Log.e("ANDRRA|" + GLES20.GL_NO_ERROR + "|", op + ": OpenGL Error: " + error + " -" + errorType);
    	    }
    	}
    }
    Last edited by Hank Finley; 08-31-2013 at 01:03 AM.

  8. #18
    Member Regular Contributor
    Join Date
    Jun 2013
    Posts
    491
    You appear to have 12 sets of vertex coordinates, and telling glDrawArrays to draw that many vertices, but the texture coordinate array only has 6 sets of texture coordinates. All of the attribute arrays must have enough data for all of the vertices (i.e. for 4 triangles, you need 12 sets of texture coordinates).

  9. #19
    Intern Newbie
    Join Date
    Aug 2013
    Posts
    39
    I'm not really sure how it works but is there a way to apply the one set of texture coordinates to each position set? Seems a bit of waste to duplicate the same texture data over and over. I could possibly have 15000 of these. Does the declaration of 'uniform' in the shader do this?

    Other than the above question, I have gone forward and created the full texture coordinates for all squares and they are almost there:
    Click image for larger version. 

Name:	device-2013-09-01-170339.jpg 
Views:	100 
Size:	12.7 KB 
ID:	1142

    So the actual andrra_point.png image is not actually rendering as you can see from the black squares. It is loaded in onSurfaceCreated() as follows:
    Can you see if I have missed anything, I have included everything that has anything to do with the texture.

    Code :
    public void onSurfaceCreated(GL10 unused, EGLConfig config) {
        //... other code
     
        //Load the point(square texture) shaders
        final String pointsVertexShader = getPointVertexShader();  
        final String pointsFragmentShader = getPointFragmentShader();	
     
        final int pointVertexShaderHandle = compileShader("pointsVertexShader", GLES20.GL_VERTEX_SHADER, pointsVertexShader);	
        final int pointFragmentShaderHandle = compileShader("pointsFragmentShader", GLES20.GL_FRAGMENT_SHADER, pointsFragmentShader);
     
        mPointsProgramHandle = createAndLinkProgram(pointVertexShaderHandle, pointFragmentShaderHandle, new String[] {"u_pointSize", "a_Position", "a_TexCoordinate"});
     
        // Load the texture
        mTextureDataHandle = loadTexture(mActivityContext, com.ANDRRA1.R.drawable.andrra_point);
    }

    Above mTextureDataHandle gets an int assigned to it from loadTexture()

    Code :
    public int loadTexture(final Context context, final int resourceId)
    {
    	final int[] textureHandle = new int[1];
     
    	GLES20.glGenTextures(1, textureHandle, 0);
     
    	if (textureHandle[0] != 0)
    	{
    		final BitmapFactory.Options options = new BitmapFactory.Options();
    		options.inScaled = false;	// No pre-scaling
     
    		// Read in the resource
    		final Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(), resourceId, options);
     
    		// Bind to the texture in OpenGL
    		GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureHandle[0]);
     
    		// Set filtering
    		GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST);
    		GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_NEAREST);
     
    		// Load the bitmap into the bound texture.
    		GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);
     
    		// Recycle the bitmap, since its data has been loaded into OpenGL.
    		bitmap.recycle();
    	}
     
    	if (textureHandle[0] == 0)
    	{
    		throw new RuntimeException("Error loading texture.");
    	}
     
    	return textureHandle[0];
    }

    Code :
    protected String getPointVertexShader()
    {
    	// Define a simple shader program for our points.
    	final String pointVertexShader =
    	"uniform mat4 u_MVPMatrix;						\n"		
    	+ "uniform vec2 u_pointSize;						\n"		
    	+ "attribute vec4 a_Position;						\n"
            + "attribute vec2 a_TexCoordinate;					\n"		// Per-vertex texture coordinate information we will pass in.			  
     
    	+ "varying vec2 v_TexCoordinate;					\n"		// This will be passed into the fragment shader.
     
    	+ "void main()                  					\n"
    	+ "{                            					\n"
    	+ "   v_TexCoordinate = a_TexCoordinate;			\n"		// Pass through the texture coordinate.
    	+ "   gl_Position = u_MVPMatrix * a_Position;		\n"		// gl_Position is a special variable used to store the final position.
    	+ "   gl_Position += vec4(gl_Position.w * u_pointSize * (a_TexCoordinate - vec2(0.5,0.5)), 0, 0);\n"
    	+ "}                              					\n";
    	return pointVertexShader;
    }

    Code :
    protected String getPointFragmentShader()
    {
    	final String pointFragmentShader = 
    	      "precision mediump float;		\n"		// Set the default precision to medium. We don't need as high of a precision in the fragment shader.
    		+ "uniform sampler2D u_Texture;	\n"		// The input texture.
     
    		+ "varying vec2 v_TexCoordinate;\n"		// Interpolated texture coordinate per fragment.
     
    		+ "void main()					\n"		// The entry point for our fragment shader.
    		+ "{							\n"
    		+ "   gl_FragColor = (texture2D(u_Texture, v_TexCoordinate));\n"		// Pass the color directly through the pipeline.		  
    		+ "}							\n";
    	return pointFragmentShader;
    }

    Code :
    private void drawTexturedPoint(final FloatBuffer geometryBuffer, final FloatBuffer textureBuffer)
    {
        GLES20.glUseProgram(mPointsProgramHandle);
     
        mPointSizeHandle = GLES20.glGetUniformLocation(mPointsProgramHandle, "u_pointSize");
        mPointMVPMatrixHandle = GLES20.glGetUniformLocation(mPointsProgramHandle, "u_MVPMatrix");
        mTextureUniformHandle = GLES20.glGetUniformLocation(mPointsProgramHandle, "u_Texture");                   
        mPointPositionHandle = GLES20.glGetAttribLocation(mPointsProgramHandle, "a_Position");
        mTextureCoordinateHandle = GLES20.glGetAttribLocation(mPointsProgramHandle, "a_TexCoordinate");
     
        // Set the active texture unit to texture unit 0.
        GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
        // Bind the texture to this unit.
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextureDataHandle);
        // Tell the texture uniform sampler to use this texture in the shader by binding to texture unit 0.
        GLES20.glUniform1i(mTextureUniformHandle, 0);
     
        GLES20.glUniformMatrix4fv(mPointMVPMatrixHandle, 1, false, mMVPMatrix, 0);
     
        GLES20.glUniform2f(mPointSizeHandle, mPointSize/mWidth, mPointSize/mHeight);
     
        // Pass in the position information
        geometryBuffer.position(0);
        GLES20.glVertexAttribPointer(mPointPositionHandle, mPositionDataSize, GLES20.GL_FLOAT, false, mPositionFloatStrideBytes, geometryBuffer);
        GLES20.glEnableVertexAttribArray(mPointPositionHandle);
     
        // Pass in the texture coordinate information
        textureBuffer.position(0);
        GLES20.glVertexAttribPointer(mTextureCoordinateHandle, mVec2DataSize, GLES20.GL_FLOAT, false, 0, textureBuffer);
        GLES20.glEnableVertexAttribArray(mTextureCoordinateHandle);
     
        // Draw the cube.
        GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, geometryBuffer.capacity()/mPositionDataSize);
    }
    Last edited by Hank Finley; 09-01-2013 at 05:39 AM.

  10. #20
    Member Regular Contributor
    Join Date
    Jun 2013
    Posts
    491
    Quote Originally Posted by Hank Finley View Post
    I'm not really sure how it works but is there a way to apply the one set of texture coordinates to each position set?
    Desktop OpenGL can do this using instanced rendering, but OpenGL ES doesn't have that (at least, not as part of the core API, although the GL_NV_draw_instanced extension provides the basic features of instanced rendering, so you might want to check whether that is available on the target platforms).

    Quote Originally Posted by Hank Finley View Post
    Seems a bit of waste to duplicate the same texture data over and over. I could possibly have 15000 of these.
    Check whether you can use GL_POINTS. That only requires one set of vertex coordinates per point and no texture coordinates. IOW, 3 floats per point rather than 30 floats per point with glDrawArrays() or 20 floats per point with glDrawElements().

    Quote Originally Posted by Hank Finley View Post
    Does the declaration of 'uniform' in the shader do this?
    "uniform" means that the value is constant throughout the draw call, i.e. the same for all vertices of all primitives.

    Quote Originally Posted by Hank Finley View Post
    Other than the above question, I have gone forward and created the full texture coordinates for all squares and they are almost there:

    So the actual andrra_point.png image is not actually rendering as you can see from the black squares. It is loaded in onSurfaceCreated() as follows:
    Can you see if I have missed anything, I have included everything that has anything to do with the texture.
    Assuming that the texture has an alpha channel, you need to enable blending, e.g.
    Code :
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    glEnable(GL_BLEND)
    or:
    Code :
    glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
    glEnable(GL_BLEND)
    The latter should be used if the texture data has pre-multiplied alpha, the former if not.

    If the texture contains only an alpha channel, then the colour should be specified as a uniform which is copied to gl_FragColor.rgb and the .r component of the texture used for gl_FragColor.a.

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •