I have another thread that explains more clearly what I am trying to accomplish. Unfortunately I don’t seem to be able to delete threads. Ignore this please
I strongly advise to implement this variant first. It may be not as “efficient” as possible, but it is simple, easy to extend, and can be used as a reference later.
What you are looking for is called “instancing”. (for example, see http://www.opengl-tutorial.org/intermediate-tutorials/billboards-particles/particles-instancing/)
In your case, you’d have a base mesh of 4 vertices and 6 indices. Each tile of your height map would match one instance, with glVertexAttribDivisor() used to advance in your vertex coordinate array by 4 with each iteration.
There are other options too - instanced render functions are pretty flexible (and can be very confusing). I can also think of scenarios where this data can be reduced even further, e.g. to four height values per tile (one per vertex), with the actual X/Y/Z coordinates computed in a vertex shader.
You may find eventually that all this work isn’t actually worth the effort, as I found that instanced rendering in OpenGL can be even slower than using a brute-force approach with redundant data in your vertex buffers, especially if instances have very little geometry like in your case.
Why not just calculating the texture coordinates in a shader based on world position and use a repeating texture?