I want to create mesh class with VBO in C++.
The class looks like following:
mesh::mesh(std::vector<Vector3d>* Vertices, std::vector<unsigned int>* Indices, std::vector<Vector2d>* TextureCoords) {
if(Vertices) this->vertices = *Vertices;
if(Indices) this->indices = *Indices;
if(TextureCoords) this->textureCoords = *TextureCoords;
chatbox.AddMessageToQueue("vertices.size() : %d", vertices.size());
glGenBuffers(1, &VBO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, vertices.size()*sizeof(Vector3d) + textureCoords.size()*sizeof(Vector2d), 0, GL_STATIC_DRAW);
glBufferSubData(GL_ARRAY_BUFFER, 0, vertices.size()*sizeof(Vector3d), vertices.data());
glBufferSubData(GL_ARRAY_BUFFER, vertices.size()*sizeof(Vector3d), textureCoords.size()*sizeof(Vector2d), textureCoords.data());
glGenBuffers(1, &IND);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IND);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size()*sizeof(unsigned int), &indices[0], GL_STATIC_DRAW);
}
void mesh::draw() {
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glVertexPointer(3, GL_FLOAT, 0, (void*)0);
glTexCoordPointer(2, GL_FLOAT, 0, (void*)(sizeof(float)*3*6));
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IND);
glDrawElements(GL_TRIANGLES, indices.size(), GL_UNSIGNED_INT, (unsigned int*)0 + 0);
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
}
The problem is in the texture coordinates only. I'm trying to create the mesh like so:
std::vector<unsigned int> indices;
std::vector<mesh::Vector3d> vertices;
std::vector<mesh::Vector2d> texCoords;
vertices.push_back({PosX, PosY, 1.0});
vertices.push_back({PosX + SizeX, PosY, 1.0});
vertices.push_back({PosX + SizeX, PosY + SizeY, 1.0});
vertices.push_back({PosX, PosY + SizeY, 1.0});
indices.push_back(0);
indices.push_back(1);
indices.push_back(2);
indices.push_back(0);
indices.push_back(2);
indices.push_back(3);
texCoords.push_back({0, 1});
texCoords.push_back({1, 0});
texCoords.push_back({0, 0});
texCoords.push_back({0, 1});
texCoords.push_back({1, 1});
texCoords.push_back({1, 0});
gui_checkbox = new mesh(&vertices, &indices, &texCoords);
But the result is wrong, as you can see in the left picture below (the picture on the right is the desired one):
The vertices are in ortho mode, so the coordinate origin for vertices is in top left corner and for texture coordinates the origin is in the bottom left just like in OpenGL.
When one is using indices to address the vertex positions, the texture coordinates also get indexed. In your case this means, that you are only using the first four entries in texCoords. The strange looking comes from texCoords[0] == texCoords[3].
The correct texCoords would most probably be
texCoords.push_back({0, 1});
texCoords.push_back({1, 1});
texCoords.push_back({1, 0});
texCoords.push_back({0, 0});
These can be derived from the vertex-coordinates: texCoords should have the same value at a component whenever their corresponding vertices have the same component value. e.g. if vertices[0].y == vertices[1].y => texCoords[0].y == texCoords[1].y and so on. In addition, the texCoords y coordinates have to be flipped, since vertex origin as on top-left while texcoords start at bottom left.
Edit:
glTexCoordPointer(2, GL_FLOAT, 0, (void*)(sizeof(float)*3*6));
does not look correct to me. This statement tells that the first texture coordinate starts after the sixth vector3, but shouldn't they start after the fourth one? (You only have 4 entries in vertices):
glTexCoordPointer(2, GL_FLOAT, 0, (void*)(sizeof(float)*3*4));
Related
actually Im a bit confused about using glBufferSubData and glMapBuffer. In my program I'm loading a mesh of Triangles so i created a Struct of Vertex and initialized my VertexBuffer with the data of whole mesh. I implemented ray-casting and ray-triangle intersection. What im trying to do is, if my cursor intersects with the mesh, the intersected triangle changes his color as long its get intersected. Its working at the moment but when I try to load a bigger mesh with 50.000+ Vertices it doesnt work anymore. I am updating my whole VBO with glBufferData because I dont understand how I can update only Color of Triangles with glBufferSubData. Can someone explain me how I can update only the specific part (e.g. Color) of my VBO ?
struct Vertex
{
glm::vec3 Pos;
glm::vec3 Normal;
glm::vec3 Color;
};
VertexBuffer(void* vertices, size_t size)
{
glGenVertexArrays(1, &VAO);
glBindVertexArray(VAO);
glGenBuffers(1, &buffer);
glBindBuffer(GL_ARRAY_BUFFER, buffer);
glBufferData(GL_ARRAY_BUFFER, size, vertices, GL_DYNAMIC_DRAW);
glBindVertexArray(0);
}
void Render()
{
glBindVertexArray(vertexBuffer->VAO);
glUseProgram(Fill->program);
glUniformMatrix4fv(glGetUniformLocation(Fill->program, "model"), 1, GL_FALSE, glm::value_ptr(model));
glUniformMatrix4fv(glGetUniformLocation(Fill->program, "view"), 1, GL_FALSE, glm::value_ptr(view));
glUniformMatrix4fv(glGetUniformLocation(Fill->program, "projection"), 1, GL_FALSE, glm::value_ptr(proj));
for (int j = 0; j < numVertices; j += 3){
if (intersectPlane(this->Vertices[j], this->Vertices[j + 1], this->Vertices[j + 2], ray, orig)){
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer->buffer);
this->Vertices[j].Color = glm::vec3(1.0, 0.0, 0.0);
this->Vertices[j + 1].Color = glm::vec3(1.0, 0.0, 0.0);
this->Vertices[j + 2].Color = glm::vec3(1.0, 0.0, 0.0);
glBufferData(GL_ARRAY_BUFFER, numVertices * sizeof(Vertex), Vertices, GL_DYNAMIC_DRAW);
}
else{
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer->buffer);
this->Vertices[j].Color = glm::vec3(0.695f, 0.695f, 0.695f);
this->Vertices[j + 1].Color = glm::vec3(0.695f, 0.695f, 0.695f);
this->Vertices[j + 2].Color = glm::vec3(0.695f, 0.695f, 0.695f);
glBufferData(GL_ARRAY_BUFFER, numVertices * sizeof(Vertex), Vertices, GL_DYNAMIC_DRAW);
}
}
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer->buffer);
GLuint posLoc = glGetAttribLocation(Fill->program, "Position");
GLuint norm = glGetAttribLocation(Fill->program, "Normal");
GLuint colo = glGetAttribLocation(Fill->program, "Color");
glVertexAttribPointer(posLoc, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*)offsetof(Vertex, Pos));
glVertexAttribPointer(norm, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*)offsetof(Vertex, Normal));
glVertexAttribPointer(colo, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*)offsetof(Vertex, Color));
glEnableVertexAttribArray(posLoc);
glEnableVertexAttribArray(norm);
glEnableVertexAttribArray(colo);
glDrawArrays(GL_TRIANGLES, 0, numVertices);
glBindVertexArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glUseProgram(0);
}
glBufferSubData updates part (or the whole) of the buffer without the need to recreate it.
In your case you can do some calculus to know the position in bytes inside the buffer (so called "offset") of the edge currently selected, and update the buffer just for that pair of vertices.
glMapBuffer gives you a (virtual) pointer to the buffer. You can read or write to that address directly using your C/C++ functions. Be aware to "unmap" when done.
Now, your buffer layout is Pos,Normal,Color and repeat. So: PxPyPzNxNyNzCrCgCbPxPyPzNxNyNzCrCgCbPxPyPzNxNyNzCrCgCb... "interleaved data". You must be carefull with the positions (bytes) you update.
I am currently trying to create a tilemap using instanced drawing. I have been able to draw multiple instances of a tile by sending the vertices corresponding to the geometry combined with the texture coordinates and the offsets of each tiles in a separate VBO and using the attribute divisor.
This however allows me to use only one texture. So I splitted the texture coordinates from the vertices and created a separate VBO like for the offsets, but it doesn't generate the expected results. Let's say the coordinates I send are the coordinates that match the first texture in the atlas for the first tile and the coordinates that match the second texture for the other tiles, if I use glAttributeDivisor(1, 0), all the tiles use only the first texture. If I use any other value, I get some sort of checker pattern with only one pixel of each texture used for the entire tile.
Here's what it does when the attribute divisior is 0:
And this is when the attribute divisor is at 1:
Normally, the first tile in the bottom left corner should be a grass tile, like when the divisor is 0, and all the others should be a dirt tile.
This is what I do to create the buffers:
TileMap::TileMap(std::vector<glm::vec2> positions, std::vector<glm::vec2> texCoords, glm::vec2 tileSize,
std::shared_ptr<graphics::Shader> shader,
std::shared_ptr<graphics::Texture> texture) :
m_positions(positions), m_texCoords(texCoords), m_tileSize(tileSize), m_shader(shader), m_texture(texture) {
m_model = glm::mat4();
m_model = glm::scale(m_model, glm::vec3(tileSize, 1.0f));
GLfloat vertices[] =
{
// Positions
1.0f, 1.0f, // Top Right
1.0f, 0.0f, // Bottom Right
0.0f, 0.0f, // Bottom Left
0.0f, 1.0f // Top Left
};
GLuint indices[] =
{
0, 1, 3,
1, 2, 3
};
glGenVertexArrays(1, &m_vao);
glGenBuffers(1, &m_vbo);
glGenBuffers(1, &m_ebo);
glGenBuffers(1, &m_textureVbo);
glBindBuffer(GL_ARRAY_BUFFER, m_textureVbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(glm::vec2) * m_texCoords.size(), &m_texCoords[0], GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glGenBuffers(1, &m_instanceVbo);
glBindBuffer(GL_ARRAY_BUFFER, m_instanceVbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(glm::vec2) * m_positions.size(), &m_positions[0], GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(m_vao);
glBindBuffer(GL_ARRAY_BUFFER, m_vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_ebo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(GLfloat), (GLvoid*)0);
glEnableVertexAttribArray(1);
glBindBuffer(GL_ARRAY_BUFFER, m_textureVbo);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(GLfloat), (GLvoid*)0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glEnableVertexAttribArray(2);
glBindBuffer(GL_ARRAY_BUFFER, m_instanceVbo);
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(GLfloat), (GLvoid*)0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glVertexAttribDivisor(1, 0);
glVertexAttribDivisor(2, 1);
glBindVertexArray(0);
}
And this is how I generate the tilemap:
std::vector<glm::vec2> positions;
std::vector<glm::vec2> texCoords;
bool test = false;
for(float i = 0.0f; i < 7.0f; i++) {
for(float j = 0.0f; j < 7.0f; j++) {
positions.push_back(glm::vec2(j, i));
if(test){
texCoords.push_back(glm::vec2(1.0f, 1.0f)); // Top Right
texCoords.push_back(glm::vec2(1.0f, 0.0f)); // Bottom Right
texCoords.push_back(glm::vec2(0.5f, 0.0f)); // Bottom Left
texCoords.push_back(glm::vec2(0.5f, 1.0f)); // Top Left
} else {
texCoords.push_back(glm::vec2(0.5f, 1.0f)); // Top Right
texCoords.push_back(glm::vec2(0.5f, 0.0f)); // Bottom Right
texCoords.push_back(glm::vec2(0.0f, 0.0f)); // Bottom Left
texCoords.push_back(glm::vec2(0.0f, 1.0f)); // Top Left
}
test = true; //This is just to test the texture switching after the first tile
}
}
graphics::TileMap tileMap(positions, texCoords, glm::vec2(64.0f), shader, texture);
I am not really familiar with OpenGl so I have absolutely no idea what is causing this nor what to use so that each quad read the 4 texture coordinates that should by tied to them.
I'm using shaders and modern OpenGL. I tried glGetError() checks but no error is returned, I also tried debugging with apitrace, but I couldn't find anything. I'm not even sure if the problem is initialization or drawing code.
Sprite init:
void Sprite::init(float _x, float _y, float _width, float _height, const char* texture_path) {
x = _x;
y = _y;
width = _width;
height = _height;
texture.init(texture_path);
glGenBuffers(1, &vbo);
glGenBuffers(1, &ebo);
// This array will hold our vertex data
// We need 4 vertices, and each vertex has 2 floats for X and Y
Vertex vertexData[4];
// Top right
vertexData[0].set_position(x + width, y + height);
vertexData[0].set_uv(1.0f, 1.0f);
// Bottom right
vertexData[1].set_position(x + width, y);
vertexData[1].set_uv(1.0f, 0.0f);
// Bottom left
vertexData[2].set_position(x, y);
vertexData[2].set_uv(0.0f, 0.0f);
// Top left
vertexData[3].set_position(x, y + height);
vertexData[3].set_uv(0.0f, 1.0f);
for (int i = 0; i < 4; i++) {
vertexData[i].set_color(255, 255, 255, 255);
}
GLuint indices[] = { // Note that we start from 0!
0, 1, 3, // First Triangle
1, 2, 3 // Second Triangle
};
// Bind the vertex buffer object (active buffer)
glBindBuffer(GL_ARRAY_BUFFER, vbo);
// Upload the buffer data to GPU
glBufferData(GL_ARRAY_BUFFER, sizeof(vertexData), vertexData, GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
// Unbind the buffer
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
}
Sprite draw:
void Sprite::draw() {
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture.id);
// Bind the buffer object
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
// Tell OpenGL that we want to use the first attribute array
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glEnableVertexAttribArray(2);
// This is the position attribute pointer
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, position));
// This is the color attribute pointer
glVertexAttribPointer(1, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(Vertex), (void*)offsetof(Vertex, color));
// This is the UV attribute pointer
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, uv));
// Draw the 4 vertices to the screen
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
// Disable the vertex attrib array
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
glDisableVertexAttribArray(2);
// Unbind the VBO and EBO
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
}
Rendering code:
Sprite sprite;
sprite.init(0, 0, 500, 500, "assets/textures/awesomeface.png");
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Enable shader
shader_program.enable();
sprite.draw();
// Disable shader
shader_program.disable();
// Swap buffers
window.swap_window();
You need to call glEnable(GL_TEXTURE_2D); to enable use of textures. It would also be preferable to disable it as soon as you are done using that utility, simply by putting glDisable(GL_TEXTURE2D); as soon as you have finished drawing, or whenever you are done working with textures. Hope this helps! I had this problem as well, and it took me a good 3 days of staring at a blinking cursor to figure out.
I've been trying to render a cube in a QGLWidget, but it comes out wrong. No matter how I rotate it, it looks like a flat square. It's like it didn't notice the Z coordinates of its vertices. Just before I added clearing of the GL_DEPTH_BUFFER_BIT, the square looked like all of the cube's sides crammed into one. Now it seems to discard vertices which don't belong in the front side, but it still isn't a cube.!
Screenshots [link]
My initializeGL() and paintGL():
typedef struct
{
float XYZW[4];
float RGBA[4];
} Vertex;
Vertex Vertices[8] =
{
//vertices
};
const GLubyte Indices[36] =
{
//indices
};
void ModelView::initializeGL()
{
m_program = new QGLShaderProgram(this);
m_program->addShaderFromSourceCode(QGLShader::Vertex, vertexShaderSource);
m_program->addShaderFromSourceCode(QGLShader::Fragment, fragmentShaderSource);
m_program->link();
}
void ModelView::paintGL()
{
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LESS);
glClearColor(.5f, .5f, .5f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glViewport(0, 0, width(), height());
m_program->bind();
QMatrix4x4 matrix;
matrix.perspective(60, 4.0/3.0, 0.1, 100.0);
matrix.translate(0, 0, -2);
matrix.rotate(50.0, 1, 1, 1);
m_program->setUniformValue(m_matrixUniform, matrix);
m_posAttr = m_program->attributeLocation("posAttr");
m_colAttr = m_program->attributeLocation("colAttr");
m_matrixUniform = m_program->uniformLocation("matrix");
glGenBuffers(1, &BufferId);
glGenBuffers(1, &IndexBufferId);
glBindBuffer(GL_ARRAY_BUFFER, BufferId);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IndexBufferId);
glBufferData(GL_ARRAY_BUFFER, BufferSize, Vertices, GL_STATIC_DRAW);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(Indices), Indices, GL_STATIC_DRAW);
glVertexAttribPointer(m_posAttr, 2, GL_FLOAT, GL_FALSE, VertexSize, 0);
glVertexAttribPointer(m_colAttr, 3, GL_FLOAT, GL_FALSE, VertexSize, (GLvoid *)RgbOffset);
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_BYTE, NULL);
glDisableVertexAttribArray(1);
glDisableVertexAttribArray(0);
m_program->release();
}
Vertices and Indices should be defined correctly, they're taken from a tutorial, as is most of the code. Rendering of 2D object seems to be just fine, though.
Also, why does the tutorial call matrix.translate with the -2 argument? If I change it to anything else greater than 1 or remove it, the rendered object disappears.
Qt5, Windows Vista 32-bit.
Also, why does the tutorial call matrix.translate with the -2
argument? If I change it to anything else greater than 1 or remove it,
the rendered object disappears.
This is due to clipping. When you render objects, things that are "too close" or "too far" are discarded, via the near and far clipping planes (respectively).
By moving the cube closer (changing -2 to 1 or 0), you are bringing the cube forward, past the near clipping plane, and it consequently disappears.
glVertexAttribPointer() has a size parameter, which specifies the number of components per vertex. In the code it is 2, therefore everything is 2D. Changing to 3 solves the issue.
My Vertex Buffer Object code is supposed to render textures nicely but instead the textures are being rendered oddly with some triangle shapes.
What happens - http://godofgod.co.uk/my_files/wrong.png
What is supposed to happen - http://godofgod.co.uk/my_files/right.png
This function creates the VBO and sets the vertex and texture coordinate data:
extern "C" GLuint create_box_vbo(GLdouble size[2]){
GLuint vbo;
glGenBuffers(1,&vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
GLsizeiptr data_size = 8*sizeof(GLdouble);
GLdouble vertices[] = {0,0, 0,size[1], size[0],0, size[0],size[1]};
glBufferData(GL_ARRAY_BUFFER, data_size, vertices, GL_STATIC_DRAW);
data_size = 8*sizeof(GLint);
GLint textcoords[] = {0,0, 0,1, 1,0, 1,1};
glBufferData(GL_ARRAY_BUFFER, data_size, textcoords, GL_STATIC_DRAW);
return vbo;
}
Here is some relavant code from another function which is supposed to draw the textures with the VBO.
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP_TO_EDGE);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glColor4d(1,1,1,a/255);
glBindTexture(GL_TEXTURE_2D, texture);
glTranslated(offset[0],offset[1],0);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glVertexPointer(2, GL_DOUBLE, 0, 0);
glEnableClientState(GL_VERTEX_ARRAY);
glTexCoordPointer (2, GL_INT, 0, 0);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glDrawArrays(GL_TRIANGLES, 0, 3);
glDrawArrays(GL_TRIANGLES, 1, 3);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);
glBindBuffer(GL_ARRAY_BUFFER, 0);
I would have hoped for the code to use the first three coordinates (top-left,bottom-left,top-right) and the last three (bottom-left,top-right,bottom-right) to draw the triangles with the texture data correctly in the most efficient way. I don't see why triangles should make it more efficient but apparently that's the way to go. It, of-course, fails for some reason.
I am asking what is broken but also am I going about it in the right way generally?
Thank you.
If you want to use the one VBO for both vertex and texture coordinates you need to group them using a struct.
Define your data:
typedef struct {
GLdouble x, y;
GLint s, t;
} VertexData;
VertexData data[] = {
// x y s t
{0.0, 0.0, 0, 0},
{0.0, size[1], 0, 1},
{size[0], 0.0, 1, 0},
{size[0], size[1], 1, 1}
};
Copy it into VBO:
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(data), (GLvoid*)data, GL_STATIC_DRAW);
Set pointers. Note that stride is your struct's size and pointer itself serves as offset:
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glVertexPointer(2, GL_DOUBLE, sizeof(VertexData), (GLvoid*)offsetof(VertexData, x));
glTexCoordPointer(2, GL_INT, sizeof(VertexData), (GLvoid*)offsetof(VertexData, s));
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
And draw.
EDIT: Implemented offset with offsetof() as Bahbar suggested.
You're loading data twice to the vbo. The second call to glBufferData is replacing the first one. Then both calls to gl*Pointer actually use the same data when calling draw.